[**RFC**] [IPV6]: Support RFC3542 IPV6_PKTINFO socket option.

2007-07-16 Thread YOSHIFUJI Hideaki / 吉藤英明
Hello.

This patch is just a tentative implementation of RFC3542 IPV6_PKTINFO
sticky option, and is NOT intended to be applied so far.

We need to check if this is okay in RFC POV, anyway.

---
[RFC] [IPV6]: Support RFC3542 IPV6_PKTINFO socket option.

Signed-off-by: YOSHIFUJI Hideaki <[EMAIL PROTECTED]>

---
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 46b9dce..1ff4059 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -542,6 +542,10 @@ extern void
ipv6_packet_cleanup(void);
 extern int ip6_datagram_connect(struct sock *sk, 
 struct sockaddr *addr, int 
addr_len);
 
+extern int ip6_datagram_set_pktinfo(struct in6_pktinfo 
*src_info,
+struct in6_addr *saddr,
+struct flowi *fl);
+
 extern int ipv6_recv_error(struct sock *sk, struct msghdr 
*msg, int len);
 extern voidipv6_icmp_error(struct sock *sk, struct sk_buff 
*skb, int err, __be16 port,
u32 info, u8 *payload);
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 409da3a..752a2c0 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -36,7 +36,8 @@ extern intdatagram_recv_ctl(struct sock 
*sk,
  struct msghdr *msg,
  struct sk_buff *skb);
 
-extern int datagram_send_ctl(struct msghdr *msg,
+extern int datagram_send_ctl(struct sock *sk,
+ struct msghdr *msg,
  struct flowi *fl,
  struct ipv6_txoptions *opt,
  int *hlimit, int *tclass);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index fe0f490..cc6e480 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -496,7 +496,55 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, 
struct sk_buff *skb)
return 0;
 }
 
