netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
@ 2006-07-27  9:57 YOSHIFUJI Hideaki / 吉藤英明
  2006-07-27 10:28 ` Hugo Santos
  0 siblings, 1 reply; 7+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-07-27  9:57 UTC (permalink / raw)
  To: davem; +Cc: yoshfuji, vnuorval, anttit, netdev, usagi-core

Hello.

Based on MIPL kernel patch, these changesets contain following:
 - fix payload length checking
 - fix infinity lifetime handling
 - add/modify finity lifetime from userspace

This is only for review.  Comments appreciated.
We will prepare another round.

(To Ville and Antti: please send me your "sign-off" if you like.)

Git tree is also available on addrconf-lifetime-20060727 branch at:
	git://git.skbuff.net/gitroot/yoshfuji/linux-2.6.18-rc2-addr-lifetime/linux-2.6.18-rc2-addr-lifetime

Thank you.

HEADLINES
---------

    [IPV6] ADDRCONF: Check payload length for IFA_LOCAL attribute in RTM_{ADD,DEL}MSG message.
    [IPV6] ADDRCONF: Allow user-space to specify address lifetime.
    [IPV6] ADDRCONF: Do not verify an address with infinity lifetime.
    [IPV6] ADDRCONF: Support get operation of single address.
    [IPV6] ADDRCONF: NLM_F_REPLACE support for RTM_NEWADDR

DIFFSTAT
--------

 net/ipv6/addrconf.c |  174 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 166 insertions(+), 8 deletions(-)

CHANGESETS
----------

commit cb9e0e620c90ee486141bd737a93a20142d6dad1
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Mon Jul 3 13:58:39 2006 +0900

    [IPV6] ADDRCONF: Check payload length for IFA_LOCAL attribute in RTM_{ADD,DEL}MSG message.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2316a43..81702b9 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2853,7 +2853,8 @@ inet6_rtm_deladdr(struct sk_buff *skb, s
 		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
 	}
 	if (rta[IFA_LOCAL-1]) {
-		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+		    (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
 			return -EINVAL;
 		pfx = RTA_DATA(rta[IFA_LOCAL-1]);
 	}
@@ -2877,7 +2878,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
 	}
 	if (rta[IFA_LOCAL-1]) {
-		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+		    (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
 			return -EINVAL;
 		pfx = RTA_DATA(rta[IFA_LOCAL-1]);
 	}

---
commit 78fee6e086390892e8b297b64700546491fdb871
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Mon Jul 3 14:02:28 2006 +0900

    [IPV6] ADDRCONF: Allow user-space to specify address lifetime.
    
    Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 81702b9..c064188 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1869,15 +1869,21 @@ err_exit:
 /*
  *	Manual configuration of address on an interface
  */
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
+static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
+			  __u32 prefered_lft, __u32 valid_lft)
 {
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev;
 	struct net_device *dev;
+	__u8 ifa_flags = 0;
 	int scope;
 
 	ASSERT_RTNL();
 	
+	/* check the lifetime */
+	if (!valid_lft || prefered_lft > valid_lft)
+		return -EINVAL;
+
 	if ((dev = __dev_get_by_index(ifindex)) == NULL)
 		return -ENODEV;
 	
@@ -1889,10 +1895,29 @@ static int inet6_addr_add(int ifindex, s
 
 	scope = ipv6_addr_scope(pfx);
 
-	ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
+	if (valid_lft == INFINITY_LIFE_TIME)
+		ifa_flags |= IFA_F_PERMANENT;
+	else if (valid_lft >= 0x7FFFFFFF/HZ)
+		valid_lft = 0x7FFFFFFF/HZ;
+
+	if (prefered_lft == 0)
+		ifa_flags |= IFA_F_DEPRECATED;
+	else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+		 (prefered_lft != INFINITY_LIFE_TIME))
+		prefered_lft = 0x7FFFFFFF/HZ;
+
+	ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+
 	if (!IS_ERR(ifp)) {
+		spin_lock(&ifp->lock);
+		ifp->valid_lft = valid_lft;
+		ifp->prefered_lft = prefered_lft;
+		ifp->tstamp = jiffies;
+		spin_unlock(&ifp->lock);
+
 		addrconf_dad_start(ifp, 0);
 		in6_ifa_put(ifp);
+		addrconf_verify(0);
 		return 0;
 	}
 
@@ -1945,7 +1970,8 @@ int addrconf_add_ifaddr(void __user *arg
 		return -EFAULT;
 
 	rtnl_lock();
-	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
+			     INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
 	rtnl_unlock();
 	return err;
 }
@@ -2870,6 +2896,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 	struct rtattr  **rta = arg;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in6_addr *pfx;
+	__u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
 
 	pfx = NULL;
 	if (rta[IFA_ADDRESS-1]) {
@@ -2886,7 +2913,18 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 	if (pfx == NULL)
 		return -EINVAL;
 
-	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+	if (rta[IFA_CACHEINFO-1]) {
+		struct ifa_cacheinfo *ci;
+		if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
+			return -EINVAL;
+		ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
+		valid_lft = ci->ifa_valid;
+		prefered_lft = ci->ifa_prefered;
+	}
+
+	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
+			      prefered_lft, valid_lft);
+
 }
 
 /* Maximum length of ifa_cacheinfo attributes */

---
commit d8be7c7b011b989fd134a10ca3bf27d78e209275
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Mon Jul 3 15:11:30 2006 +0900

    [IPV6] ADDRCONF: Do not verify an address with infinity lifetime.
    
    We also do not try regenarating new temporary address corresponding to an
    address with infinite preferred lifetime.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c064188..93a40a8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2797,12 +2797,16 @@ #ifdef CONFIG_IPV6_PRIVACY
 					ifp->idev->nd_parms->retrans_time / HZ;
 #endif
 
-			if (age >= ifp->valid_lft) {
+			if (ifp->valid_lft != INFINITY_LIFE_TIME &&
+			    age >= ifp->valid_lft) {
 				spin_unlock(&ifp->lock);
 				in6_ifa_hold(ifp);
 				read_unlock(&addrconf_hash_lock);
 				ipv6_del_addr(ifp);
 				goto restart;
+			} else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
+				spin_unlock(&ifp->lock);
+				continue;
 			} else if (age >= ifp->prefered_lft) {
 				/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
 				int deprecate = 0;

---
commit 9cfa5093e1c50d192f1b9d0958a5110e2470f8ad
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Tue Jul 4 17:32:55 2006 +0900

    [IPV6] ADDRCONF: Support get operation of single address.
    
    Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 93a40a8..3ef3fe2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3165,6 +3165,62 @@ static int inet6_dump_ifacaddr(struct sk
 	return inet6_dump_addr(skb, cb, type);
 }
 
+static int inet6_rtm_getaddr(struct sk_buff *in_skb,
+		struct nlmsghdr* nlh, void *arg)
+{
+	struct rtattr **rta = arg;
+	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+	struct in6_addr *addr = NULL;
+	struct net_device *dev = NULL;
+	struct inet6_ifaddr *ifa;
+	struct sk_buff *skb;
+	int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
+	int err;
+
+	if (rta[IFA_ADDRESS-1]) {
+		if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
+			return -EINVAL;
+		addr = RTA_DATA(rta[IFA_ADDRESS-1]);
+	}
+	if (rta[IFA_LOCAL-1]) {
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
+		    (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
+			return -EINVAL;
+		addr = RTA_DATA(rta[IFA_LOCAL-1]);
+	}
+	if (addr == NULL)
+		return -EINVAL;
+
+	if (ifm->ifa_index)
+		dev = __dev_get_by_index(ifm->ifa_index);
+
+	if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
+		return -EADDRNOTAVAIL;
+
+	if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
+		err = -ENOBUFS;
+		goto out;
+	}
+
+	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+	err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
+				nlh->nlmsg_seq, RTM_NEWADDR, 0);
+	if (err < 0) {
+		err = -EMSGSIZE;
+		goto out_free;
+	}
+
+	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+out:
+	in6_ifa_put(ifa);
+	return err;
+out_free:
+	kfree_skb(skb);
+	goto out;
+}
+
 static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 {
 	struct sk_buff *skb;
@@ -3407,7 +3463,8 @@ static struct rtnetlink_link inet6_rtnet
 	[RTM_GETLINK - RTM_BASE] = { .dumpit	= inet6_dump_ifinfo, },
 	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },
 	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, },
-	[RTM_GETADDR - RTM_BASE] = { .dumpit	= inet6_dump_ifaddr, },
+	[RTM_GETADDR - RTM_BASE] = { .doit	= inet6_rtm_getaddr,
+				     .dumpit	= inet6_dump_ifaddr, },
 	[RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
 	[RTM_GETANYCAST - RTM_BASE] = { .dumpit	= inet6_dump_ifacaddr, },
 	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet6_rtm_newroute, },

---
commit 21e1b516ba98ac9b369eaf1084a1b5a1927ad72a
Author: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Date:   Sun Jul 2 01:18:32 2006 +0900

    [IPV6] ADDRCONF: NLM_F_REPLACE support for RTM_NEWADDR
    
    Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3ef3fe2..25032c2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2895,6 +2895,55 @@ inet6_rtm_deladdr(struct sk_buff *skb, s
 }
 
 static int
+inet6_addr_modify(int ifindex, struct in6_addr *pfx,
+		  __u32 prefered_lft, __u32 valid_lft)
+{
+	struct inet6_ifaddr *ifp = NULL;
+	struct net_device *dev;
+	int ifa_flags = 0;
+
+	if ((dev = __dev_get_by_index(ifindex)) == NULL)
+		return -ENODEV;
+
+	if (!(dev->flags&IFF_UP))
+		return -ENETDOWN;
+
+	ifp = ipv6_get_ifaddr(pfx, dev, 1);
+	if (ifp == NULL)
+		return -ENOENT;
+
+	if (!valid_lft || (prefered_lft > valid_lft))
+		return -EINVAL;
+
+	if (valid_lft == INFINITY_LIFE_TIME)
+		ifa_flags = IFA_F_PERMANENT;
+	else if (valid_lft >= 0x7FFFFFFF/HZ)
+		valid_lft = 0x7FFFFFFF/HZ;
+
+	if (prefered_lft == 0)
+		ifa_flags = IFA_F_DEPRECATED;
+	else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+		 (prefered_lft != INFINITY_LIFE_TIME))
+		prefered_lft = 0x7FFFFFFF/HZ;
+
+	spin_lock_bh(&ifp->lock);
+	ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
+
+	ifp->tstamp = jiffies;
+	ifp->valid_lft = valid_lft;
+	ifp->prefered_lft = prefered_lft;
+
+	spin_unlock_bh(&ifp->lock);
+	if (!(ifp->flags&IFA_F_TENTATIVE))
+		ipv6_ifa_notify(0, ifp);
+	in6_ifa_put(ifp);
+
+	addrconf_verify(0);
+
+	return 0;
+}
+
+static int
 inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct rtattr  **rta = arg;
@@ -2926,6 +2975,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 		prefered_lft = ci->ifa_prefered;
 	}
 
+	if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+		int ret;
+		ret = inet6_addr_modify(ifm->ifa_index, pfx,
+					prefered_lft, valid_lft);
+		if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
+			return ret;
+	}
+
 	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
 			      prefered_lft, valid_lft);
 

---

-- 
YOSHIFUJI Hideaki @ USAGI Project  <yoshfuji@linux-ipv6.org>
GPG-FP  : 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-27  9:57 [RFC] [IPV6] ADDRCONF: Lifetime handling fixes YOSHIFUJI Hideaki / 吉藤英明
@ 2006-07-27 10:28 ` Hugo Santos
  2006-07-27 10:49   ` Noriaki TAKAMIYA
  0 siblings, 1 reply; 7+ messages in thread
From: Hugo Santos @ 2006-07-27 10:28 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / ?$B5HF#1QL@
  Cc: davem, vnuorval, anttit, netdev, usagi-core

[-- Attachment #1: Type: text/plain, Size: 395 bytes --]

Hi,

>  static int
> +inet6_addr_modify(int ifindex, struct in6_addr *pfx,
> +		  __u32 prefered_lft, __u32 valid_lft)
> +{

   ...

> +	ifp = ipv6_get_ifaddr(pfx, dev, 1);
> +	if (ifp == NULL)
> +		return -ENOENT;
> +
> +	if (!valid_lft || (prefered_lft > valid_lft))
> +		return -EINVAL;
                ^^^^^^^^^^^^^^^

   Unreleased ifp? This test should go before ipv6_get_ifaddr.

   Hugo

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-27 10:28 ` Hugo Santos
@ 2006-07-27 10:49   ` Noriaki TAKAMIYA
  2006-07-28  8:11     ` David Miller
  0 siblings, 1 reply; 7+ messages in thread
