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
nexedi
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
Hide 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
0 to disable any limiting, otherwise the maximal rate in jiffies(1)
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:
Pekka Savola <pekkas@netcore.fi>
YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
...
...
include/linux/rtnetlink.h
View file @
a954eec8
...
...
@@ -336,6 +336,7 @@ enum
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
...
...
include/linux/sysctl.h
View file @
a954eec8
...
...
@@ -388,7 +388,12 @@ enum {
NET_IPV6_DAD_TRANSMITS
=
7
,
NET_IPV6_RTR_SOLICITS
=
8
,
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 */
...
...
include/net/addrconf.h
View file @
a954eec8
...
...
@@ -6,6 +6,11 @@
#define MAX_RTR_SOLICITATIONS 3
#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)
struct
prefix_info
{
...
...
include/net/if_inet6.h
View file @
a954eec8
...
...
@@ -43,6 +43,12 @@ struct inet6_ifaddr
struct
inet6_ifaddr
*
lst_next
;
/* next addr in addr_lst */
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
;
};
...
...
@@ -86,7 +92,13 @@ struct ipv6_devconf
int
rtr_solicits
;
int
rtr_solicit_interval
;
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
;
};
...
...
@@ -101,6 +113,13 @@ struct inet6_dev
__u32
if_flags
;
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
inet6_dev
*
next
;
struct
ipv6_devconf
cnf
;
...
...
net/ipv6/Kconfig
View file @
a954eec8
#
# 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"
net/ipv6/addrconf.c
View file @
a954eec8
...
...
@@ -28,6 +28,8 @@
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
* YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
* support.
*/
#include <linux/config.h>
...
...
@@ -62,6 +64,12 @@
#include <linux/if_tunnel.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>
#define IPV6_MAX_ADDRESSES 16
...
...
@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
int
inet6_dev_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
*/
...
...
@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf =
MAX_RTR_SOLICITATIONS
,
/* router solicits */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
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
=
...
...
@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt =
MAX_RTR_SOLICITATIONS
,
/* router solicits */
RTR_SOLICITATION_INTERVAL
,
/* rtr solicit interval */
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 */
...
...
@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */
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
);
dev
->
ip6_ptr
=
ndev
;
/* One reference from device */
...
...
@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
/* Add to inet6_dev unicast addr list. */
ifa
->
if_next
=
idev
->
addr_list
;
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
);
write_unlock_bh
(
&
idev
->
lock
);
read_unlock
(
&
addrconf_lock
);
...
...
@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
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
);
for
(
ifap
=
&
inet6_addr_lst
[
hash
];
(
ifa
=*
ifap
)
!=
NULL
;
ifap
=
&
ifa
->
lst_next
)
{
...
...
@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
write_unlock_bh
(
&
addrconf_hash_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
;
ifap
=
&
ifa
->
if_next
)
{
if
(
ifa
==
ifp
)
{
...
...
@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *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
* should do:
...
...
@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
* an address of the attached interface
* 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
,
struct
in6_addr
*
daddr
,
struct
in6_addr
*
saddr
)
{
...
...
@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst,
struct
inet6_dev
*
idev
;
struct
rt6_info
*
rt
;
int
err
;
int
hiscore
=
-
1
,
score
;
rt
=
(
struct
rt6_info
*
)
dst
;
if
(
rt
)
...
...
@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh
(
&
idev
->
lock
);
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
!
(
ifp
->
flags
&
(
IFA_F_DEPRECATED
|
IFA_F_TENTATIVE
)))
{
in6_ifa_hold
(
ifp
);
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
);
if
(
IPV6_GET_SADDR_MAXSCORE
(
score
))
{
read_unlock_bh
(
&
idev
->
lock
);
read_unlock
(
&
addrconf_lock
);
goto
out
;
}
if
(
!
match
&&
!
(
ifp
->
flags
&
IFA_F_TENTATIVE
))
{
match
=
ifp
;
in6_ifa_hold
(
ifp
);
}
}
}
read_unlock_bh
(
&
idev
->
lock
);
...
...
@@ -535,16 +741,26 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh
(
&
idev
->
lock
);
for
(
ifp
=
idev
->
addr_list
;
ifp
;
ifp
=
ifp
->
if_next
)
{
if
(
ifp
->
scope
==
scope
)
{
if
(
!
(
ifp
->
flags
&
(
IFA_F_DEPRECATED
|
IFA_F_TENTATIVE
)))
{
in6_ifa_hold
(
ifp
);
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
);
if
(
IPV6_GET_SADDR_MAXSCORE
(
score
))
{
read_unlock_bh
(
&
idev
->
lock
);
goto
out_unlock_base
;
}
if
(
!
match
&&
!
(
ifp
->
flags
&
IFA_F_TENTATIVE
))
{
match
=
ifp
;
in6_ifa_hold
(
ifp
);
}
}
}
read_unlock_bh
(
&
idev
->
lock
);
...
...
@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_unlock
(
&
dev_base_lock
);
out:
if
(
ifp
==
NULL
)
{
ifp
=
match
;
match
=
NULL
;
}
err
=
-
EADDRNOTAVAIL
;
if
(
ifp
)
{
ipv6_addr_copy
(
saddr
,
&
ifp
->
addr
);
if
(
match
)
{
ipv6_addr_copy
(
saddr
,
&
match
->
addr
);
err
=
0
;
in6_ifa_put
(
ifp
);
}
if
(
match
)
in6_ifa_put
(
match
);
}
return
err
;
}
...
...
@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
ifp
->
flags
|=
IFA_F_TENTATIVE
;
spin_unlock_bh
(
&
ifp
->
lock
);
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
ipv6_del_addr
(
ifp
);
}
...
...
@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
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.
*/
...
...
@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
struct
inet6_ifaddr
*
ifp
;
struct
in6_addr
addr
;
int
plen
;
int
create
=
0
;
plen
=
pinfo
->
prefix_len
>>
3
;
...
...
@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
return
;
}
create
=
1
;
addrconf_dad_start
(
ifp
);
}
...
...
@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if
(
ifp
)
{
int
flags
;
#ifdef CONFIG_IPV6_PRIVACY
struct
inet6_ifaddr
*
ift
;
#endif
spin_lock
(
&
ifp
->
lock
);
ifp
->
valid_lft
=
valid_lft
;
...
...
@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if
(
!
(
flags
&
IFA_F_TENTATIVE
))
ipv6_ifa_notify
((
flags
&
IFA_F_DEPRECATED
)
?
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
);
addrconf_verify
(
0
);
}
...
...
@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static
struct
addrconf_sysctl_table
{
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_conf_dir
[
2
];
ctl_table
addrconf_proto_dir
[
2
];
...
...
@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table
&
ipv6_devconf
.
rtr_solicit_delay
,
sizeof
(
int
),
0644
,
NULL
,
&
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
}},
{{
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
if
(
t
==
NULL
)
return
;
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
].
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