diff -urN linux-2.4.26-pre5/Documentation/filesystems/proc.txt linux-2.4.26-pre5-sts/Documentation/filesystems/proc.txt
--- linux-2.4.26-pre5/Documentation/filesystems/proc.txt	Mon Apr 21 22:40:56 2003
+++ linux-2.4.26-pre5-sts/Documentation/filesystems/proc.txt	Sat Mar 20 23:28:36 2004
@@ -1527,6 +1527,15 @@
 
 Log packets with source addresses with no known route to kernel log.
 
+loop
+----
+
+By default (loop=0) the traffic between local IP addresses
+is routed via interface "lo". Setting this flag for two
+interfaces allows traffic between their IP addresses to
+be looped externally. This is useful for setups where the
+interfaces are attached to same broadcast medium.
+
 mc_forwarding
 -------------
 
diff -urN linux-2.4.26-pre5/Documentation/networking/ip-sysctl.txt linux-2.4.26-pre5-sts/Documentation/networking/ip-sysctl.txt
--- linux-2.4.26-pre5/Documentation/networking/ip-sysctl.txt	Sat Mar 20 10:08:18 2004
+++ linux-2.4.26-pre5-sts/Documentation/networking/ip-sysctl.txt	Sat Mar 20 23:28:36 2004
@@ -391,6 +391,13 @@
 	conf/all/mc_forwarding must also be set to TRUE to enable multicast routing
 	for the interface
 
+loop - BOOLEAN
+	By default (loop=0) the traffic between local IP addresses
+	is routed via interface "lo". Setting this flag for two
+	interfaces allows traffic between their IP addresses to
+	be looped externally. This is useful for setups where the
+	interfaces are attached to same broadcast medium.
+
 medium_id - INTEGER
 	Integer value used to differentiate the devices by the medium they
 	are attached to. Two devices can have different id values when
diff -urN linux-2.4.26-pre5/include/linux/inetdevice.h linux-2.4.26-pre5-sts/include/linux/inetdevice.h
--- linux-2.4.26-pre5/include/linux/inetdevice.h	Sat Mar 20 10:08:20 2004
+++ linux-2.4.26-pre5-sts/include/linux/inetdevice.h	Sat Mar 20 23:29:55 2004
@@ -22,6 +22,7 @@
 	int	arp_ignore;
 	int	medium_id;
 	int	force_igmp_version;
+	int	loop;
 	void	*sysctl;
 };
 
@@ -73,6 +74,7 @@
 #define IN_DEV_ARPFILTER(in_dev)	(ipv4_devconf.arp_filter || (in_dev)->cnf.arp_filter)
 #define IN_DEV_ARP_ANNOUNCE(in_dev)	(max(ipv4_devconf.arp_announce, (in_dev)->cnf.arp_announce))
 #define IN_DEV_ARP_IGNORE(in_dev)	(max(ipv4_devconf.arp_ignore, (in_dev)->cnf.arp_ignore))
+#define IN_DEV_LOOP(in_dev)		((in_dev)->cnf.loop)
 
 struct in_ifaddr
 {
diff -urN linux-2.4.26-pre5/include/linux/sysctl.h linux-2.4.26-pre5-sts/include/linux/sysctl.h
--- linux-2.4.26-pre5/include/linux/sysctl.h	Sat Mar 20 10:10:11 2004
+++ linux-2.4.26-pre5-sts/include/linux/sysctl.h	Sat Mar 20 23:30:48 2004
@@ -364,6 +364,7 @@
 	NET_IPV4_CONF_FORCE_IGMP_VERSION=17,
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 	NET_IPV4_CONF_ARP_IGNORE=19,
+ 	NET_IPV4_CONF_LOOP=20,
 };
 
 /* /proc/sys/net/ipv4/netfilter */
