diff -urp v4.20/linux/include/uapi/linux/if_bridge.h linux/include/uapi/linux/if_bridge.h
--- v4.20/linux/include/uapi/linux/if_bridge.h	2018-08-12 23:41:04.000000000 +0300
+++ linux/include/uapi/linux/if_bridge.h	2019-01-20 15:11:23.352455287 +0200
@@ -45,6 +45,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 @@ 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.20/linux/net/bridge/br_device.c linux/net/bridge/br_device.c
--- v4.20/linux/net/bridge/br_device.c	2019-01-20 14:18:30.000000000 +0200
+++ linux/net/bridge/br_device.c	2019-01-20 15:11:23.353455273 +0200
@@ -433,6 +433,7 @@ void br_dev_setup(struct net_device *dev
 
 	ether_addr_copy(br->group_addr, eth_stp_addr);
 
+	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.20/linux/net/bridge/br_input.c linux/net/bridge/br_input.c
--- v4.20/linux/net/bridge/br_input.c	2019-01-20 14:18:30.000000000 +0200
+++ linux/net/bridge/br_input.c	2019-01-20 15:11:23.353455273 +0200
@@ -79,9 +79,11 @@ int br_handle_frame_finish(struct net *n
 	struct net_bridge_fdb_entry *dst = NULL;
 	struct net_bridge_mdb_entry *mdst;
 	bool local_rcv, mcast_hit = false;
-	const unsigned char *dest;
+	unsigned char *dest;
 	struct net_bridge *br;
 	u16 vid = 0;
+	int ip_mode, ret = 0;
+	__be16 h_proto;
 
 	if (!p || p->state == BR_STATE_DISABLED)
 		goto drop;
@@ -97,6 +99,10 @@ int br_handle_frame_finish(struct net *n
 		br_fdb_update(br, p, eth_hdr(skb)->h_source, vid, false);
 
 	local_rcv = !!(br->dev->flags & IFF_PROMISC);
+	h_proto = eth_hdr(skb)->h_proto;
+	ip_mode = !local_rcv && (br->ip_mode != 0) &&
+		  (htons(ETH_P_IP) == h_proto ||
+		   htons(ETH_P_ARP) == h_proto);
 	dest = eth_hdr(skb)->h_dest;
 	if (is_multicast_ether_addr(dest)) {
 		/* by definition the broadcast is also a multicast address */
@@ -155,15 +161,47 @@ int br_handle_frame_finish(struct net *n
 		break;
 	}
 
-	if (dst) {
-		unsigned long now = jiffies;
+	if (ip_mode) {
+		bool fwd = true;
 
-		if (dst->is_local)
-			return br_pass_frame_up(skb);
+		if (htons(ETH_P_IP) == h_proto) {
+			/* deliver IP on port, not on br */
+			ret = 1;
+			if (local_rcv) {
+				/* No packet on br */
+				local_rcv = false;
+			} else
+				fwd = false;	/* Do not forward IP */
+		} else {
+			/* deliver ARP on port and on br */
+			if (local_rcv) {
+				struct sk_buff *skb2 = skb_clone(skb,
+								 GFP_ATOMIC);
+
+				ret = 1;
+				/* Preserve original skb, use clone */
+				if (skb2) {
+					BR_INPUT_SKB_CB(skb2)->brdev = br->dev;
+					br_pass_frame_up(skb2);
+				}
+			}
+		}
+		if (ret && PACKET_OTHERHOST == skb->pkt_type) {
+			memcpy(dest, p->dev->dev_addr, p->dev->addr_len);
+			skb->pkt_type = PACKET_HOST;
+		}
+		if (!fwd)
+			goto out;
+	}
 
-		if (now != dst->used)
-			dst->used = now;
-		br_forward(dst->dst, skb, local_rcv, false);
+	if (dst) {
+		if (!dst->is_local) {
+			unsigned long now = jiffies;
+
+			if (now != dst->used)
+				dst->used = now;
+			br_forward(dst->dst, skb, local_rcv, false);
+		}
 	} else {
 		if (!mcast_hit)
 			br_flood(br, skb, pkt_type, local_rcv, false);
@@ -171,11 +209,11 @@ int br_handle_frame_finish(struct net *n
 			br_multicast_flood(mdst, skb, local_rcv, false);
 	}
 
-	if (local_rcv)
-		return br_pass_frame_up(skb);
+	if (local_rcv && !ret)
+		br_pass_frame_up(skb);
 
 out:
-	return 0;
+	return ret;
 drop:
 	kfree_skb(skb);
 	goto out;
@@ -300,6 +338,14 @@ 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(dev_net(skb->dev), NULL,
+						   skb)) {
+				*pskb = skb;
+				return RX_HANDLER_PASS;
+			}
+			break;
+		}
 		NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
 			dev_net(skb->dev), NULL, skb, skb->dev, NULL,
 			br_handle_frame_finish);
diff -urp v4.20/linux/net/bridge/br_ioctl.c linux/net/bridge/br_ioctl.c
--- v4.20/linux/net/bridge/br_ioctl.c	2018-08-12 23:41:04.000000000 +0300
+++ linux/net/bridge/br_ioctl.c	2019-01-20 15:11:23.353455273 +0200
@@ -150,6 +150,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_work.timer);
+		b.ip_mode = br->ip_mode;
 		rcu_read_unlock();
 
 		if (copy_to_user((void __user *)args[1], &b, sizeof(b)))
@@ -289,6 +290,11 @@ 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;
+		ret = 0;
+		break;
 	}
 
 	if (!ret) {
diff -urp v4.20/linux/net/bridge/br_private.h linux/net/bridge/br_private.h
--- v4.20/linux/net/bridge/br_private.h	2019-01-20 14:18:30.000000000 +0200
+++ linux/net/bridge/br_private.h	2019-01-20 15:13:58.631290698 +0200
@@ -371,6 +371,7 @@ struct net_bridge {
 	u32				root_path_cost;
 
 	u8				group_addr[ETH_ALEN];
+	unsigned char			ip_mode;
 
 	enum {
 		BR_NO_STP, 		/* no spanning tree */
diff -urp v4.20/linux/net/bridge/br_sysfs_br.c linux/net/bridge/br_sysfs_br.c
--- v4.20/linux/net/bridge/br_sysfs_br.c	2019-01-20 14:18:30.000000000 +0200
+++ linux/net/bridge/br_sysfs_br.c	2019-01-20 15:11:23.355455245 +0200
@@ -170,6 +170,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)
 {
@@ -828,6 +849,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,