-int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
+int ip6_datagram_set_pktinfo(struct in6_pktinfo *src_info,
+struct in6_addr *saddr,
+struct flowi *fl)
+{
+   struct net_device *dev = NULL;
+   int addr_type;
+
+   if (src_info->ipi6_ifindex) {
+   if (fl->oif && src_info->ipi6_ifindex != fl->oif)
+   return -EINVAL;
+   fl->oif = src_info->ipi6_ifindex;
+   }
+
+   addr_type = ipv6_addr_type(&src_info->ipi6_addr);
+
+   if (addr_type == IPV6_ADDR_ANY)
+   return 0;
+
+   if (saddr) {
+   if (!ipv6_addr_any(saddr))
+   return -EINVAL;
+   if (!ipv6_addr_equal(&src_info->ipi6_addr, saddr))
+   return -EINVAL;
+   }
+
+   if (addr_type & IPV6_ADDR_LINKLOCAL) {
+   if (!src_info->ipi6_ifindex)
+   return -EINVAL;
+   else {
+   dev = dev_get_by_index(src_info->ipi6_ifindex);
+   if (!dev)
+   return -ENODEV;
+   }
+   }
+   if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
+   if (dev)
+   dev_put(dev);
+   return -EINVAL;
+   }
+   if (dev)
+   dev_put(dev);
+
+   ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
+
+   return 0;
+}
+
+int datagram_send_ctl(struct sock *sk,
+ struct msghdr *msg, struct flowi *fl,
  struct ipv6_txoptions *opt,
  int *hlimit, int *tclass)
 {
@@ -508,8 +556,6 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
int err = 0;
 
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-   int addr_type;
-   struct net_device *dev = NULL;
 
if (!CMSG_OK(msg, cmsg)) {
err = -EINVAL;
@@ -526,39 +572,13 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi 
*fl,
err = -EINVAL;
goto exit_f;
}
-
src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
 
-   if (src_info->ipi6_ifindex) {
-   if (fl->oif && src_info->ipi6_ifindex != 
fl->oif)
-   return -EINVAL;
-   fl->oif = src_info->ipi6_ifindex;
-   }
-
- 

Re: [**RFC**] [IPV6]: Support RFC3542 IPV6_PKTINFO socket option.

2007-07-16 Thread Vlad Yasevich
YOSHIFUJI Hideaki / 吉藤英明 wrote:
> Hello.
> 
> This patch is just a tentative implementation of RFC3542 IPV6_PKTINFO
> sticky option, and is NOT intended to be applied so far.
> 
> We need to check if this is okay in RFC POV, anyway.

ok.  comments from just the RFC pov.

> diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
> index fe0f490..cc6e480 100644
> --- a/net/ipv6/datagram.c
> +++ b/net/ipv6/datagram.c
> @@ -496,7 +496,55 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr 
> *msg, struct sk_buff *skb)
>   return 0;
>  }
>  
> -int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
> +int ip6_datagram_set_pktinfo(struct in6_pktinfo *src_info,
> +  struct in6_addr *saddr,
> +  struct flowi *fl)
> +{
> + struct net_device *dev = NULL;
> + int addr_type;
> +
> + if (src_info->ipi6_ifindex) {
> + if (fl->oif && src_info->ipi6_ifindex != fl->oif)
> + return -EINVAL;
> + fl->oif = src_info->ipi6_ifindex;
> + }
> +
> + addr_type = ipv6_addr_type(&src_info->ipi6_addr);
> +
> + if (addr_type == IPV6_ADDR_ANY)
> + return 0;

The above code will not fully clear the previously set option since
we are not guaranteed that fl->oif is 0.

   An   application can clear any sticky IPV6_PKTINFO option by doing a
   "regular" setsockopt with ipi6_addr being in6addr_any and
   ipi6_ifindex being zero.



> +
> + if (saddr) {
> + if (!ipv6_addr_any(saddr))
> + return -EINVAL;
> + if (!ipv6_addr_equal(&src_info->ipi6_addr, saddr))
> + return -EINVAL;
> + }
   
Not following the following text:
   If the ipi6_addr member is not the
   unspecified address, but the socket has already bound a source
   address, then the ipi6_addr value overrides the already-bound source
   address for this output operation only.


> +
> + if (addr_type & IPV6_ADDR_LINKLOCAL) {
> + if (!src_info->ipi6_ifindex)
> + return -EINVAL;
> + else {
> + dev = dev_get_by_index(src_info->ipi6_ifindex);
> + if (!dev)
> + return -ENODEV;
> + }
> + }
> + if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
> + if (dev)
> + dev_put(dev);
> + return -EINVAL;
> + }
> + if (dev)
> + dev_put(dev);
> +
> + ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);

Additional checks needed for:

   IPV6_PKTINFO can also be used as a sticky option for specifying the
   socket's default source address.  However, the ipi6_addr member must
   be the unspecified address for TCP sockets, because it is not
   possible to dynamically change the source address of a TCP
   connection.  When the IPV6_PKTINFO option is specified for a TCP
   socket with a non-unspecified address, the call will fail.  This
   restriction should be applied even before the socket binds a specific
   address.


Also, see Section 6.7 for the correct interface selection rules that should
be applied as well.  Not sure if these are implemented anywhere.

Thanks
-vlad
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [**RFC**] [IPV6]: Support RFC3542 IPV6_PKTINFO socket option.

2007-07-16 Thread YOSHIFUJI Hideaki / 吉藤英明
In article <[EMAIL PROTECTED]> (at Mon, 16 Jul 2007 11:31:28 -0400), Vlad 
Yasevich <[EMAIL PROTECTED]> says:

> YOSHIFUJI Hideaki / 吉藤英明 wrote:
> > Hello.
> > 
> > This patch is just a tentative implementation of RFC3542 IPV6_PKTINFO
> > sticky option, and is NOT intended to be applied so far.
> > 
> > We need to check if this is okay in RFC POV, anyway.
> 
> ok.  comments from just the RFC pov.

Thank you.  Here's take 2.

diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 78a0d06..cdc4846 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -546,6 +546,10 @@ extern void
ipv6_packet_cleanup(void);
 extern int ip6_datagram_connect(struct sock *sk, 
 struct sockaddr *addr, int 
addr_len);
 
