diff -urp v2.6.17/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt
--- v2.6.17/linux/Documentation/filesystems/proc.txt	2006-06-18 17:23:33.000000000 +0300
+++ linux/Documentation/filesystems/proc.txt	2006-06-18 22:23:30.658222480 +0300
@@ -1699,6 +1699,16 @@ the net,  it  will  prevent  spoofing  a
 (external addresses  can  still  be  spoofed), without the need for additional
 firewall rules.
 
+rp_filter_mask
+--------------
+
+Integer  value representing bitmask of the  mediums for which the reverse path
+protection  is disabled. If  the source validation results  in reverse path to
+interface with medium_id value in the 1..31 range the access is allowed if the
+corresponding  bit is set in the bitmask. The bitmask value is considered only
+when  rp_filter is  enabled. By  default the  bitmask is  empty preserving the
+original rp_filter semantic.
+
 secure_redirects
 ----------------
 
diff -urp v2.6.17/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.17/linux/Documentation/networking/ip-sysctl.txt	2006-06-18 17:23:33.000000000 +0300
+++ linux/Documentation/networking/ip-sysctl.txt	2006-06-18 22:23:30.659222328 +0300
@@ -558,6 +558,15 @@ rp_filter - BOOLEAN
 	Default value is 0. Note that some distributions enable it
 	in startup scripts.
 
+rp_filter_mask - INTEGER
+	Integer value representing bitmask of the mediums for which the
+	reverse path protection is disabled. If the source validation
+	results in reverse path to interface with medium_id value in
+	the 1..31 range the access is allowed if the corresponding bit
+	is set in the bitmask. The bitmask value is considered only when
+	rp_filter is enabled. By default the bitmask is empty preserving
+	the original rp_filter semantic.
+
 arp_filter - BOOLEAN
 	1 - Allows you to have multiple network interfaces on the same
 	subnet, and have the ARPs for each interface be answered
diff -urp v2.6.17/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.17/linux/include/linux/inetdevice.h	2006-06-18 17:23:40.000000000 +0300
+++ linux/include/linux/inetdevice.h	2006-06-18 22:23:30.660222176 +0300
@@ -31,6 +31,7 @@ struct ipv4_devconf
 	int	no_policy;
 	int	force_igmp_version;
 	int	promote_secondaries;
+	int	rp_filter_mask;
 	void	*sysctl;
 };
 
@@ -74,6 +75,7 @@ struct in_device
 #define IN_DEV_IDTAG(in_dev)		((in_dev)->cnf.tag)
 #define IN_DEV_MEDIUM_ID(in_dev)	((in_dev)->cnf.medium_id)
 #define IN_DEV_PROMOTE_SECONDARIES(in_dev)	(ipv4_devconf.promote_secondaries || (in_dev)->cnf.promote_secondaries)
+#define IN_DEV_RPFILTER_MASK(in_dev)	((in_dev)->cnf.rp_filter_mask)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -urp v2.6.17/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.17/linux/include/linux/sysctl.h	2006-06-18 17:23:40.000000000 +0300
+++ linux/include/linux/sysctl.h	2006-06-18 22:25:19.973604016 +0300
@@ -458,6 +458,7 @@ enum
 	NET_IPV4_CONF_ARP_IGNORE=19,
 	NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
 	NET_IPV4_CONF_ARP_ACCEPT=21,
+	NET_IPV4_CONF_RP_FILTER_MASK=22,
 	__NET_IPV4_CONF_MAX
 };
 
diff -urp v2.6.17/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.17/linux/net/ipv4/devinet.c	2006-06-18 17:23:40.000000000 +0300
+++ linux/net/ipv4/devinet.c	2006-06-18 22:23:30.662221872 +0300
@@ -1348,6 +1348,14 @@ static struct devinet_sysctl_table {
 			.proc_handler	= &proc_dointvec,
 		},
 		{
+			.ctl_name	= NET_IPV4_CONF_RP_FILTER_MASK,
+			.procname	= "rp_filter_mask",
+			.data		= &ipv4_devconf.rp_filter_mask,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec,
+		},
+		{
 			.ctl_name	= NET_IPV4_CONF_BOOTP_RELAY,
 			.procname	= "bootp_relay",
 			.data		= &ipv4_devconf.bootp_relay,
diff -urp v2.6.17/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.6.17/linux/net/ipv4/fib_frontend.c	2006-06-18 17:23:40.000000000 +0300
+++ linux/net/ipv4/fib_frontend.c	2006-06-18 22:23:30.663221720 +0300
@@ -171,6 +171,7 @@ int fib_validate_source(u32 src, u32 dst
 			    .iif = oif };
 	struct fib_result res;
 	int no_addr, rpf;
+	unsigned rpf_mask = 0;
 	int ret;
 
 	no_addr = rpf = 0;
@@ -179,6 +180,7 @@ int fib_validate_source(u32 src, u32 dst
 	if (in_dev) {
 		no_addr = in_dev->ifa_list == NULL;
 		rpf = IN_DEV_RPFILTER(in_dev);
+		rpf_mask = IN_DEV_RPFILTER_MASK(in_dev);
 	}
 	rcu_read_unlock();
 
@@ -201,6 +203,17 @@ int fib_validate_source(u32 src, u32 dst
 		fib_res_put(&res);
 		return ret;
 	}
+	if (rpf_mask && rpf) {
+		int omi = 0;
+
+		rcu_read_lock();
+		in_dev = __in_dev_get_rcu(FIB_RES_DEV(res));
+		if (in_dev)
+			omi = IN_DEV_MEDIUM_ID(in_dev);
+		rcu_read_unlock();
+		if (omi >= 1 && omi <= 31 && ((1 << omi) & rpf_mask))
+			rpf = 0;
+	}
 	fib_res_put(&res);
 	if (no_addr)
 		goto last_resort;
