diff -ur v2.6.8/linux/include/linux/if_bridge.h linux/include/linux/if_bridge.h
--- v2.6.8/linux/include/linux/if_bridge.h	2004-06-16 23:54:04.000000000 +0300
+++ linux/include/linux/if_bridge.h	2004-08-14 15:50:34.032596240 +0300
@@ -44,6 +44,7 @@
 #define BRCTL_SET_PORT_PRIORITY 16
 #define BRCTL_SET_PATH_COST 17
 #define BRCTL_GET_FDB_ENTRIES 18
+#define BRCTL_SET_BRIDGE_IP_MODE 19
 
 #define BR_STATE_DISABLED 0
 #define BR_STATE_LISTENING 1
@@ -72,6 +73,7 @@
 	__u32 tcn_timer_value;
 	__u32 topology_change_timer_value;
 	__u32 gc_timer_value;
+	__u32 ip_mode;
 };
 
 struct __port_info
diff -ur v2.6.8/linux/net/bridge/br_if.c linux/net/bridge/br_if.c
--- v2.6.8/linux/net/bridge/br_if.c	2004-08-14 11:08:12.000000000 +0300
+++ linux/net/bridge/br_if.c	2004-08-14 15:50:34.032596240 +0300
@@ -156,6 +156,7 @@
 	memset(br->bridge_id.addr, 0, ETH_ALEN);
 
 	br->stp_enabled = 0;
+	br->ip_mode = 0;
 	br->designated_root = br->bridge_id;
 	br->root_path_cost = 0;
 	br->root_port = 0;
diff -ur v2.6.8/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v2.6.8/linux/net/bridge/br_input.c	2004-08-14 11:08:12.000000000 +0300
+++ linux/net/bridge/br_input.c	2004-08-14 15:57:47.947631128 +0300
@@ -31,7 +31,7 @@
 	return 0;
 }
 
-static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
+static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb, int force_local)
 {
 	struct net_device *indev;
 
@@ -40,18 +40,53 @@
 
 	indev = skb->dev;
 	skb->dev = br->dev;
+	if (skb->pkt_type == PACKET_OTHERHOST && force_local)
+		skb->pkt_type = PACKET_HOST;
 
 	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
 			br_pass_frame_up_finish);
 }
 
+#define frame_up(br, skb, clone, force_local) {				\
+	if (ip_mode) {							\
+		if (htons(ETH_P_ARP) == skb->mac.ethernet->h_proto) {	\
+			struct sk_buff *skb2;				\
+									\
+			if ((skb2 = skb_clone(skb, GFP_ATOMIC)))	\
+				br_pass_frame_up(br, skb2, 1);		\
+		}							\
+		passedup = 1;						\
+	} else if (clone) {						\
+		struct sk_buff *skb2;					\
+									\
+		skb2 = skb_clone(skb, GFP_ATOMIC);			\
+		if (skb2) {						\
+			passedup = 1;					\
+			br_pass_frame_up(br, skb2,			\
+					 force_local);			\
+		}							\
+	} else {							\
+		br_pass_frame_up(br, skb, force_local);			\
+	}								\
+}
+
+#define handle_frame(br, p, skb)					\
+	if (ip_mode && passedup) { 					\
+		ret = 1;						\
+		if (PACKET_OTHERHOST != skb->pkt_type)			\
+			goto out;					\
+		memcpy(dest, p->dev->dev_addr, p->dev->addr_len);	\
+		skb->pkt_type = PACKET_HOST;				\
+		goto out;						\
+	}
+
 int br_handle_frame_finish(struct sk_buff *skb)
 {
 	struct net_bridge *br;
 	unsigned char *dest;
 	struct net_bridge_fdb_entry *dst;
 	struct net_bridge_port *p;
-	int passedup;
+	int passedup, ip_mode, ret = 0;
 
 	dest = skb->mac.ethernet->h_dest;
 
@@ -67,31 +102,40 @@
 	br = p->br;
 	passedup = 0;
 	if (br->dev->flags & IFF_PROMISC) {
-		struct sk_buff *skb2;
-
-		skb2 = skb_clone(skb, GFP_ATOMIC);
-		if (skb2 != NULL) {
-			passedup = 1;
-			br_pass_frame_up(br, skb2);
-		}
+		ip_mode = 0;
+		frame_up(br, skb, 1, 0);
+	} else {
+		ip_mode = (br->ip_mode != 0);
 	}
 
 	if (dest[0] & 1) {
-		br_flood_forward(br, skb, !passedup);
+		br_flood_forward(br, skb, !passedup || ip_mode);
 		if (!passedup)
-			br_pass_frame_up(br, skb);
+			frame_up(br, skb, 0, 1);
+		handle_frame(br, p, skb);
 		goto out;
 	}
 
 	dst = __br_fdb_get(br, dest);
-	if (dst != NULL && dst->is_local) {
-		if (!passedup)
-			br_pass_frame_up(br, skb);
-		else
+	if (dst != NULL &&
+	    (dst->is_local ||
+	     (ip_mode && dst->dst->dev != skb->dev &&
+	      htons(ETH_P_IP) == skb->mac.ethernet->h_proto))) {
+		if (!passedup) {
+			frame_up(br, skb, 0, 1);
+			handle_frame(br, p, skb);
+		} else {
+			handle_frame(br, p, skb);
 			kfree_skb(skb);
+		}
 		goto out;
 	}
 
+	if (ip_mode && passedup) {
+		ip_mode = 0;
+		frame_up(br, skb, 1, 0);
+	}
+
 	if (dst != NULL) {
 		br_forward(dst->dst, skb);
 		goto out;
@@ -101,7 +145,7 @@
 
 out:
 	rcu_read_unlock();
-	return 0;
+	return ret;
 }
 
 int br_handle_frame(struct sk_buff *skb)
@@ -135,6 +179,8 @@
 	}
 
 	else if (p->state == BR_STATE_FORWARDING) {
+		int ret = 0;
+
 		if (br_should_route_hook && br_should_route_hook(&skb)) {
 			rcu_read_unlock();
 			return -1;
@@ -143,10 +189,13 @@
 		if (!memcmp(p->br->dev->dev_addr, dest, ETH_ALEN))
 			skb->pkt_type = PACKET_HOST;
 
-		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
-			br_handle_frame_finish);
+		if (!p->br->ip_mode || p->br->dev->flags & IFF_PROMISC)
+			NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
+				br_handle_frame_finish);
+		else
+			ret = br_handle_frame_finish(skb);
 		rcu_read_unlock();
-		return 0;
+		return ret;
 	}
 
 err:
diff -ur v2.6.8/linux/net/bridge/br_ioctl.c linux/net/bridge/br_ioctl.c
--- v2.6.8/linux/net/bridge/br_ioctl.c	2004-08-14 11:08:12.000000000 +0300
+++ linux/net/bridge/br_ioctl.c	2004-08-14 15:50:34.034595936 +0300
@@ -141,6 +141,7 @@
 		b.tcn_timer_value = br_timer_value(&br->tcn_timer);
 		b.topology_change_timer_value = br_timer_value(&br->topology_change_timer);
 		b.gc_timer_value = br_timer_value(&br->gc_timer);
+		b.ip_mode = br->ip_mode;
 	        rcu_read_unlock();
 
 		if (copy_to_user((void __user *)args[1], &b, sizeof(b)))
@@ -303,6 +304,10 @@
 	case BRCTL_GET_FDB_ENTRIES:
 		return get_fdb_entries(br, (void __user *)args[1], 
 				       args[2], args[3]);
+
+	case BRCTL_SET_BRIDGE_IP_MODE:
+		br->ip_mode = args[1]?1:0;
+		return 0;
 	}
 
 	return -EOPNOTSUPP;
diff -ur v2.6.8/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v2.6.8/linux/net/bridge/br_private.h	2004-08-14 11:08:12.000000000 +0300
+++ linux/net/bridge/br_private.h	2004-08-14 15:50:34.034595936 +0300
@@ -109,6 +109,7 @@
 	unsigned char			stp_enabled;
 	unsigned char			topology_change;
 	unsigned char			topology_change_detected;
+	unsigned char			ip_mode;
 
 	struct timer_list		hello_timer;
 	struct timer_list		tcn_timer;
diff -ur v2.6.8/linux/net/bridge/br_sysfs_br.c linux/net/bridge/br_sysfs_br.c
--- v2.6.8/linux/net/bridge/br_sysfs_br.c	2004-08-14 11:08:12.000000000 +0300
+++ linux/net/bridge/br_sysfs_br.c	2004-08-14 15:50:34.035595784 +0300
@@ -156,6 +156,26 @@
 static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
 			 store_stp_state);
 
+static ssize_t show_ipmode(struct class_device *cd, char *buf)
+{
+	struct net_bridge *br = to_bridge(cd);
+	return sprintf(buf, "%d\n", br->ip_mode);
+}
+
+static void set_ipmode(struct net_bridge *br, unsigned long val)
+{
+	br->ip_mode = val;
+}
+
+static ssize_t store_ipmode(struct class_device *cd,
+			       const char *buf, size_t len)
+{
+	return store_bridge_parm(cd, buf, len, set_ipmode);
+}
+
+static CLASS_DEVICE_ATTR(ipmode, S_IRUGO | S_IWUSR, show_ipmode,
+			 store_ipmode);
+
 static ssize_t show_priority(struct class_device *cd, char *buf)
 {
 	struct net_bridge *br = to_bridge(cd);
@@ -247,6 +267,7 @@
 	&class_device_attr_max_age.attr,
 	&class_device_attr_ageing_time.attr,
 	&class_device_attr_stp_state.attr,
+	&class_device_attr_ipmode.attr,
 	&class_device_attr_priority.attr,
 	&class_device_attr_bridge_id.attr,
 	&class_device_attr_root_id.attr,
