@@ -2402,6 +2402,7 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg)
2402
2402
* Manual configuration of address on an interface
2403
2403
*/
2404
2404
static int inet6_addr_add (struct net * net , int ifindex , const struct in6_addr * pfx ,
2405
+ const struct in6_addr * peer_pfx ,
2405
2406
unsigned int plen , __u8 ifa_flags , __u32 prefered_lft ,
2406
2407
__u32 valid_lft )
2407
2408
{
@@ -2457,6 +2458,8 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
2457
2458
ifp -> valid_lft = valid_lft ;
2458
2459
ifp -> prefered_lft = prefered_lft ;
2459
2460
ifp -> tstamp = jiffies ;
2461
+ if (peer_pfx )
2462
+ ifp -> peer_addr = * peer_pfx ;
2460
2463
spin_unlock_bh (& ifp -> lock );
2461
2464
2462
2465
addrconf_prefix_route (& ifp -> addr , ifp -> prefix_len , dev ,
@@ -2526,7 +2529,7 @@ int addrconf_add_ifaddr(struct net *net, void __user *arg)
2526
2529
return - EFAULT ;
2527
2530
2528
2531
rtnl_lock ();
2529
- err = inet6_addr_add (net , ireq .ifr6_ifindex , & ireq .ifr6_addr ,
2532
+ err = inet6_addr_add (net , ireq .ifr6_ifindex , & ireq .ifr6_addr , NULL ,
2530
2533
ireq .ifr6_prefixlen , IFA_F_PERMANENT ,
2531
2534
INFINITY_LIFE_TIME , INFINITY_LIFE_TIME );
2532
2535
rtnl_unlock ();
@@ -3610,18 +3613,20 @@ static void addrconf_verify(unsigned long foo)
3610
3613
rcu_read_unlock_bh ();
3611
3614
}
3612
3615
3613
- static struct in6_addr * extract_addr (struct nlattr * addr , struct nlattr * local )
3616
+ static struct in6_addr * extract_addr (struct nlattr * addr , struct nlattr * local ,
3617
+ struct in6_addr * * peer_pfx )
3614
3618
{
3615
3619
struct in6_addr * pfx = NULL ;
3616
3620
3621
+ * peer_pfx = NULL ;
3622
+
3617
3623
if (addr )
3618
3624
pfx = nla_data (addr );
3619
3625
3620
3626
if (local ) {
3621
3627
if (pfx && nla_memcmp (local , pfx , sizeof (* pfx )))
3622
- pfx = NULL ;
3623
- else
3624
- pfx = nla_data (local );
3628
+ * peer_pfx = pfx ;
3629
+ pfx = nla_data (local );
3625
3630
}
3626
3631
3627
3632
return pfx ;
@@ -3639,15 +3644,15 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh)
3639
3644
struct net * net = sock_net (skb -> sk );
3640
3645
struct ifaddrmsg * ifm ;
3641
3646
struct nlattr * tb [IFA_MAX + 1 ];
3642
- struct in6_addr * pfx ;
3647
+ struct in6_addr * pfx , * peer_pfx ;
3643
3648
int err ;
3644
3649
3645
3650
err = nlmsg_parse (nlh , sizeof (* ifm ), tb , IFA_MAX , ifa_ipv6_policy );
3646
3651
if (err < 0 )
3647
3652
return err ;
3648
3653
3649
3654
ifm = nlmsg_data (nlh );
3650
- pfx = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ]);
3655
+ pfx = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ], & peer_pfx );
3651
3656
if (pfx == NULL )
3652
3657
return - EINVAL ;
3653
3658
@@ -3705,7 +3710,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3705
3710
struct net * net = sock_net (skb -> sk );
3706
3711
struct ifaddrmsg * ifm ;
3707
3712
struct nlattr * tb [IFA_MAX + 1 ];
3708
- struct in6_addr * pfx ;
3713
+ struct in6_addr * pfx , * peer_pfx ;
3709
3714
struct inet6_ifaddr * ifa ;
3710
3715
struct net_device * dev ;
3711
3716
u32 valid_lft = INFINITY_LIFE_TIME , preferred_lft = INFINITY_LIFE_TIME ;
@@ -3717,7 +3722,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3717
3722
return err ;
3718
3723
3719
3724
ifm = nlmsg_data (nlh );
3720
- pfx = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ]);
3725
+ pfx = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ], & peer_pfx );
3721
3726
if (pfx == NULL )
3722
3727
return - EINVAL ;
3723
3728
@@ -3745,7 +3750,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh)
3745
3750
* It would be best to check for !NLM_F_CREATE here but
3746
3751
* userspace alreay relies on not having to provide this.
3747
3752
*/
3748
- return inet6_addr_add (net , ifm -> ifa_index , pfx ,
3753
+ return inet6_addr_add (net , ifm -> ifa_index , pfx , peer_pfx ,
3749
3754
ifm -> ifa_prefixlen , ifa_flags ,
3750
3755
preferred_lft , valid_lft );
3751
3756
}
@@ -3802,6 +3807,7 @@ static inline int rt_scope(int ifa_scope)
3802
3807
static inline int inet6_ifaddr_msgsize (void )
3803
3808
{
3804
3809
return NLMSG_ALIGN (sizeof (struct ifaddrmsg ))
3810
+ + nla_total_size (16 ) /* IFA_LOCAL */
3805
3811
+ nla_total_size (16 ) /* IFA_ADDRESS */
3806
3812
+ nla_total_size (sizeof (struct ifa_cacheinfo ));
3807
3813
}
@@ -3840,13 +3846,22 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
3840
3846
valid = INFINITY_LIFE_TIME ;
3841
3847
}
3842
3848
3843
- if (nla_put (skb , IFA_ADDRESS , 16 , & ifa -> addr ) < 0 ||
3844
- put_cacheinfo (skb , ifa -> cstamp , ifa -> tstamp , preferred , valid ) < 0 ) {
3845
- nlmsg_cancel (skb , nlh );
3846
- return - EMSGSIZE ;
3847
- }
3849
+ if (ipv6_addr_type (& ifa -> peer_addr ) != IPV6_ADDR_ANY ) {
3850
+ if (nla_put (skb , IFA_LOCAL , 16 , & ifa -> addr ) < 0 ||
3851
+ nla_put (skb , IFA_ADDRESS , 16 , & ifa -> peer_addr ) < 0 )
3852
+ goto error ;
3853
+ } else
3854
+ if (nla_put (skb , IFA_ADDRESS , 16 , & ifa -> addr ) < 0 )
3855
+ goto error ;
3856
+
3857
+ if (put_cacheinfo (skb , ifa -> cstamp , ifa -> tstamp , preferred , valid ) < 0 )
3858
+ goto error ;
3848
3859
3849
3860
return nlmsg_end (skb , nlh );
3861
+
3862
+ error :
3863
+ nlmsg_cancel (skb , nlh );
3864
+ return - EMSGSIZE ;
3850
3865
}
3851
3866
3852
3867
static int inet6_fill_ifmcaddr (struct sk_buff * skb , struct ifmcaddr6 * ifmca ,
@@ -4046,7 +4061,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
4046
4061
struct net * net = sock_net (in_skb -> sk );
4047
4062
struct ifaddrmsg * ifm ;
4048
4063
struct nlattr * tb [IFA_MAX + 1 ];
4049
- struct in6_addr * addr = NULL ;
4064
+ struct in6_addr * addr = NULL , * peer ;
4050
4065
struct net_device * dev = NULL ;
4051
4066
struct inet6_ifaddr * ifa ;
4052
4067
struct sk_buff * skb ;
@@ -4056,7 +4071,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh)
4056
4071
if (err < 0 )
4057
4072
goto errout ;
4058
4073
4059
- addr = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ]);
4074
+ addr = extract_addr (tb [IFA_ADDRESS ], tb [IFA_LOCAL ], & peer );
4060
4075
if (addr == NULL ) {
4061
4076
err = - EINVAL ;
4062
4077
goto errout ;
@@ -4564,11 +4579,26 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4564
4579
ip6_ins_rt (ifp -> rt );
4565
4580
if (ifp -> idev -> cnf .forwarding )
4566
4581
addrconf_join_anycast (ifp );
4582
+ if (ipv6_addr_type (& ifp -> peer_addr ) != IPV6_ADDR_ANY )
4583
+ addrconf_prefix_route (& ifp -> peer_addr , 128 ,
4584
+ ifp -> idev -> dev , 0 , 0 );
4567
4585
break ;
4568
4586
case RTM_DELADDR :
4569
4587
if (ifp -> idev -> cnf .forwarding )
4570
4588
addrconf_leave_anycast (ifp );
4571
4589
addrconf_leave_solict (ifp -> idev , & ifp -> addr );
4590
+ if (ipv6_addr_type (& ifp -> peer_addr ) != IPV6_ADDR_ANY ) {
4591
+ struct rt6_info * rt ;
4592
+ struct net_device * dev = ifp -> idev -> dev ;
4593
+
4594
+ rt = rt6_lookup (dev_net (dev ), & ifp -> peer_addr , NULL ,
4595
+ dev -> ifindex , 1 );
4596
+ if (rt ) {
4597
+ dst_hold (& rt -> dst );
4598
+ if (ip6_del_rt (rt ))
4599
+ dst_free (& rt -> dst );
4600
+ }
4601
+ }
4572
4602
dst_hold (& ifp -> rt -> dst );
4573
4603
4574
4604
if (ip6_del_rt (ifp -> rt ))
0 commit comments