diff -urN linux-2.4.26-pre5/net/ipv4/devinet.c linux-2.4.26-pre5-sts/net/ipv4/devinet.c
--- linux-2.4.26-pre5/net/ipv4/devinet.c	Sat Mar 20 10:08:21 2004
+++ linux-2.4.26-pre5-sts/net/ipv4/devinet.c	Sat Mar 20 23:32:05 2004
@@ -1134,7 +1134,7 @@
 static struct devinet_sysctl_table
 {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[20];
+	ctl_table devinet_vars[21];
 	ctl_table devinet_dev[2];
 	ctl_table devinet_conf_dir[2];
 	ctl_table devinet_proto_dir[2];
@@ -1188,6 +1188,9 @@
 	 &proc_dointvec},
 	{NET_IPV4_CONF_ARP_IGNORE, "arp_ignore",
 	 &ipv4_devconf.arp_ignore, sizeof(int), 0644, NULL,
+	 &proc_dointvec},
+	{NET_IPV4_CONF_LOOP, "loop",
+	 &ipv4_devconf.loop, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
 	{NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version",
 	 &ipv4_devconf.force_igmp_version, sizeof(int), 0644, NULL,
diff -urN linux-2.4.26-pre5/net/ipv4/fib_frontend.c linux-2.4.26-pre5-sts/net/ipv4/fib_frontend.c
--- linux-2.4.26-pre5/net/ipv4/fib_frontend.c	Sat Sep 13 07:57:34 2003
+++ linux-2.4.26-pre5-sts/net/ipv4/fib_frontend.c	Sat Mar 20 23:28:36 2004
@@ -209,7 +209,7 @@
 	struct in_device *in_dev;
 	struct rt_key key;
 	struct fib_result res;
-	int no_addr, rpf;
+	int no_addr, rpf, loop;
 	int ret;
 
 	key.dst = src;
@@ -219,12 +219,13 @@
 	key.iif = oif;
 	key.scope = RT_SCOPE_UNIVERSE;
 
-	no_addr = rpf = 0;
+	no_addr = rpf = loop = 0;
 	read_lock(&inetdev_lock);
 	in_dev = __in_dev_get(dev);
 	if (in_dev) {
 		no_addr = in_dev->ifa_list == NULL;
 		rpf = IN_DEV_RPFILTER(in_dev);
+		loop = IN_DEV_LOOP(in_dev);
 	}
 	read_unlock(&inetdev_lock);
 
@@ -233,6 +234,11 @@
 
 	if (fib_lookup(&key, &res))
 		goto last_resort;
+	if (loop && res.type == RTN_LOCAL) {
+		*spec_dst = FIB_RES_PREFSRC(res);
+		fib_res_put(&res);
+		return 0;
+	}
 	if (res.type != RTN_UNICAST)
 		goto e_inval_res;
 	*spec_dst = FIB_RES_PREFSRC(res);
diff -urN linux-2.4.26-pre5/net/ipv4/route.c linux-2.4.26-pre5-sts/net/ipv4/route.c
--- linux-2.4.26-pre5/net/ipv4/route.c	Sat Dec  6 08:14:52 2003
+++ linux-2.4.26-pre5-sts/net/ipv4/route.c	Sat Mar 20 23:28:36 2004
@@ -1853,6 +1853,11 @@
 			dev_put(dev_out);
 			goto out;	/* Wrong error code */
 		}
+		err = -ENETDOWN;
+		if (!(dev_out->flags&IFF_UP)) {
+			dev_put(dev_out);
+			goto out;
+		}
 
 		if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) {
 			if (!key.src)
@@ -1922,10 +1927,41 @@
 		goto e_inval;
 
 	if (res.type == RTN_LOCAL) {
-		if (!key.src)
-			key.src = key.dst;
+		struct in_device *in_dev;
+		u32 src;
+
 		if (dev_out)
 			dev_put(dev_out);
+		dev_out = FIB_RES_DEV(res);
+		in_dev = in_dev_get(dev_out);
+		src = key.src? : FIB_RES_PREFSRC(res);
+		if (in_dev && IN_DEV_LOOP(in_dev) && src) {
+			struct net_device *dev_src;
+
+			in_dev_put(in_dev);
+			in_dev = NULL;
+			dev_src = ip_dev_find(src);
+			if (dev_src && dev_src != dev_out &&
+			    (in_dev = in_dev_get(dev_src)) &&
+			    IN_DEV_LOOP(in_dev)) {
+				in_dev_put(in_dev);
+				dev_out = dev_src;
+				key.src = src;
+				key.oif = dev_out->ifindex;
+				res.type = RTN_UNICAST;
+				if (res.fi) {
+					fib_info_put(res.fi);
+					res.fi = NULL;
+				}
+				goto make_route;
+			}
+			if (dev_src)
+				dev_put(dev_src);
+		}
+		if (in_dev)
+			in_dev_put(in_dev);
+		if (!key.src)
+			key.src = key.dst;
 		dev_out = &loopback_dev;
 		dev_hold(dev_out);
 		key.oif = dev_out->ifindex;