aboutsummaryrefslogtreecommitdiff
path: root/pfinet/linux-src/net/ipv6/raw_ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'pfinet/linux-src/net/ipv6/raw_ipv6.c')
-rw-r--r--pfinet/linux-src/net/ipv6/raw_ipv6.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/pfinet/linux-src/net/ipv6/raw_ipv6.c b/pfinet/linux-src/net/ipv6/raw_ipv6.c
index 95856ea7..9980b3ad 100644
--- a/pfinet/linux-src/net/ipv6/raw_ipv6.c
+++ b/pfinet/linux-src/net/ipv6/raw_ipv6.c
@@ -7,7 +7,7 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw_ipv6.c,v 1.1 2007/10/08 21:12:31 stesie Exp $
+ * $Id: raw_ipv6.c,v 1.2 2007/10/13 01:43:00 stesie Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -128,6 +128,25 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return(-EADDRNOTAVAIL);
} else {
if (addr_type != IPV6_ADDR_ANY) {
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ addr->sin6_scope_id) {
+ /* Override any existing binding,
+ * if another one is supplied by user.
+ */
+ sk->bound_dev_if =
+ addr->sin6_scope_id;
+ }
+
+ /* Binding to link-local address requires
+ an interface */
+ if (!sk->bound_dev_if)
+ return(-EINVAL);
+
+ if (!dev_get_by_index(sk->bound_dev_if))
+ return(-ENODEV);
+ }
+
/* ipv4 addr of the socket is invalid. Only the
* unpecified and mapped address have a v4 equivalent.
*/
@@ -252,6 +271,10 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
sizeof(struct in6_addr));
sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin6->sin6_scope_id =
+ ((struct inet6_skb_parm *) skb->cb)->iif;
}
if (sk->net_pinfo.af_inet6.rxopt.all)
@@ -391,6 +414,11 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
if (sk->state == TCP_ESTABLISHED &&
!ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
daddr = &sk->net_pinfo.af_inet6.daddr;
+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ fl.oif = sin6->sin6_scope_id;
} else {
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);