diff -urp v2.6.33/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.33/linux/Documentation/networking/ip-sysctl.txt	2010-02-25 09:01:26.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2010-02-25 11:47:41.000000000 +0200
@@ -758,6 +758,15 @@ rp_filter - INTEGER
 	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.33/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.33/linux/include/linux/inetdevice.h	2010-02-25 09:01:36.000000000 +0200
+++ linux/include/linux/inetdevice.h	2010-02-25 11:47:41.000000000 +0200
@@ -98,6 +98,7 @@ static inline void ipv4_devconf_setall(s
 #define IN_DEV_PROMOTE_SECONDARIES(in_dev) \
 					IN_DEV_ORCONF((in_dev), \
 						      PROMOTE_SECONDARIES)
+#define IN_DEV_RPFILTER_MASK(in_dev)	IN_DEV_CONF_GET(in_dev, RP_FILTER_MASK)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -urp v2.6.33/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.33/linux/include/linux/sysctl.h	2010-02-25 09:01:36.000000000 +0200
+++ linux/include/linux/sysctl.h	2010-02-25 11:48:12.000000000 +0200
@@ -483,6 +483,7 @@ enum
 	NET_IPV4_CONF_ARP_NOTIFY=22,
 	NET_IPV4_CONF_ACCEPT_LOCAL=23,
 	NET_IPV4_CONF_SRC_VMARK=24,
+	NET_IPV4_CONF_RP_FILTER_MASK=25,
 	__NET_IPV4_CONF_MAX
 };
 
diff -urp v2.6.33/linux/kernel/sysctl_binary.c linux/kernel/sysctl_binary.c
--- v2.6.33/linux/kernel/sysctl_binary.c	2010-02-25 09:01:36.000000000 +0200
+++ linux/kernel/sysctl_binary.c	2010-02-25 11:49:51.000000000 +0200
@@ -247,6 +247,7 @@ static const struct bin_table bin_net_ip
 	{ CTL_INT,	NET_IPV4_CONF_ARP_IGNORE,		"arp_ignore" },
 	{ CTL_INT,	NET_IPV4_CONF_ARP_ACCEPT,		"arp_accept" },
 	{ CTL_INT,	NET_IPV4_CONF_ARP_NOTIFY,		"arp_notify" },
+	{ CTL_INT,	NET_IPV4_CONF_RP_FILTER_MASK,		"rp_filter_mask" },
 
 	{ CTL_INT,	NET_IPV4_CONF_NOXFRM,			"disable_xfrm" },
 	{ CTL_INT,	NET_IPV4_CONF_NOPOLICY,			"disable_policy" },
diff -urp v2.6.33/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.33/linux/net/ipv4/devinet.c	2010-02-25 09:01:36.000000000 +0200
+++ linux/net/ipv4/devinet.c	2010-02-25 11:47:41.000000000 +0200
@@ -1405,6 +1405,7 @@ static struct devinet_sysctl_table {
 		DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
 		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
 		DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"),
+		DEVINET_SYSCTL_RW_ENTRY(RP_FILTER_MASK, "rp_filter_mask"),
 		DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"),
 		DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"),
 		DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"),
diff -urp v2.6.33/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.6.33/linux/net/ipv4/fib_frontend.c	2010-02-25 09:01:36.000000000 +0200
+++ linux/net/ipv4/fib_frontend.c	2010-02-25 11:50:32.000000000 +0200
@@ -242,6 +242,7 @@ int fib_validate_source(__be32 src, __be
 
 	struct fib_result res;
 	int no_addr, rpf, accept_local;
+	unsigned rpf_mask = 0;
 	int ret;
 	struct net *net;
 
@@ -254,6 +255,7 @@ int fib_validate_source(__be32 src, __be
 		accept_local = IN_DEV_ACCEPT_LOCAL(in_dev);
 		if (mark && !IN_DEV_SRC_VMARK(in_dev))
 			fl.mark = 0;
+		rpf_mask = IN_DEV_RPFILTER_MASK(in_dev);
 	}
 	rcu_read_unlock();
 
@@ -279,6 +281,17 @@ int fib_validate_source(__be32 src, __be
 		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;