+extern int ip6_datagram_set_pktinfo(struct sock *sk,
+struct in6_pktinfo 
*src_info,
+struct flowi *fl);
+
 extern int ipv6_recv_error(struct sock *sk, struct msghdr 
*msg, int len);
 extern voidipv6_icmp_error(struct sock *sk, struct sk_buff 
*skb, int err, __be16 port,
u32 info, u8 *payload);
diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h
index 409da3a..752a2c0 100644
--- a/include/net/transp_v6.h
+++ b/include/net/transp_v6.h
@@ -36,7 +36,8 @@ extern intdatagram_recv_ctl(struct sock 
*sk,
  struct msghdr *msg,
  struct sk_buff *skb);
 
-extern int datagram_send_ctl(struct msghdr *msg,
+extern int datagram_send_ctl(struct sock *sk,
+ struct msghdr *msg,
  struct flowi *fl,
  struct ipv6_txoptions *opt,
  int *hlimit, int *tclass);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index b1fe7ac..119363a 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -496,7 +496,58 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, 
struct sk_buff *skb)
return 0;
 }
 
-int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
+int ip6_datagram_set_pktinfo(struct sock *sk,
+struct in6_pktinfo *src_info,
+struct flowi *fl)
+{
+   struct net_device *dev = NULL;
+   int addr_type;
+   int err = 0;
+   struct in6_addr *saddr = sk ? &inet6_sk(sk)->saddr : NULL;
+
+   if (src_info->ipi6_ifindex) {
+   dev = dev_get_by_index(src_info->ipi6_ifindex);
+   if (!dev)
+   return -ENODEV;
+   }
+
+   fl->oif = src_info->ipi6_ifindex;
+
+   addr_type = ipv6_addr_type(&src_info->ipi6_addr);
+   if (addr_type == IPV6_ADDR_ANY)
+   goto out;
+
+   err = -EINVAL;
+
+   if (sk && inet_sk(sk)->is_icsk)
+   goto out;
+
+   if (saddr) {
+   if (!ipv6_addr_any(saddr))
+   goto out;
+   if (!ipv6_addr_equal(&src_info->ipi6_addr, saddr))
+   goto out;
+   }
+
+   if (addr_type & IPV6_ADDR_LINKLOCAL) {
+   if (!src_info->ipi6_ifindex)
+   goto out;
+   }
+   if (!ipv6_chk_addr(&src_info->ipi6_addr, dev, 0)) {
+   err = -EADDRNOTAVAIL;
+   goto out;
+   }
+   err = 0;
+   ipv6_addr_copy(&fl->fl6_src, &src_info->ipi6_addr);
+out:
+   if (dev)
+   dev_put(dev);
+
+   return err;
+}
+
+int datagram_send_ctl(struct sock *sk,
+ struct msghdr *msg, struct flowi *fl,
  struct ipv6_txoptions *opt,
  int *hlimit, int *tclass)
 {
@@ -508,8 +559,6 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
int err = 0;
 
for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-   int addr_type;
-   struct net_device *dev = NULL;
 
if (!CMSG_OK(msg, cmsg)) {
err = -EINVAL;
@@ -526,39 +575,11 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi 
*fl,
err = -EINVAL;
goto exit_f;
}
-
src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
 
-   if (src_info->ipi6_ifindex) {
-   if (fl->oif && src_info->ipi6_ifindex != 
fl->oif)
-   return -EINVAL;
-   fl->oif = src_info->ipi6_ifindex;
-   }
-
-   addr_type = i

Re: [**RFC**] [IPV6]: Support RFC3542 IPV6_PKTINFO socket option.

2007-07-16 Thread Vlad Yasevich
Hi Yoshifuji-san

Some more comments below...

YOSHIFUJI Hideaki / 吉藤英明 wrote:
> 
> Thank you.  Here's take 2.
> 
> diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
> index b1fe7ac..119363a 100644
> --- a/net/ipv6/datagram.c
> +++ b/net/ipv6/datagram.c
> @@ -496,7 +496,58 @@ int datagram_recv_ctl(struct sock *sk, struct msghdr 
> *msg, struct sk_buff *skb)
>   return 0;
>  }
>  
> -int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
> +int ip6_datagram_set_pktinfo(struct sock *sk,
> +  struct in6_pktinfo *src_info,
> +  struct flowi *fl)
> +{
> + struct net_device *dev = NULL;
> + int addr_type;
> + int err = 0;
> + struct in6_addr *saddr = sk ? &inet6_sk(sk)->saddr : NULL;
> +
> + if (src_info->ipi6_ifindex) {
> + dev = dev_get_by_index(src_info->ipi6_ifindex);
> + if (!dev)
> + return -ENODEV;
> + }
> +
> + fl->oif = src_info->ipi6_ifindex;
> +
> + addr_type = ipv6_addr_type(&src_info->ipi6_addr);
> + if (addr_type == IPV6_ADDR_ANY)
> + goto out;
> +
> + err = -EINVAL;
> +
> + if (sk && inet_sk(sk)->is_icsk)
> + goto out;
> +

> + if (saddr) {
> + if (!ipv6_addr_any(saddr))
> + goto out;
> + if (!ipv6_addr_equal(&src_info->ipi6_addr, saddr))
> + goto out;
> + }

shouldn't the block above go away?  IPV6_PKTINFO can override the
source address that was bound or specified via other options.

 diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index aa3d07c..3ebcef8 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -456,6 +456,28 @@ sticky_done:
>   break;
>   }
>  
> + case IPV6_PKTINFO:
> + {
> + struct in6_pktinfo pktinfo;
> + struct flowi fl;
> + int err;
> +
> + if (optlen < sizeof(pktinfo))
> + return -EINVAL;
> + if (copy_from_user(&pktinfo, optval, sizeof(pktinfo)))
> + return -EFAULT;
> +
> + fl.fl6_flowlabel = 0;
> + fl.oif = sk->sk_bound_dev_if;
> +
> + lock_sock(sk);
> + err = ip6_datagram_set_pktinfo(sk, &pktinfo, &fl);
> + if (!err)
> + sk->sk_bound_dev_if = fl.oif;
> + release_sock(sk);
> + break;
> + }
> +