From: Noriaki TAKAMIYA @ 2006-07-27 10:49 UTC (permalink / raw)
  To: hsantos; +Cc: yoshfuji, davem, vnuorval, anttit, netdev, usagi-core

Hi,

  This is Takamiya, from USAGI Project.

>> Thu, 27 Jul 2006 11:28:02 +0100
>> [Subject: Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes] wrote...
>> Hugo Santos <hsantos@av.it.pt> wrote...

> > +	ifp = ipv6_get_ifaddr(pfx, dev, 1);
> > +	if (ifp == NULL)
> > +		return -ENOENT;
> > +
> > +	if (!valid_lft || (prefered_lft > valid_lft))
> > +		return -EINVAL;
>                 ^^^^^^^^^^^^^^^
> 
>    Unreleased ifp? This test should go before ipv6_get_ifaddr.

  That's right. Thanks.

--
Noriaki Takamiya

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-27 10:49   ` Noriaki TAKAMIYA
@ 2006-07-28  8:11     ` David Miller
  2006-07-28  8:18       ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 7+ messages in thread
From: David Miller @ 2006-07-28  8:11 UTC (permalink / raw)
  To: takamiya; +Cc: hsantos, yoshfuji, vnuorval, anttit, netdev, usagi-core

From: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Date: Thu, 27 Jul 2006 19:49:29 +0900 (JST)

