patch-2.2.7 linux/net/ipv6/udp.c
Next file: linux/net/irda/af_irda.c
Previous file: linux/net/ipv6/tcp_ipv6.c
Back to the patch index
Back to the overall index
- Lines: 226
- Date:
Thu Apr 22 19:45:20 1999
- Orig file:
v2.2.6/linux/net/ipv6/udp.c
- Orig date:
Tue Mar 23 14:35:48 1999
diff -u --recursive --new-file v2.2.6/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
@@ -7,7 +7,7 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.38 1999/03/21 05:23:00 davem Exp $
+ * $Id: udp.c,v 1.39 1999/04/22 10:07:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -204,6 +204,7 @@
struct in6_addr saddr;
struct dst_entry *dst;
struct flowi fl;
+ struct ip6_flowlabel *flowlabel = NULL;
int addr_type;
int err;
@@ -218,6 +219,17 @@
if (usin->sin6_family && usin->sin6_family != AF_INET6)
return(-EAFNOSUPPORT);
+ fl.fl6_flowlabel = 0;
+ if (np->sndflow) {
+ fl.fl6_flowlabel = usin->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;
+ ipv6_addr_copy(&usin->sin6_addr, &flowlabel->dst);
+ }
+ }
+
addr_type = ipv6_addr_type(&usin->sin6_addr);
if (addr_type == IPV6_ADDR_ANY) {
@@ -262,6 +274,7 @@
}
ipv6_addr_copy(&np->daddr, daddr);
+ np->flow_label = fl.fl6_flowlabel;
sk->dport = usin->sin6_port;
@@ -271,25 +284,31 @@
*/
fl.proto = IPPROTO_UDP;
- fl.nl_u.ip6_u.daddr = &np->daddr;
- fl.nl_u.ip6_u.saddr = NULL;
+ fl.fl6_dst = &np->daddr;
+ fl.fl6_src = &saddr;
fl.oif = sk->bound_dev_if;
fl.uli_u.ports.dport = sk->dport;
fl.uli_u.ports.sport = sk->sport;
- if (np->opt && np->opt->srcrt) {
+ if (flowlabel) {
+ if (flowlabel->opt && flowlabel->opt->srcrt) {
+ struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
+ fl.fl6_dst = rt0->addr;
+ }
+ } else if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- fl.nl_u.ip6_u.daddr = rt0->addr;
+ fl.fl6_dst = rt0->addr;
}
dst = ip6_route_output(sk, &fl);
if ((err = dst->error) != 0) {
dst_release(dst);
+ fl6_sock_release(flowlabel);
return err;
}
- ip6_dst_store(sk, dst, fl.nl_u.ip6_u.daddr);
+ ip6_dst_store(sk, dst, fl.fl6_dst);
/* get the source adddress used in the apropriate device */
@@ -305,6 +324,7 @@
}
sk->state = TCP_ESTABLISHED;
}
+ fl6_sock_release(flowlabel);
return err;
}
@@ -396,6 +416,7 @@
sin6 = (struct sockaddr_in6 *) msg->msg_name;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = skb->h.uh->source;
+ sin6->sin6_flowinfo = 0;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
ipv6_addr_set(&sin6->sin6_addr, 0, 0,
@@ -734,10 +755,10 @@
struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
struct ipv6_txoptions *opt = NULL;
+ struct ip6_flowlabel *flowlabel = NULL;
struct flowi fl;
int addr_len = msg->msg_namelen;
struct in6_addr *daddr;
- struct in6_addr *saddr = NULL;
int len = ulen + sizeof(struct udphdr);
int addr_type;
int hlimit = -1;
@@ -752,23 +773,35 @@
if (msg->msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT))
return(-EINVAL);
-
+
+ fl.fl6_flowlabel = 0;
+
if (sin6) {
if (sin6->sin6_family == AF_INET)
return udp_sendmsg(sk, msg, ulen);
if (addr_len < sizeof(*sin6))
return(-EINVAL);
-
+
if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
return(-EINVAL);
if (sin6->sin6_port == 0)
return(-EINVAL);
-
+
udh.uh.dest = sin6->sin6_port;
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))
@@ -776,38 +809,52 @@
} else {
if (sk->state != TCP_ESTABLISHED)
return(-ENOTCONN);
-
+
udh.uh.dest = sk->dport;
daddr = &sk->net_pinfo.af_inet6.daddr;
+ fl.fl6_flowlabel = np->flow_label;
}
-
+
addr_type = ipv6_addr_type(daddr);
-
+
if (addr_type == IPV6_ADDR_MAPPED) {
struct sockaddr_in sin;
-
+
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = daddr->s6_addr32[3];
sin.sin_port = udh.uh.dest;
msg->msg_name = (struct sockaddr *)(&sin);
msg->msg_namelen = sizeof(sin);
+ fl6_sock_release(flowlabel);
return udp_sendmsg(sk, msg, ulen);
}
-
+
udh.daddr = NULL;
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);
if (opt && opt->srcrt)
udh.daddr = daddr;
@@ -819,13 +866,14 @@
udh.pl_len = len;
fl.proto = IPPROTO_UDP;
- fl.nl_u.ip6_u.daddr = daddr;
- fl.nl_u.ip6_u.saddr = saddr;
+ fl.fl6_dst = daddr;
fl.uli_u.ports.dport = udh.uh.dest;
fl.uli_u.ports.sport = udh.uh.source;
err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
msg->msg_flags);
+
+ fl6_sock_release(flowlabel);
if (err < 0)
return err;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)