<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From 2e724cb183f6d9de9e6fffcaaf41d72b13085ad2 Mon Sep 17 00:00:00 2001
From: YOSHIFUJI Hideaki &lt;yoshfuji@linux-ipv6.org&gt;
Date: Wed, 21 Mar 2007 14:07:03 +0100
Subject: [PATCH] [IPV6] FIB6RULE: Find source address during looking up route.

When looking up route for destination with rules with
source address restrictions, we may need to find a source
address for the traffic if not given.

Based on patch from Noriaki TAKAMIYA &lt;takamiya@po.ntts.co.jp&gt;.

Signed-off-by: YOSHIFUJI Hideaki &lt;yoshfuji@linux-ipv6.org&gt;
---
 include/linux/fib_rules.h |    7 +++++--
 net/ipv6/fib6_rules.c     |   34 +++++++++++++++++++++++++++++++---
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h
index 8270aac..2bbfa87 100644
--- a/include/linux/fib_rules.h
+++ b/include/linux/fib_rules.h
@@ -5,8 +5,11 @@
 #include &lt;linux/rtnetlink.h&gt;
 
 /* rule is permanent, and cannot be deleted */
-#define FIB_RULE_PERMANENT	1
-#define FIB_RULE_INVERT		2
+#define FIB_RULE_PERMANENT	0x00000001
+#define FIB_RULE_INVERT		0x00000002
+
+/* try to find source address in routing lookups */
+#define	FIB_RULE_FIND_SADDR	0x00010000
 
 struct fib_rule_hdr
 {
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 0862809..48c6d32 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -17,6 +17,7 @@
 
 #include &lt;net/fib_rules.h&gt;
 #include &lt;net/ipv6.h&gt;
+#include &lt;net/addrconf.h&gt;
 #include &lt;net/ip6_route.h&gt;
 #include &lt;net/netlink.h&gt;
 
@@ -95,8 +96,27 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 	if (table)
 		rt = lookup(table, flp, flags);
 
-	if (rt != &amp;ip6_null_entry)
+	if (rt != &amp;ip6_null_entry) {
+		struct fib6_rule *r = (struct fib6_rule *)rule;
+
+		/*
+		 * If we need to find a source address for this traffic,
+		 * we check the result if it meets requirement of the rule.
+		 */
+		if ((rule-&gt;flags &amp; FIB_RULE_FIND_SADDR) &amp;&amp;
+		    r-&gt;src.plen &amp;&amp; !(flags &amp; RT6_LOOKUP_F_HAS_SADDR)) {
+			struct in6_addr saddr;
+			if (ipv6_get_saddr(&amp;rt-&gt;u.dst, &amp;flp-&gt;fl6_dst,
+					   &amp;saddr))
+				goto again;
+			if (!ipv6_prefix_equal(&amp;saddr, &amp;r-&gt;src.addr,
+					       r-&gt;src.plen))
+				goto again;
+			ipv6_addr_copy(&amp;flp-&gt;fl6_src, &amp;saddr);
+		}
 		goto out;
+	}
+again:
 	dst_release(&amp;rt-&gt;u.dst);
 	rt = NULL;
 	goto out;
@@ -117,9 +137,17 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
 	    !ipv6_prefix_equal(&amp;fl-&gt;fl6_dst, &amp;r-&gt;dst.addr, r-&gt;dst.plen))
 		return 0;
 
+	/*
+	 * If FIB_RULE_FIND_SADDR is set and we do not have a
+	 * source address for the traffic, we defer check for
+	 * source address.
+	 */
 	if (r-&gt;src.plen) {
-		if (!(flags &amp; RT6_LOOKUP_F_HAS_SADDR) ||
-		    !ipv6_prefix_equal(&amp;fl-&gt;fl6_src, &amp;r-&gt;src.addr, r-&gt;src.plen))
+		if (flags &amp; RT6_LOOKUP_F_HAS_SADDR) {
+			if (!ipv6_prefix_equal(&amp;fl-&gt;fl6_src, &amp;r-&gt;src.addr,
+					       r-&gt;src.plen))
+				return 0;
+		} else if (!(r-&gt;common.flags &amp; FIB_RULE_FIND_SADDR))
 			return 0;
 	}
 
-- 
1.5.0.3

</pre></body></html>