> >> Thu, 27 Jul 2006 11:28:02 +0100
> >> [Subject: Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes] wrote...
> >> Hugo Santos <hsantos@av.it.pt> wrote...
> 
> > > +	ifp = ipv6_get_ifaddr(pfx, dev, 1);
> > > +	if (ifp == NULL)
> > > +		return -ENOENT;
> > > +
> > > +	if (!valid_lft || (prefered_lft > valid_lft))
> > > +		return -EINVAL;
> >                 ^^^^^^^^^^^^^^^
> > 
> >    Unreleased ifp? This test should go before ipv6_get_ifaddr.
> 
>   That's right. Thanks.

Thank you Takamiya-san.

Besides this correction, the rest of the changes look fine to me.
I think we should get these fixes into 2.6.18, if you don't mind.

So please resubmit with the correction.

Thanks again.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-28  8:11     ` David Miller
@ 2006-07-28  8:18       ` YOSHIFUJI Hideaki / 吉藤英明
  2006-07-28  9:25         ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 7+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-07-28  8:18 UTC (permalink / raw)
  To: davem; +Cc: takamiya, hsantos, vnuorval, anttit, netdev, usagi-core, yoshfuji

In article <20060728.011103.21926965.davem@davemloft.net> (at Fri, 28 Jul 2006 01:11:03 -0700 (PDT)), David Miller <davem@davemloft.net> says:

