summaryrefslogtreecommitdiffstats
path: root/net/ipv6/raw.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-06-13 16:29:25 +0000
commitdb7d4daea91e105e3859cf461d7e53b9b77454b2 (patch)
tree9bb65b95440af09e8aca63abe56970dd3360cc57 /net/ipv6/raw.c
parent9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff)
Merge with Linux 2.2.8.
Diffstat (limited to 'net/ipv6/raw.c')
-rw-r--r--net/ipv6/raw.c46
1 files changed, 39 insertions, 7 deletions
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 3b02e06d9..f82ac33db 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -7,7 +7,7 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.23 1998/11/08 11:17:09 davem Exp $
+ * $Id: raw.c,v 1.24 1999/04/22 10:07:45 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -283,6 +283,7 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
sin6->sin6_family = AF_INET6;
memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
sizeof(struct in6_addr));
+ sin6->sin6_flowinfo = 0;
}
if (sk->net_pinfo.af_inet6.rxopt.all)
@@ -363,7 +364,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr *saddr = NULL;
+ struct ip6_flowlabel *flowlabel = NULL;
struct flowi fl;
int addr_len = msg->msg_namelen;
struct in6_addr *daddr;
@@ -388,6 +389,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
* Get and verify the address.
*/
+ fl.fl6_flowlabel = 0;
+
if (sin6) {
if (addr_len < sizeof(struct sockaddr_in6))
return(-EINVAL);
@@ -405,12 +408,28 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
return(-EINVAL);
daddr = &sin6->sin6_addr;
+ if (np->sndflow) {
+ fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ daddr = &flowlabel->dst;
+ }
+ }
+
+
+ /* Otherwise it will be difficult to maintain sk->dst_cache. */
+ if (sk->state == TCP_ESTABLISHED &&
+ !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
+ daddr = &sk->net_pinfo.af_inet6.daddr;
} else {
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
proto = sk->num;
daddr = &(sk->net_pinfo.af_inet6.daddr);
+ fl.fl6_flowlabel = np->flow_label;
}
if (ipv6_addr_any(daddr)) {
@@ -422,23 +441,34 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
}
fl.oif = sk->bound_dev_if;
+ fl.fl6_src = NULL;
if (msg->msg_controllen) {
opt = &opt_space;
memset(opt, 0, sizeof(struct ipv6_txoptions));
- err = datagram_send_ctl(msg, &fl.oif, &saddr, opt, &hlimit);
- if (err < 0)
+ err = datagram_send_ctl(msg, &fl, opt, &hlimit);
+ if (err < 0) {
+ fl6_sock_release(flowlabel);
return err;
+ }
+ if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (flowlabel == NULL)
+ return -EINVAL;
+ }
+ if (!(opt->opt_nflen|opt->opt_flen))
+ opt = NULL;
}
- if (opt == NULL || !(opt->opt_nflen|opt->opt_flen))
+ if (opt == NULL)
opt = np->opt;
+ if (flowlabel)
+ opt = fl6_merge_options(&opt_space, flowlabel, opt);
raw_opt = &sk->tp_pinfo.tp_raw;
fl.proto = proto;
- fl.nl_u.ip6_u.daddr = daddr;
- fl.nl_u.ip6_u.saddr = saddr;
+ fl.fl6_dst = daddr;
fl.uli_u.icmpt.type = 0;
fl.uli_u.icmpt.code = 0;
@@ -463,6 +493,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
opt, hlimit, msg->msg_flags);
}
+ fl6_sock_release(flowlabel);
+
return err<0?err:len;
}