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
a954eec8
Commit
a954eec8
authored
Feb 23, 2003
by
Hideaki Yoshifuji
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[IPV6]: Privacy Extensions for Stateless Address Autoconfiguration.
parent
fc39cece
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
494 additions
and
28 deletions
+494
-28
Documentation/networking/ip-sysctl.txt
Documentation/networking/ip-sysctl.txt
+31
-0
include/linux/rtnetlink.h
include/linux/rtnetlink.h
+1
-0
include/linux/sysctl.h
include/linux/sysctl.h
+6
-1
include/net/addrconf.h
include/net/addrconf.h
+5
-0
include/net/if_inet6.h
include/net/if_inet6.h
+20
-1
net/ipv6/Kconfig
net/ipv6/Kconfig
+16
-0
net/ipv6/addrconf.c
net/ipv6/addrconf.c
+415
-26
No files found.
Documentation/networking/ip-sysctl.txt
View file @
a954eec8
...
@@ -619,6 +619,37 @@ ratelimit - INTEGER
...
@@ -619,6 +619,37 @@ ratelimit - INTEGER
0 to disable any limiting, otherwise the maximal rate in jiffies(1)
0 to disable any limiting, otherwise the maximal rate in jiffies(1)
Default: 100
Default: 100
use_tempaddr - INTEGER
Preference for Privacy Extensions (RFC3041).
<= 0 : disable Privacy Extensions
== 1 : enable Privacy Extensions, but prefer public
addresses over temporary addresses.
> 1 : enable Privacy Extensions and prefer temporary
addresses over public addresses.
Default: 0 (for most devices)
-1 (for point-to-point devices and loopback devices)
temp_valid_lft - INTEGER
valid lifetime (in seconds) for temporary addresses.
Default: 604800 (7 days)
temp_prefered_lft - INTEGER
Preferred lifetime (in seconds) for temorary addresses.
Default: 86400 (1 day)
max_desync_factor - INTEGER
Maximum value for DESYNC_FACTOR, which is a random value
that ensures that clients don't synchronize with each
other and generage new addresses at exactly the same time.
value is in seconds.
Default: 600
regen_max_retry - INTEGER
Number of attempts before give up attempting to generate
valid temporary addresses.
Default: 5
IPv6 Update by:
IPv6 Update by:
Pekka Savola <pekkas@netcore.fi>
Pekka Savola <pekkas@netcore.fi>
YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
...
...
include/linux/rtnetlink.h
View file @
a954eec8
...
@@ -336,6 +336,7 @@ enum
...
@@ -336,6 +336,7 @@ enum
/* ifa_flags */
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_DEPRECATED 0x20
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
#define IFA_F_TENTATIVE 0x40
...
...
include/linux/sysctl.h
View file @
a954eec8
...
@@ -388,7 +388,12 @@ enum {
...
@@ -388,7 +388,12 @@ enum {
NET_IPV6_DAD_TRANSMITS
=
7
,
NET_IPV6_DAD_TRANSMITS
=
7
,
NET_IPV6_RTR_SOLICITS
=
8
,
NET_IPV6_RTR_SOLICITS
=
8
,
NET_IPV6_RTR_SOLICIT_INTERVAL
=
9
,
NET_IPV6_RTR_SOLICIT_INTERVAL
=
9
,
NET_IPV6_RTR_SOLICIT_DELAY
=
10
NET_IPV6_RTR_SOLICIT_DELAY
=
10
,
NET_IPV6_USE_TEMPADDR
=
11
,
NET_IPV6_TEMP_VALID_LFT
=
12
,
NET_IPV6_TEMP_PREFERED_LFT
=
13
,
NET_IPV6_REGEN_MAX_RETRY
=
14
,
NET_IPV6_MAX_DESYNC_FACTOR
=
15
};
};
/* /proc/sys/net/ipv6/icmp */
/* /proc/sys/net/ipv6/icmp */
...
...
include/net/addrconf.h
View file @
a954eec8
...
@@ -6,6 +6,11 @@
...
@@ -6,6 +6,11 @@
#define MAX_RTR_SOLICITATIONS 3
#define MAX_RTR_SOLICITATIONS 3
#define RTR_SOLICITATION_INTERVAL (4*HZ)
#define RTR_SOLICITATION_INTERVAL (4*HZ)
#define TEMP_VALID_LIFETIME (7*86400)
#define TEMP_PREFERRED_LIFETIME (86400)
#define REGEN_MAX_RETRY (5)
#define MAX_DESYNC_FACTOR (600)
#define ADDR_CHECK_FREQUENCY (120*HZ)
#define ADDR_CHECK_FREQUENCY (120*HZ)
struct
prefix_info
{
struct
prefix_info
{
...
...
include/net/if_inet6.h
View file @
a954eec8
...
@@ -43,6 +43,12 @@ struct inet6_ifaddr
...
@@ -43,6 +43,12 @@ struct inet6_ifaddr
struct
inet6_ifaddr
*
lst_next
;
/* next addr in addr_lst */
struct
inet6_ifaddr
*
lst_next
;
/* next addr in addr_lst */
struct
inet6_ifaddr
*
if_next
;
/* next addr in inet6_dev */
struct
inet6_ifaddr
*
if_next
;
/* next addr in inet6_dev */
#ifdef CONFIG_IPV6_PRIVACY
struct
inet6_ifaddr
*
tmp_next
;
/* next addr in tempaddr_lst */
struct
inet6_ifaddr
*
ifpub
;
int
regen_count
;
#endif
int
dead
;
int
dead
;
};
};
...
@@ -86,7 +92,13 @@ struct ipv6_devconf
...
@@ -86,7 +92,13 @@ struct ipv6_devconf
int
rtr_solicits
;
int
rtr_solicits
;
int
rtr_solicit_interval
;
int
rtr_solicit_interval
;
int
rtr_solicit_delay
;
int
rtr_solicit_delay
;
#ifdef CONFIG_IPV6_PRIVACY
int
use_tempaddr
;
int
temp_valid_lft
;
int
temp_prefered_lft
;
int
regen_max_retry
;
int
max_desync_factor
;
#endif
void
*
sysctl
;
void
*
sysctl
;
};
};
...
@@ -101,6 +113,13 @@ struct inet6_dev
...
@@ -101,6 +113,13 @@ struct inet6_dev
__u32
if_flags
;
__u32
if_flags
;
int
dead
;
int
dead
;
#ifdef CONFIG_IPV6_PRIVACY
u8
rndid
[
8
];
u8
entropy
[
8
];
struct
timer_list
regen_timer
;
struct
inet6_ifaddr
*
tempaddr_list
;
#endif
struct
neigh_parms
*
nd_parms
;
struct
neigh_parms
*
nd_parms
;
struct
inet6_dev
*
next
;
struct
inet6_dev
*
next
;
struct
ipv6_devconf
cnf
;
struct
ipv6_devconf
cnf
;
...
...
net/ipv6/Kconfig
View file @
a954eec8
#
#
# IPv6 configuration
# IPv6 configuration
#
#
config IPV6_PRIVACY
bool "IPv6: Privacy Extensions (RFC 3041) support"
depends on IPV6
---help---
Privacy Extensions for Stateless Address Autoconfiguration in IPv6
support. With this option, additional periodically-alter
pseudo-random global-scope unicast address(es) will assigned to
your interface(s).
By default, kernel do not generate temporary addresses.
To use temporary addresses, do
echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr
See <file:Documentation/networking/ip-sysctl.txt> for details.
source "net/ipv6/netfilter/Kconfig"
source "net/ipv6/netfilter/Kconfig"
net/ipv6/addrconf.c
View file @
a954eec8
...
@@ -28,6 +28,8 @@
...
@@ -28,6 +28,8 @@
* packets.
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
* address validation timer.
* YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
* support.
*/
*/
#include <linux/config.h>
#include <linux/config.h>
...
@@ -62,6 +64,12 @@
...
@@ -62,6 +64,12 @@
#include <linux/if_tunnel.h>
#include <linux/if_tunnel.h>
#include <linux/rtnetlink.h>
#include <linux/rtnetlink.h>
#ifdef CONFIG_IPV6_PRIVACY
#include <linux/random.h>
#include <linux/crypto.h>
#include <asm/scatterlist.h>
#endif
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#define IPV6_MAX_ADDRESSES 16
#define IPV6_MAX_ADDRESSES 16
...
@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
...
@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
int
inet6_dev_count
;
int
inet6_dev_count
;
int
inet6_ifa_count
;
int
inet6_ifa_count
;
#ifdef CONFIG_IPV6_PRIVACY
static
int
__ipv6_regen_rndid
(
struct
inet6_dev
*
idev
);
static
int
__ipv6_try_regen_rndid
(
struct
inet6_dev
*
idev
,
struct
in6_addr
*
tmpaddr
);
static
void
ipv6_regen_rndid
(
unsigned
long
data
);
static
int
desync_factor
=
MAX_DESYNC_FACTOR
*
HZ
;
#endif
int
ipv6_count_addresses
(
struct
inet6_dev
*
idev
);
/*
/*
* Configured unicast address hash table
* Configured unicast address hash table
*/
*/
...
@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf =
...
@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf =
MAX_RTR_SOLICITATIONS
,
/* router solicits */
MAX_RTR_SOLICITATIONS
,
/* router solicits */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
MAX_RTR_SOLICITATION_DELAY
,
/* rtr solicit delay */
MAX_RTR_SOLICITATION_DELAY
,
/* rtr solicit delay */
#ifdef CONFIG_IPV6_PRIVACY
.
use_tempaddr
=
0
,
.
temp_valid_lft
=
TEMP_VALID_LIFETIME
,
.
temp_prefered_lft
=
TEMP_PREFERRED_LIFETIME
,
.
regen_max_retry
=
REGEN_MAX_RETRY
,
.
max_desync_factor
=
MAX_DESYNC_FACTOR
,
#endif
};
};
static
struct
ipv6_devconf
ipv6_devconf_dflt
=
static
struct
ipv6_devconf
ipv6_devconf_dflt
=
...
@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt =
...
@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt =
MAX_RTR_SOLICITATIONS
,
/* router solicits */
MAX_RTR_SOLICITATIONS
,
/* router solicits */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
MAX_RTR_SOLICITATION_DELAY
,
/* rtr solicit delay */
MAX_RTR_SOLICITATION_DELAY
,
/* rtr solicit delay */
#ifdef CONFIG_IPV6_PRIVACY
.
use_tempaddr
=
0
,
.
temp_valid_lft
=
TEMP_VALID_LIFETIME
,
.
temp_prefered_lft
=
TEMP_PREFERRED_LIFETIME
,
.
regen_max_retry
=
REGEN_MAX_RETRY
,
.
max_desync_factor
=
MAX_DESYNC_FACTOR
,
#endif
};
};
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
...
@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
...
@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */
/* We refer to the device */
dev_hold
(
dev
);
dev_hold
(
dev
);
#ifdef CONFIG_IPV6_PRIVACY
get_random_bytes
(
ndev
->
rndid
,
sizeof
(
ndev
->
rndid
));
get_random_bytes
(
ndev
->
entropy
,
sizeof
(
ndev
->
entropy
));
init_timer
(
&
ndev
->
regen_timer
);
ndev
->
regen_timer
.
function
=
ipv6_regen_rndid
;
ndev
->
regen_timer
.
data
=
(
unsigned
long
)
ndev
;
if
((
dev
->
flags
&
IFF_LOOPBACK
)
||
dev
->
type
==
ARPHRD_TUNNEL
||
dev
->
type
==
ARPHRD_SIT
)
{
printk
(
KERN_INFO
"Disabled Privacy Extensions on device %p(%s)
\n
"
,
dev
,
dev
->
name
);
ndev
->
cnf
.
use_tempaddr
=
-
1
;
}
else
{
__ipv6_regen_rndid
(
ndev
);
}
#endif
write_lock_bh
(
&
addrconf_lock
);
write_lock_bh
(
&
addrconf_lock
);
dev
->
ip6_ptr
=
ndev
;
dev
->
ip6_ptr
=
ndev
;
/* One reference from device */
/* One reference from device */
...
@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
...
@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
/* Add to inet6_dev unicast addr list. */
/* Add to inet6_dev unicast addr list. */
ifa
->
if_next
=
idev
->
addr_list
;
ifa
->
if_next
=
idev
->
addr_list
;
idev
->
addr_list
=
ifa
;
idev
->
addr_list
=
ifa
;
#ifdef CONFIG_IPV6_PRIVACY
ifa
->
regen_count
=
0
;
if
(
ifa
->
flags
&
IFA_F_TEMPORARY
)
{
ifa
->
tmp_next
=
idev
->
tempaddr_list
;
idev
->
tempaddr_list
=
ifa
;
in6_ifa_hold
(
ifa
);
}
else
{
ifa
->
tmp_next
=
NULL
;
}
#endif
in6_ifa_hold
(
ifa
);
in6_ifa_hold
(
ifa
);
write_unlock_bh
(
&
idev
->
lock
);
write_unlock_bh
(
&
idev
->
lock
);
read_unlock
(
&
addrconf_lock
);
read_unlock
(
&
addrconf_lock
);
...
@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
...
@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
ifp
->
dead
=
1
;
ifp
->
dead
=
1
;
#ifdef CONFIG_IPV6_PRIVACY
spin_lock_bh
(
&
ifp
->
lock
);
if
(
ifp
->
ifpub
)
{
__in6_ifa_put
(
ifp
->
ifpub
);
ifp
->
ifpub
=
NULL
;
}
spin_unlock_bh
(
&
ifp
->
lock
);
#endif
write_lock_bh
(
&
addrconf_hash_lock
);
write_lock_bh
(
&
addrconf_hash_lock
);
for
(
ifap
=
&
inet6_addr_lst
[
hash
];
(
ifa
=*
ifap
)
!=
NULL
;
for
(
ifap
=
&
inet6_addr_lst
[
hash
];
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
lst_next
)
{
ifap
=
&
ifa
->
lst_next
)
{
...
@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
...
@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
write_unlock_bh
(
&
addrconf_hash_lock
);
write_unlock_bh
(
&
addrconf_hash_lock
);
write_lock_bh
(
&
idev
->
lock
);
write_lock_bh
(
&
idev
->
lock
);
#ifdef CONFIG_IPV6_PRIVACY
if
(
ifp
->
flags
&
IFA_F_TEMPORARY
)
{
for
(
ifap
=
&
idev
->
tempaddr_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
tmp_next
)
{
if
(
ifa
==
ifp
)
{
*
ifap
=
ifa
->
tmp_next
;
if
(
ifp
->
ifpub
)
{
__in6_ifa_put
(
ifp
->
ifpub
);
ifp
->
ifpub
=
NULL
;
}
__in6_ifa_put
(
ifp
);
ifa
->
tmp_next
=
NULL
;
break
;
}
}
}
#endif
for
(
ifap
=
&
idev
->
addr_list
;
(
ifa
=*
ifap
)
!=
NULL
;
for
(
ifap
=
&
idev
->
addr_list
;
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
if_next
)
{
ifap
=
&
ifa
->
if_next
)
{
if
(
ifa
==
ifp
)
{
if
(
ifa
==
ifp
)
{
...
@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
...
@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
in6_ifa_put
(
ifp
);
in6_ifa_put
(
ifp
);
}
}
#ifdef CONFIG_IPV6_PRIVACY
static
int
ipv6_create_tempaddr
(
struct
inet6_ifaddr
*
ifp
,
struct
inet6_ifaddr
*
ift
)
{
struct
inet6_dev
*
idev
;
struct
in6_addr
addr
,
*
tmpaddr
;
unsigned
long
tmp_prefered_lft
,
tmp_valid_lft
;
int
tmp_plen
;
int
ret
=
0
;
if
(
ift
)
{
spin_lock_bh
(
&
ift
->
lock
);
memcpy
(
&
addr
.
s6_addr
[
8
],
&
ift
->
addr
.
s6_addr
[
8
],
8
);
spin_unlock_bh
(
&
ift
->
lock
);
tmpaddr
=
&
addr
;
}
else
{
tmpaddr
=
NULL
;
}
retry:
spin_lock_bh
(
&
ifp
->
lock
);
in6_ifa_hold
(
ifp
);
idev
=
ifp
->
idev
;
in6_dev_hold
(
idev
);
memcpy
(
addr
.
s6_addr
,
ifp
->
addr
.
s6_addr
,
8
);
write_lock
(
&
idev
->
lock
);
if
(
idev
->
cnf
.
use_tempaddr
<=
0
)
{
write_unlock
(
&
idev
->
lock
);
spin_unlock_bh
(
&
ifp
->
lock
);
printk
(
KERN_INFO
"ipv6_create_tempaddr(): use_tempaddr is disabled.
\n
"
);
in6_dev_put
(
idev
);
in6_ifa_put
(
ifp
);
ret
=
-
1
;
goto
out
;
}
if
(
ifp
->
regen_count
++
>=
idev
->
cnf
.
regen_max_retry
)
{
idev
->
cnf
.
use_tempaddr
=
-
1
;
/*XXX*/
write_unlock
(
&
idev
->
lock
);
spin_unlock_bh
(
&
ifp
->
lock
);
printk
(
KERN_WARNING
"ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.
\n
"
);
in6_dev_put
(
idev
);
in6_ifa_put
(
ifp
);
ret
=
-
1
;
goto
out
;
}
if
(
__ipv6_try_regen_rndid
(
idev
,
tmpaddr
)
<
0
)
{
write_unlock
(
&
idev
->
lock
);
spin_unlock_bh
(
&
ifp
->
lock
);
printk
(
KERN_WARNING
"ipv6_create_tempaddr(): regeneration of randomized interface id failed.
\n
"
);
in6_dev_put
(
idev
);
in6_ifa_put
(
ifp
);
ret
=
-
1
;
goto
out
;
}
memcpy
(
&
addr
.
s6_addr
[
8
],
idev
->
rndid
,
8
);
tmp_valid_lft
=
min_t
(
__u32
,
ifp
->
valid_lft
,
idev
->
cnf
.
temp_valid_lft
);
tmp_prefered_lft
=
min_t
(
__u32
,
ifp
->
prefered_lft
,
idev
->
cnf
.
temp_prefered_lft
-
desync_factor
/
HZ
);
tmp_plen
=
ifp
->
prefix_len
;
write_unlock
(
&
idev
->
lock
);
spin_unlock_bh
(
&
ifp
->
lock
);
ift
=
ipv6_count_addresses
(
idev
)
<
IPV6_MAX_ADDRESSES
?
ipv6_add_addr
(
idev
,
&
addr
,
tmp_plen
,
ipv6_addr_type
(
&
addr
)
&
IPV6_ADDR_SCOPE_MASK
,
IFA_F_TEMPORARY
)
:
0
;
if
(
!
ift
)
{
in6_dev_put
(
idev
);
in6_ifa_put
(
ifp
);
printk
(
KERN_INFO
"ipv6_create_tempaddr(): retry temporary address regeneration.
\n
"
);
tmpaddr
=
&
addr
;
goto
retry
;
}
spin_lock_bh
(
&
ift
->
lock
);
ift
->
ifpub
=
ifp
;
ift
->
valid_lft
=
tmp_valid_lft
;
ift
->
prefered_lft
=
tmp_prefered_lft
;
ift
->
tstamp
=
ifp
->
tstamp
;
spin_unlock_bh
(
&
ift
->
lock
);
addrconf_dad_start
(
ift
);
in6_ifa_put
(
ift
);
in6_dev_put
(
idev
);
out:
return
ret
;
}
#endif
/*
/*
* Choose an apropriate source address
* Choose an apropriate source address
* should do:
* should do:
...
@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
...
@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
* an address of the attached interface
* an address of the attached interface
* iii) don't use deprecated addresses
* iii) don't use deprecated addresses
*/
*/
static
int
inline
ipv6_saddr_pref
(
const
struct
inet6_ifaddr
*
ifp
,
u8
invpref
)
{
int
pref
;
pref
=
ifp
->
flags
&
IFA_F_DEPRECATED
?
0
:
2
;
#ifdef CONFIG_IPV6_PRIVACY
pref
|=
(
ifp
->
flags
^
invpref
)
&
IFA_F_TEMPORARY
?
0
:
1
;
#endif
return
pref
;
}
#ifdef CONFIG_IPV6_PRIVACY
#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)
#else
#define IPV6_GET_SADDR_MAXSCORE(score) (score)
#endif
int
ipv6_get_saddr
(
struct
dst_entry
*
dst
,
int
ipv6_get_saddr
(
struct
dst_entry
*
dst
,
struct
in6_addr
*
daddr
,
struct
in6_addr
*
saddr
)
struct
in6_addr
*
daddr
,
struct
in6_addr
*
saddr
)
{
{
...
@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst,
...
@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst,
struct
inet6_dev
*
idev
;
struct
inet6_dev
*
idev
;
struct
rt6_info
*
rt
;
struct
rt6_info
*
rt
;
int
err
;
int
err
;
int
hiscore
=
-
1
,
score
;
rt
=
(
struct
rt6_info
*
)
dst
;
rt
=
(
struct
rt6_info
*
)
dst
;
if
(
rt
)
if
(
rt
)
...
@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst,
...
@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh
(
&
idev
->
lock
);
read_lock_bh
(
&
idev
->
lock
);
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
!
(
ifp
->
flags
&
(
IFA_F_DEPRECATED
|
IFA_F_TENTATIVE
)))
{
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
continue
;
#ifdef CONFIG_IPV6_PRIVACY
score
=
ipv6_saddr_pref
(
ifp
,
idev
->
cnf
.
use_tempaddr
>
1
?
IFA_F_TEMPORARY
:
0
);
#else
score
=
ipv6_saddr_pref
(
ifp
,
0
);
#endif
if
(
score
<=
hiscore
)
continue
;
if
(
match
)
in6_ifa_put
(
match
);
match
=
ifp
;
hiscore
=
score
;
in6_ifa_hold
(
ifp
);
in6_ifa_hold
(
ifp
);
if
(
IPV6_GET_SADDR_MAXSCORE
(
score
))
{
read_unlock_bh
(
&
idev
->
lock
);
read_unlock_bh
(
&
idev
->
lock
);
read_unlock
(
&
addrconf_lock
);
read_unlock
(
&
addrconf_lock
);
goto
out
;
goto
out
;
}
}
if
(
!
match
&&
!
(
ifp
->
flags
&
IFA_F_TENTATIVE
))
{
match
=
ifp
;
in6_ifa_hold
(
ifp
);
}
}
}
}
}
read_unlock_bh
(
&
idev
->
lock
);
read_unlock_bh
(
&
idev
->
lock
);
...
@@ -535,15 +741,25 @@ int ipv6_get_saddr(struct dst_entry *dst,
...
@@ -535,15 +741,25 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh
(
&
idev
->
lock
);
read_lock_bh
(
&
idev
->
lock
);
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
!
(
ifp
->
flags
&
(
IFA_F_DEPRECATED
|
IFA_F_TENTATIVE
)))
{
if
(
ifp
->
flags
&
IFA_F_TENTATIVE
)
in6_ifa_hold
(
ifp
);
continue
;
read_unlock_bh
(
&
idev
->
lock
);
#ifdef CONFIG_IPV6_PRIVACY
goto
out_unlock_base
;
score
=
ipv6_saddr_pref
(
ifp
,
idev
->
cnf
.
use_tempaddr
>
1
?
IFA_F_TEMPORARY
:
0
);
}
#else
score
=
ipv6_saddr_pref
(
ifp
,
0
);
#endif
if
(
score
<=
hiscore
)
continue
;
if
(
!
match
&&
!
(
ifp
->
flags
&
IFA_F_TENTATIVE
))
{
if
(
match
)
in6_ifa_put
(
match
);
match
=
ifp
;
match
=
ifp
;
hiscore
=
score
;
in6_ifa_hold
(
ifp
);
in6_ifa_hold
(
ifp
);
if
(
IPV6_GET_SADDR_MAXSCORE
(
score
))
{
read_unlock_bh
(
&
idev
->
lock
);
goto
out_unlock_base
;
}
}
}
}
}
}
...
@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst,
...
@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_unlock
(
&
dev_base_lock
);
read_unlock
(
&
dev_base_lock
);
out:
out:
if
(
ifp
==
NULL
)
{
ifp
=
match
;
match
=
NULL
;
}
err
=
-
EADDRNOTAVAIL
;
err
=
-
EADDRNOTAVAIL
;
if
(
ifp
)
{
if
(
match
)
{
ipv6_addr_copy
(
saddr
,
&
ifp
->
addr
);
ipv6_addr_copy
(
saddr
,
&
match
->
addr
);
err
=
0
;
err
=
0
;
in6_ifa_put
(
ifp
);
}
if
(
match
)
in6_ifa_put
(
match
);
in6_ifa_put
(
match
);
}
return
err
;
return
err
;
}
}
...
@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
...
@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
ifp
->
flags
|=
IFA_F_TENTATIVE
;
ifp
->
flags
|=
IFA_F_TENTATIVE
;
spin_unlock_bh
(
&
ifp
->
lock
);
spin_unlock_bh
(
&
ifp
->
lock
);
in6_ifa_put
(
ifp
);
in6_ifa_put
(
ifp
);
#ifdef CONFIG_IPV6_PRIVACY
}
else
if
(
ifp
->
flags
&
IFA_F_TEMPORARY
)
{
struct
inet6_ifaddr
*
ifpub
;
spin_lock_bh
(
&
ifp
->
lock
);
ifpub
=
ifp
->
ifpub
;
if
(
ifpub
)
{
in6_ifa_hold
(
ifpub
);
spin_unlock_bh
(
&
ifp
->
lock
);
ipv6_create_tempaddr
(
ifpub
,
ifp
);
in6_ifa_put
(
ifpub
);
}
else
{
spin_unlock_bh
(
&
ifp
->
lock
);
}
ipv6_del_addr
(
ifp
);
#endif
}
else
}
else
ipv6_del_addr
(
ifp
);
ipv6_del_addr
(
ifp
);
}
}
...
@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
...
@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
return
err
;
return
err
;
}
}
#ifdef CONFIG_IPV6_PRIVACY
/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
static
int
__ipv6_regen_rndid
(
struct
inet6_dev
*
idev
)
{
struct
net_device
*
dev
;
u8
eui64
[
8
];
u8
digest
[
16
];
struct
crypto_tfm
*
tfm
;
struct
scatterlist
sg
[
2
];
sg
[
0
].
page
=
virt_to_page
(
idev
->
entropy
);
sg
[
0
].
offset
=
((
long
)
idev
->
entropy
&
~
PAGE_MASK
);
sg
[
0
].
length
=
8
;
sg
[
1
].
page
=
virt_to_page
(
eui64
);
sg
[
1
].
offset
=
((
long
)
eui64
&
~
PAGE_MASK
);
sg
[
1
].
length
=
8
;
if
(
!
del_timer
(
&
idev
->
regen_timer
))
in6_dev_hold
(
idev
);
dev
=
idev
->
dev
;
if
(
ipv6_generate_eui64
(
eui64
,
dev
))
{
printk
(
KERN_INFO
"__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.
\n
"
,
idev
);
get_random_bytes
(
eui64
,
sizeof
(
eui64
));
}
regen:
tfm
=
crypto_alloc_tfm
(
"md5"
,
0
);
if
(
tfm
==
NULL
)
{
if
(
net_ratelimit
())
printk
(
KERN_WARNING
"failed to load transform for md5
\n
"
);
in6_dev_put
(
idev
);
return
-
1
;
}
crypto_digest_init
(
tfm
);
crypto_digest_update
(
tfm
,
sg
,
2
);
crypto_digest_final
(
tfm
,
digest
);
crypto_free_tfm
(
tfm
);
memcpy
(
idev
->
rndid
,
&
digest
[
0
],
8
);
idev
->
rndid
[
0
]
&=
~
0x02
;
memcpy
(
idev
->
entropy
,
&
digest
[
8
],
8
);
/*
* <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
* check if generated address is not inappropriate
*
* - Reserved subnet anycast (RFC 2526)
* 11111101 11....11 1xxxxxxx
* - ISATAP (draft-ietf-ngtrans-isatap-01.txt) 4.3
* 00-00-5E-FE-xx-xx-xx-xx
* - value 0
* - XXX: already assigned to an address on the device
*/
if
(
idev
->
rndid
[
0
]
==
0xfd
&&
(
idev
->
rndid
[
1
]
&
idev
->
rndid
[
2
]
&
idev
->
rndid
[
3
]
&
idev
->
rndid
[
4
]
&
idev
->
rndid
[
5
]
&
idev
->
rndid
[
6
])
&&
(
idev
->
rndid
[
7
]
&
0x80
))
goto
regen
;
if
((
idev
->
rndid
[
0
]
|
idev
->
rndid
[
1
])
==
0
)
{
if
(
idev
->
rndid
[
2
]
==
0x5e
&&
idev
->
rndid
[
3
]
==
0xfe
)
goto
regen
;
if
((
idev
->
rndid
[
2
]
|
idev
->
rndid
[
3
]
|
idev
->
rndid
[
4
]
|
idev
->
rndid
[
5
]
|
idev
->
rndid
[
6
]
|
idev
->
rndid
[
7
])
==
0x00
)
goto
regen
;
}
if
(
time_before
(
idev
->
regen_timer
.
expires
,
jiffies
))
{
idev
->
regen_timer
.
expires
=
0
;
printk
(
KERN_WARNING
"__ipv6_regen_rndid(): too short regeneration interval; timer diabled for %s.
\n
"
,
idev
->
dev
->
name
);
in6_dev_put
(
idev
);
return
-
1
;
}
add_timer
(
&
idev
->
regen_timer
);
return
0
;
}
static
void
ipv6_regen_rndid
(
unsigned
long
data
)
{
struct
inet6_dev
*
idev
=
(
struct
inet6_dev
*
)
data
;
read_lock_bh
(
&
addrconf_lock
);
write_lock_bh
(
&
idev
->
lock
);
if
(
!
idev
->
dead
)
__ipv6_regen_rndid
(
idev
);
write_unlock_bh
(
&
idev
->
lock
);
read_unlock_bh
(
&
addrconf_lock
);
}
static
int
__ipv6_try_regen_rndid
(
struct
inet6_dev
*
idev
,
struct
in6_addr
*
tmpaddr
)
{
int
ret
=
0
;
if
(
tmpaddr
&&
memcmp
(
idev
->
rndid
,
&
tmpaddr
->
s6_addr
[
8
],
8
)
==
0
)
ret
=
__ipv6_regen_rndid
(
idev
);
return
ret
;
}
#endif
/*
/*
* Add prefix route.
* Add prefix route.
*/
*/
...
@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
...
@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
struct
inet6_ifaddr
*
ifp
;
struct
inet6_ifaddr
*
ifp
;
struct
in6_addr
addr
;
struct
in6_addr
addr
;
int
plen
;
int
plen
;
int
create
=
0
;
plen
=
pinfo
->
prefix_len
>>
3
;
plen
=
pinfo
->
prefix_len
>>
3
;
...
@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
...
@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
return
;
return
;
}
}
create
=
1
;
addrconf_dad_start
(
ifp
);
addrconf_dad_start
(
ifp
);
}
}
...
@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
...
@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if
(
ifp
)
{
if
(
ifp
)
{
int
flags
;
int
flags
;
#ifdef CONFIG_IPV6_PRIVACY
struct
inet6_ifaddr
*
ift
;
#endif
spin_lock
(
&
ifp
->
lock
);
spin_lock
(
&
ifp
->
lock
);
ifp
->
valid_lft
=
valid_lft
;
ifp
->
valid_lft
=
valid_lft
;
...
@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
...
@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if
(
!
(
flags
&
IFA_F_TENTATIVE
))
if
(
!
(
flags
&
IFA_F_TENTATIVE
))
ipv6_ifa_notify
((
flags
&
IFA_F_DEPRECATED
)
?
ipv6_ifa_notify
((
flags
&
IFA_F_DEPRECATED
)
?
0
:
RTM_NEWADDR
,
ifp
);
0
:
RTM_NEWADDR
,
ifp
);
#ifdef CONFIG_IPV6_PRIVACY
read_lock_bh
(
&
in6_dev
->
lock
);
/* update all temporary addresses in the list */
for
(
ift
=
in6_dev
->
tempaddr_list
;
ift
;
ift
=
ift
->
tmp_next
)
{
/*
* When adjusting the lifetimes of an existing
* temporary address, only lower the lifetimes.
* Implementations must not increase the
* lifetimes of an existing temporary address
* when processing a Prefix Information Option.
*/
spin_lock
(
&
ift
->
lock
);
flags
=
ift
->
flags
;
if
(
ift
->
valid_lft
>
valid_lft
&&
ift
->
valid_lft
-
valid_lft
>
(
jiffies
-
ift
->
tstamp
)
/
HZ
)
ift
->
valid_lft
=
valid_lft
+
(
jiffies
-
ift
->
tstamp
)
/
HZ
;
if
(
ift
->
prefered_lft
>
prefered_lft
&&
ift
->
prefered_lft
-
prefered_lft
>
(
jiffies
-
ift
->
tstamp
)
/
HZ
)
ift
->
prefered_lft
=
prefered_lft
+
(
jiffies
-
ift
->
tstamp
)
/
HZ
;
spin_unlock
(
&
ift
->
lock
);
if
(
!
(
flags
&
IFA_F_TENTATIVE
))
ipv6_ifa_notify
(
0
,
ift
);
}
if
(
create
&&
in6_dev
->
cnf
.
use_tempaddr
>
0
)
{
/*
* When a new public address is created as described in [ADDRCONF],
* also create a new temporary address.
*/
read_unlock_bh
(
&
in6_dev
->
lock
);
ipv6_create_tempaddr
(
ifp
,
NULL
);
}
else
{
read_unlock_bh
(
&
in6_dev
->
lock
);
}
#endif
in6_ifa_put
(
ifp
);
in6_ifa_put
(
ifp
);
addrconf_verify
(
0
);
addrconf_verify
(
0
);
}
}
...
@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
...
@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static
struct
addrconf_sysctl_table
static
struct
addrconf_sysctl_table
{
{
struct
ctl_table_header
*
sysctl_header
;
struct
ctl_table_header
*
sysctl_header
;
ctl_table
addrconf_vars
[
1
1
];
ctl_table
addrconf_vars
[
1
6
];
ctl_table
addrconf_dev
[
2
];
ctl_table
addrconf_dev
[
2
];
ctl_table
addrconf_conf_dir
[
2
];
ctl_table
addrconf_conf_dir
[
2
];
ctl_table
addrconf_proto_dir
[
2
];
ctl_table
addrconf_proto_dir
[
2
];
...
@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table
...
@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table
&
ipv6_devconf
.
rtr_solicit_delay
,
sizeof
(
int
),
0644
,
NULL
,
&
ipv6_devconf
.
rtr_solicit_delay
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec_jiffies
},
&
proc_dointvec_jiffies
},
#ifdef CONFIG_IPV6_PRIVACY
{
NET_IPV6_USE_TEMPADDR
,
"use_tempaddr"
,
&
ipv6_devconf
.
use_tempaddr
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV6_TEMP_VALID_LFT
,
"temp_valid_lft"
,
&
ipv6_devconf
.
temp_valid_lft
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV6_TEMP_PREFERED_LFT
,
"temp_prefered_lft"
,
&
ipv6_devconf
.
temp_prefered_lft
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV6_REGEN_MAX_RETRY
,
"regen_max_retry"
,
&
ipv6_devconf
.
regen_max_retry
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
{
NET_IPV6_MAX_DESYNC_FACTOR
,
"max_desync_factor"
,
&
ipv6_devconf
.
max_desync_factor
,
sizeof
(
int
),
0644
,
NULL
,
&
proc_dointvec
},
#endif
{
0
}},
{
0
}},
{{
NET_PROTO_CONF_ALL
,
"all"
,
NULL
,
0
,
0555
,
addrconf_sysctl
.
addrconf_vars
},{
0
}},
{{
NET_PROTO_CONF_ALL
,
"all"
,
NULL
,
0
,
0555
,
addrconf_sysctl
.
addrconf_vars
},{
0
}},
...
@@ -1980,7 +2369,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf
...
@@ -1980,7 +2369,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf
if
(
t
==
NULL
)
if
(
t
==
NULL
)
return
;
return
;
memcpy
(
t
,
&
addrconf_sysctl
,
sizeof
(
*
t
));
memcpy
(
t
,
&
addrconf_sysctl
,
sizeof
(
*
t
));
for
(
i
=
0
;
i
<
sizeof
(
t
->
addrconf_vars
)
/
sizeof
(
t
->
addrconf_vars
[
0
])
-
1
;
i
++
)
{
for
(
i
=
0
;
t
->
addrconf_vars
[
i
].
data
;
i
++
)
{
t
->
addrconf_vars
[
i
].
data
+=
(
char
*
)
p
-
(
char
*
)
&
ipv6_devconf
;
t
->
addrconf_vars
[
i
].
data
+=
(
char
*
)
p
-
(
char
*
)
&
ipv6_devconf
;
t
->
addrconf_vars
[
i
].
de
=
NULL
;
t
->
addrconf_vars
[
i
].
de
=
NULL
;
}
}
...
...
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