> Besides this correction, the rest of the changes look fine to me.
> I think we should get these fixes into 2.6.18, if you don't mind.
> 
> So please resubmit with the correction.

Okay. I'll do this soon.

--yoshfuji

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-28  8:18       ` YOSHIFUJI Hideaki / 吉藤英明
@ 2006-07-28  9:25         ` YOSHIFUJI Hideaki / 吉藤英明
  2006-07-31  3:32           ` David Miller
  0 siblings, 1 reply; 7+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2006-07-28  9:25 UTC (permalink / raw)
  To: davem; +Cc: takamiya, hsantos, vnuorval, anttit, netdev, usagi-core, yoshfuji

In article <20060728.171818.37443466.yoshfuji@linux-ipv6.org> (at Fri, 28 Jul 2006 17:18:18 +0900 (JST)), YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> says:

> In article <20060728.011103.21926965.davem@davemloft.net> (at Fri, 28 Jul 2006 01:11:03 -0700 (PDT)), David Miller <davem@davemloft.net> says:
> 
> > Besides this correction, the rest of the changes look fine to me.
> > I think we should get these fixes into 2.6.18, if you don't mind.
> > 
> > So please resubmit with the correction.
> 
> Okay. I'll do this soon.

Here it is.

Changesets, on top of 2.6.18-rc2, are available on
branch "addr-lifetime-20060728b" at:
    git://git.skbuff.net/gitroot/yoshfuji/linux-2.6.18-rc2-addr-lifetime

Regards,

HEADLINES
---------

    [IPV6] ADDRCONF: Check payload length for IFA_LOCAL attribute in RTM_{ADD,DEL}MSG message
    [IPV6] ADDRCONF: Allow user-space to specify address lifetime
    [IPV6] ADDRCONF: Do not verify an address with infinity lifetime
    [IPV6] ADDRCONF: Support get operation of single address
    [IPV6] ADDRCONF: NLM_F_REPLACE support for RTM_NEWADDR

DIFFSTAT
--------

 net/ipv6/addrconf.c |  174 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 166 insertions(+), 8 deletions(-)

CHANGESETS
----------

commit 27fb40230b30534bdc08736d64cab179038591bc
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Jul 28 18:12:09 2006 +0900

    [IPV6] ADDRCONF: Check payload length for IFA_LOCAL attribute in RTM_{ADD,DEL}MSG message
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2316a43..81702b9 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2853,7 +2853,8 @@ inet6_rtm_deladdr(struct sk_buff *skb, s
 		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
 	}
 	if (rta[IFA_LOCAL-1]) {
-		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+		    (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
 			return -EINVAL;
 		pfx = RTA_DATA(rta[IFA_LOCAL-1]);
 	}
@@ -2877,7 +2878,8 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 		pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
 	}
 	if (rta[IFA_LOCAL-1]) {
-		if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
+		    (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
 			return -EINVAL;
 		pfx = RTA_DATA(rta[IFA_LOCAL-1]);
 	}

---
commit 336f472519a05ea493c5ad24de2c39e2c80003a0
Author: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Date:   Fri Jul 28 18:12:10 2006 +0900

    [IPV6] ADDRCONF: Allow user-space to specify address lifetime
    
    Based on MIPL2 kernel patch.
    
    Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 81702b9..c064188 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1869,15 +1869,21 @@ err_exit:
 /*
  *	Manual configuration of address on an interface
  */
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
+static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
+			  __u32 prefered_lft, __u32 valid_lft)
 {
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev;
 	struct net_device *dev;
+	__u8 ifa_flags = 0;
 	int scope;
 
 	ASSERT_RTNL();
 	
+	/* check the lifetime */
+	if (!valid_lft || prefered_lft > valid_lft)
+		return -EINVAL;
+
 	if ((dev = __dev_get_by_index(ifindex)) == NULL)
 		return -ENODEV;
 	
@@ -1889,10 +1895,29 @@ static int inet6_addr_add(int ifindex, s
 
 	scope = ipv6_addr_scope(pfx);
 
-	ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
+	if (valid_lft == INFINITY_LIFE_TIME)
+		ifa_flags |= IFA_F_PERMANENT;
+	else if (valid_lft >= 0x7FFFFFFF/HZ)
+		valid_lft = 0x7FFFFFFF/HZ;
+
+	if (prefered_lft == 0)
+		ifa_flags |= IFA_F_DEPRECATED;
+	else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+		 (prefered_lft != INFINITY_LIFE_TIME))
+		prefered_lft = 0x7FFFFFFF/HZ;
+
+	ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+
 	if (!IS_ERR(ifp)) {
+		spin_lock(&ifp->lock);
+		ifp->valid_lft = valid_lft;
+		ifp->prefered_lft = prefered_lft;
+		ifp->tstamp = jiffies;
+		spin_unlock(&ifp->lock);
+
 		addrconf_dad_start(ifp, 0);
 		in6_ifa_put(ifp);
+		addrconf_verify(0);
 		return 0;
 	}
 
@@ -1945,7 +1970,8 @@ int addrconf_add_ifaddr(void __user *arg
 		return -EFAULT;
 
 	rtnl_lock();
-	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
+			     INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
 	rtnl_unlock();
 	return err;
 }
@@ -2870,6 +2896,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 	struct rtattr  **rta = arg;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in6_addr *pfx;
+	__u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
 
 	pfx = NULL;
 	if (rta[IFA_ADDRESS-1]) {
@@ -2886,7 +2913,18 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 	if (pfx == NULL)
 		return -EINVAL;
 
-	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+	if (rta[IFA_CACHEINFO-1]) {
+		struct ifa_cacheinfo *ci;
+		if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
+			return -EINVAL;
+		ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
+		valid_lft = ci->ifa_valid;
+		prefered_lft = ci->ifa_prefered;
+	}
+
+	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
+			      prefered_lft, valid_lft);
+
 }
 
 /* Maximum length of ifa_cacheinfo attributes */

---
commit 28a22216f2d553020e2d15d3b1a9ab9306623e6b
Author: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date:   Fri Jul 28 18:12:11 2006 +0900

    [IPV6] ADDRCONF: Do not verify an address with infinity lifetime
    
    We also do not try regenarating new temporary address corresponding to an
    address with infinite preferred lifetime.
    
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c064188..93a40a8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2797,12 +2797,16 @@ #ifdef CONFIG_IPV6_PRIVACY
 					ifp->idev->nd_parms->retrans_time / HZ;
 #endif
 
-			if (age >= ifp->valid_lft) {
+			if (ifp->valid_lft != INFINITY_LIFE_TIME &&
+			    age >= ifp->valid_lft) {
 				spin_unlock(&ifp->lock);
 				in6_ifa_hold(ifp);
 				read_unlock(&addrconf_hash_lock);
 				ipv6_del_addr(ifp);
 				goto restart;
+			} else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
+				spin_unlock(&ifp->lock);
+				continue;
 			} else if (age >= ifp->prefered_lft) {
 				/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
 				int deprecate = 0;

---
commit eb682da0e66556e23c7c4da73e4808d0b7a29484
Author: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Date:   Fri Jul 28 18:12:12 2006 +0900

    [IPV6] ADDRCONF: Support get operation of single address
    
    Based on MIPL2 kernel patch.
    
    Signed-off-by: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 93a40a8..3ef3fe2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3165,6 +3165,62 @@ static int inet6_dump_ifacaddr(struct sk
 	return inet6_dump_addr(skb, cb, type);
 }
 
+static int inet6_rtm_getaddr(struct sk_buff *in_skb,
+		struct nlmsghdr* nlh, void *arg)
+{
+	struct rtattr **rta = arg;
+	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
+	struct in6_addr *addr = NULL;
+	struct net_device *dev = NULL;
+	struct inet6_ifaddr *ifa;
+	struct sk_buff *skb;
+	int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
+	int err;
+
+	if (rta[IFA_ADDRESS-1]) {
+		if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
+			return -EINVAL;
+		addr = RTA_DATA(rta[IFA_ADDRESS-1]);
+	}
+	if (rta[IFA_LOCAL-1]) {
+		if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
+		    (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
+			return -EINVAL;
+		addr = RTA_DATA(rta[IFA_LOCAL-1]);
+	}
+	if (addr == NULL)
+		return -EINVAL;
+
+	if (ifm->ifa_index)
+		dev = __dev_get_by_index(ifm->ifa_index);
+
+	if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
+		return -EADDRNOTAVAIL;
+
+	if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
+		err = -ENOBUFS;
+		goto out;
+	}
+
+	NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
+	err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
+				nlh->nlmsg_seq, RTM_NEWADDR, 0);
+	if (err < 0) {
+		err = -EMSGSIZE;
+		goto out_free;
+	}
+
+	err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+out:
+	in6_ifa_put(ifa);
+	return err;
+out_free:
+	kfree_skb(skb);
+	goto out;
+}
+
 static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 {
 	struct sk_buff *skb;
@@ -3407,7 +3463,8 @@ static struct rtnetlink_link inet6_rtnet
 	[RTM_GETLINK - RTM_BASE] = { .dumpit	= inet6_dump_ifinfo, },
 	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },
 	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, },
-	[RTM_GETADDR - RTM_BASE] = { .dumpit	= inet6_dump_ifaddr, },
+	[RTM_GETADDR - RTM_BASE] = { .doit	= inet6_rtm_getaddr,
+				     .dumpit	= inet6_dump_ifaddr, },
 	[RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
 	[RTM_GETANYCAST - RTM_BASE] = { .dumpit	= inet6_dump_ifacaddr, },
 	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet6_rtm_newroute, },

---
commit 1a4b3b795b8d5d3b4a746b038b6ba4ddddf9d32c
Author: Noriaki TAKAMIYA <takamiya@po.ntts.co.jp>
Date:   Fri Jul 28 18:12:13 2006 +0900

    [IPV6] ADDRCONF: NLM_F_REPLACE support for RTM_NEWADDR
    
    Based on MIPL2 kernel patch.
    
    Signed-off-by: Noriaki YAKAMIYA <takamiya@po.ntts.co.jp>
    Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3ef3fe2..8ea1e36 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2895,6 +2895,55 @@ inet6_rtm_deladdr(struct sk_buff *skb, s
 }
 
 static int
+inet6_addr_modify(int ifindex, struct in6_addr *pfx,
+		  __u32 prefered_lft, __u32 valid_lft)
+{
+	struct inet6_ifaddr *ifp = NULL;
+	struct net_device *dev;
+	int ifa_flags = 0;
+
+	if ((dev = __dev_get_by_index(ifindex)) == NULL)
+		return -ENODEV;
+
+	if (!(dev->flags&IFF_UP))
+		return -ENETDOWN;
+
+	if (!valid_lft || (prefered_lft > valid_lft))
+		return -EINVAL;
+
+	ifp = ipv6_get_ifaddr(pfx, dev, 1);
+	if (ifp == NULL)
+		return -ENOENT;
+
+	if (valid_lft == INFINITY_LIFE_TIME)
+		ifa_flags = IFA_F_PERMANENT;
+	else if (valid_lft >= 0x7FFFFFFF/HZ)
+		valid_lft = 0x7FFFFFFF/HZ;
+
+	if (prefered_lft == 0)
+		ifa_flags = IFA_F_DEPRECATED;
+	else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
+		 (prefered_lft != INFINITY_LIFE_TIME))
+		prefered_lft = 0x7FFFFFFF/HZ;
+
+	spin_lock_bh(&ifp->lock);
+	ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
+
+	ifp->tstamp = jiffies;
+	ifp->valid_lft = valid_lft;
+	ifp->prefered_lft = prefered_lft;
+
+	spin_unlock_bh(&ifp->lock);
+	if (!(ifp->flags&IFA_F_TENTATIVE))
+		ipv6_ifa_notify(0, ifp);
+	in6_ifa_put(ifp);
+
+	addrconf_verify(0);
+
+	return 0;
+}
+
+static int
 inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct rtattr  **rta = arg;
@@ -2926,6 +2975,14 @@ inet6_rtm_newaddr(struct sk_buff *skb, s
 		prefered_lft = ci->ifa_prefered;
 	}
 
+	if (nlh->nlmsg_flags & NLM_F_REPLACE) {
+		int ret;
+		ret = inet6_addr_modify(ifm->ifa_index, pfx,
+					prefered_lft, valid_lft);
+		if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
+			return ret;
+	}
+
 	return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
 			      prefered_lft, valid_lft);
 

---


-- 
YOSHIFUJI Hideaki @ USAGI Project  <yoshfuji@linux-ipv6.org>
GPG-FP  : 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC] [IPV6] ADDRCONF: Lifetime handling fixes
  2006-07-28  9:25         ` YOSHIFUJI Hideaki / 吉藤英明
@ 2006-07-31  3:32           ` David Miller
  0 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2006-07-31  3:32 UTC (permalink / raw)
  To: yoshfuji; +Cc: takamiya, hsantos, vnuorval, anttit, netdev, usagi-core

From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Date: Fri, 28 Jul 2006 18:25:34 +0900 (JST)

> Changesets, on top of 2.6.18-rc2, are available on
> branch "addr-lifetime-20060728b" at:
>     git://git.skbuff.net/gitroot/yoshfuji/linux-2.6.18-rc2-addr-lifetime

Pulled, thank you very much.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2006-07-31  3:32 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-27  9:57 [RFC] [IPV6] ADDRCONF: Lifetime handling fixes YOSHIFUJI Hideaki / 吉藤英明
2006-07-27 10:28 ` Hugo Santos
2006-07-27 10:49   ` Noriaki TAKAMIYA
2006-07-28  8:11     ` David Miller
2006-07-28  8:18       ` YOSHIFUJI Hideaki / 吉藤英明
2006-07-28  9:25         ` YOSHIFUJI Hideaki / 吉藤英明
2006-07-31  3:32           ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).