diff -urp v4.1/linux/include/uapi/linux/if_bridge.h linux/include/uapi/linux/if_bridge.h
--- v4.1/linux/include/uapi/linux/if_bridge.h	2015-04-13 11:46:47.000000000 +0300
+++ linux/include/uapi/linux/if_bridge.h	2015-06-27 13:39:53.541845379 +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
@@ -71,6 +72,7 @@ struct __bridge_info {
 	__u32 tcn_timer_value;
 	__u32 topology_change_timer_value;
 	__u32 gc_timer_value;
+	__u32 ip_mode;
 };
 
 struct __port_info {
diff -urp v4.1/linux/net/bridge/br_device.c linux/net/bridge/br_device.c
--- v4.1/linux/net/bridge/br_device.c	2015-06-27 10:24:22.000000000 +0300
+++ linux/net/bridge/br_device.c	2015-06-27 13:39:53.542845367 +0300
@@ -383,6 +383,7 @@ void br_dev_setup(struct net_device *dev
 
 	ether_addr_copy(br->group_addr, eth_reserved_addr_base);
 
+	br->ip_mode = 0;
 	br->stp_enabled = BR_NO_STP;
 	br->group_fwd_mask = BR_GROUPFWD_DEFAULT;
 	br->group_fwd_mask_required = BR_GROUPFWD_DEFAULT;
diff -urp v4.1/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v4.1/linux/net/bridge/br_input.c	2015-06-27 10:24:22.000000000 +0300
+++ linux/net/bridge/br_input.c	2015-06-27 13:45:28.375897186 +0300
@@ -122,7 +122,7 @@ static void br_do_proxy_arp(struct sk_bu
 /* note: already called with rcu_read_lock */
 int br_handle_frame_finish(struct sock *sk, struct sk_buff *skb)
 {
-	const unsigned char *dest = eth_hdr(skb)->h_dest;
+	unsigned char *dest = eth_hdr(skb)->h_dest;
 	struct net_bridge_port *p = br_port_get_rcu(skb->dev);
 	struct net_bridge *br;
 	struct net_bridge_fdb_entry *dst;
@@ -130,6 +130,9 @@ int br_handle_frame_finish(struct sock *
 	struct sk_buff *skb2;
 	bool unicast = true;
 	u16 vid = 0;
+	int ip_mode, ret = 0;
+	struct sk_buff *orig_skb = skb;
+	__be16 h_proto;
 
 	if (!p || p->state == BR_STATE_DISABLED)
 		goto drop;
@@ -154,8 +157,14 @@ int br_handle_frame_finish(struct sock *
 	/* The packet skb2 goes to the local host (NULL to skip). */
 	skb2 = NULL;
 
+	ip_mode = 0;
+	h_proto = eth_hdr(skb)->h_proto;
 	if (br->dev->flags & IFF_PROMISC)
 		skb2 = skb;
+	else
+		ip_mode = (br->ip_mode != 0) &&
+			(htons(ETH_P_IP) == h_proto ||
+			htons(ETH_P_ARP) == h_proto);
 
 	dst = NULL;
 
@@ -186,21 +195,51 @@ int br_handle_frame_finish(struct sock *
 		skb2 = skb;
 		/* Do not forward the packet since it's local. */
 		skb = NULL;
+	} else if (ip_mode) {
+		if (!dst || dst->dst->dev == skb->dev)
+			ip_mode = 0;
+	}
+
+	if (ip_mode) {
+		if (htons(ETH_P_IP) == h_proto) {
+			/* deliver IP on port, not on br */
+			ret = 1;
+			if (skb2) {
+				/* No packet on br */
+				skb2 = NULL;
+			} else
+				skb = NULL;	/* Do not forward IP */
+		} else {
+			/* deliver ARP on port and on br */
+			if (skb2) {
+				ret = 1;
+				/* Preserve original skb, use clone */
+				skb2 = skb_clone(skb2, GFP_ATOMIC);
+				if (skb2)
+					BR_INPUT_SKB_CB(skb2)->brdev = br->dev;
+			}
+		}
+		if (ret && PACKET_OTHERHOST == orig_skb->pkt_type) {
+			memcpy(dest, p->dev->dev_addr, p->dev->addr_len);
+			orig_skb->pkt_type = PACKET_HOST;
+		}
 	}
 
 	if (skb) {
+		struct sk_buff *skb_up = ret ? orig_skb : skb2;
+
 		if (dst) {
 			dst->used = jiffies;
-			br_forward(dst->dst, skb, skb2);
+			br_forward(dst->dst, skb, skb_up);
 		} else
-			br_flood_forward(br, skb, skb2, unicast);
+			br_flood_forward(br, skb, skb_up, unicast);
 	}
 
 	if (skb2)
-		return br_pass_frame_up(skb2);
+		br_pass_frame_up(skb2);
 
 out:
-	return 0;
+	return ret;
 drop:
 	kfree_skb(skb);
 	goto out;
@@ -303,6 +342,13 @@ forward:
 		if (ether_addr_equal(p->br->dev->dev_addr, dest))
 			skb->pkt_type = PACKET_HOST;
 
+		if (p->br->ip_mode && !(p->br->dev->flags & IFF_PROMISC)) {
+			if (br_handle_frame_finish(NULL, skb)) {
+				*pskb = skb;
+				return RX_HANDLER_PASS;
+			}
+			break;
+		}
 		NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, NULL, skb,
 			skb->dev, NULL,
 			br_handle_frame_finish);
diff -urp v4.1/linux/net/bridge/br_ioctl.c linux/net/bridge/br_ioctl.c
--- v4.1/linux/net/bridge/br_ioctl.c	2014-04-01 09:50:54.000000000 +0300
+++ linux/net/bridge/br_ioctl.c	2015-06-27 13:39:53.543845356 +0300
@@ -147,6 +147,7 @@ static int old_dev_ioctl(struct net_devi
 		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)))
@@ -290,6 +291,10 @@ static int old_dev_ioctl(struct net_devi
 	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 -urp v4.1/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v4.1/linux/net/bridge/br_private.h	2015-06-27 10:24:22.000000000 +0300
+++ linux/net/bridge/br_private.h	2015-06-27 13:39:53.543845356 +0300
@@ -246,6 +246,7 @@ struct net_bridge
 
 	unsigned char			topology_change;
 	unsigned char			topology_change_detected;
+	unsigned char			ip_mode;
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
 	unsigned char			multicast_router;
diff -urp v4.1/linux/net/bridge/br_sysfs_br.c linux/net/bridge/br_sysfs_br.c
--- v4.1/linux/net/bridge/br_sysfs_br.c	2014-12-12 01:02:26.000000000 +0200
+++ linux/net/bridge/br_sysfs_br.c	2015-06-27 13:39:53.543845356 +0300
@@ -180,6 +180,27 @@ static ssize_t group_fwd_mask_store(stru
 }
 static DEVICE_ATTR_RW(group_fwd_mask);
 
+static ssize_t ipmode_show(struct device *d,
+			   struct device_attribute *attr, char *buf)
+{
+	struct net_bridge *br = to_bridge(d);
+	return sprintf(buf, "%d\n", br->ip_mode);
+}
+
+static int set_ipmode(struct net_bridge *br, unsigned long val)
+{
+	br->ip_mode = val;
+	return 0;
+}
+
+static ssize_t ipmode_store(struct device *d,
+			    struct device_attribute *attr, const char *buf,
+			    size_t len)
+{
+	return store_bridge_parm(d, buf, len, set_ipmode);
+}
+static DEVICE_ATTR_RW(ipmode);
+
 static ssize_t priority_show(struct device *d, struct device_attribute *attr,
 			     char *buf)
 {
@@ -750,6 +771,7 @@ static struct attribute *bridge_attrs[]
 	&dev_attr_ageing_time.attr,
 	&dev_attr_stp_state.attr,
 	&dev_attr_group_fwd_mask.attr,
+	&dev_attr_ipmode.attr,
 	&dev_attr_priority.attr,
 	&dev_attr_bridge_id.attr,
 	&dev_attr_root_id.attr,