Shouldn't this stash the source address out of the fl into something?
Otherwise we lose the source address information.

It seems like adding to ip6_txoptions might be an option.
We seem to have the same issue for IPV6_2292PKTOPTIONS case too.

>   case IPV6_2292PKTOPTIONS:
>   {
>   struct ipv6_txoptions *opt = NULL;
> @@ -490,7 +512,7 @@ sticky_done:
>   msg.msg_controllen = optlen;
>   msg.msg_control = (void*)(opt+1);
>  
> - retv = datagram_send_ctl(&msg, &fl, opt, &junk, &junk);
> + retv = datagram_send_ctl(sk, &msg, &fl, opt, &junk, &junk);
>   if (retv)
>   goto done;
>  update:
> @@ -933,6 +955,29 @@ static int do_ipv6_getsockopt(struct sock *sk, int 
> level, int optname,
>   val = np->ipv6only;
>   break;
>  
> + case IPV6_PKTINFO:
> + {
> + struct in6_pktinfo pktinfo;
> +
> + lock_sock(sk);
> + val = sk->sk_bound_dev_if;
> + release_sock(sk);
> +
> + /*
> +  * XXX: we may need to clear pktinfo to avoid
> +  * disclosing stack here.
> +  */
> + pktinfo.ipi6_addr = inet6_sk(sk)->saddr;
> + pktinfo.ipi6_ifindex = val;
> +
> + len = min_t(unsigned int, sizeof(pktinfo), len);
> + if (put_user(len, optlen))
> + return -EFAULT;
> + if (copy_to_user(optval, &pktinfo, len))
> + return -EFAULT;
> + return 0;
> + }
> +

This returns the bound address, not the address specified in the setsockopt.

Thanks
-vlad
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html