|
@@ -2604,70 +2604,14 @@ static inline int deliver_skb(struct sk_buff *skb,
|
|
|
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
|
|
|
}
|
|
|
|
|
|
-#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
|
|
|
-
|
|
|
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
|
|
|
+#if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \
|
|
|
+ (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE))
|
|
|
/* This hook is defined here for ATM LANE */
|
|
|
int (*br_fdb_test_addr_hook)(struct net_device *dev,
|
|
|
unsigned char *addr) __read_mostly;
|
|
|
EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
|
|
|
#endif
|
|
|
|
|
|
-/*
|
|
|
- * If bridge module is loaded call bridging hook.
|
|
|
- * returns NULL if packet was consumed.
|
|
|
- */
|
|
|
-struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
|
|
|
- struct sk_buff *skb) __read_mostly;
|
|
|
-EXPORT_SYMBOL_GPL(br_handle_frame_hook);
|
|
|
-
|
|
|
-static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
|
|
|
- struct packet_type **pt_prev, int *ret,
|
|
|
- struct net_device *orig_dev)
|
|
|
-{
|
|
|
- struct net_bridge_port *port;
|
|
|
-
|
|
|
- if (skb->pkt_type == PACKET_LOOPBACK ||
|
|
|
- (port = rcu_dereference(skb->dev->br_port)) == NULL)
|
|
|
- return skb;
|
|
|
-
|
|
|
- if (*pt_prev) {
|
|
|
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
|
|
|
- *pt_prev = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- return br_handle_frame_hook(port, skb);
|
|
|
-}
|
|
|
-#else
|
|
|
-#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb)
|
|
|
-#endif
|
|
|
-
|
|
|
-#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
|
|
|
-struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *p,
|
|
|
- struct sk_buff *skb) __read_mostly;
|
|
|
-EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
|
|
|
-
|
|
|
-static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
|
|
|
- struct packet_type **pt_prev,
|
|
|
- int *ret,
|
|
|
- struct net_device *orig_dev)
|
|
|
-{
|
|
|
- struct macvlan_port *port;
|
|
|
-
|
|
|
- port = rcu_dereference(skb->dev->macvlan_port);
|
|
|
- if (!port)
|
|
|
- return skb;
|
|
|
-
|
|
|
- if (*pt_prev) {
|
|
|
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
|
|
|
- *pt_prev = NULL;
|
|
|
- }
|
|
|
- return macvlan_handle_frame_hook(port, skb);
|
|
|
-}
|
|
|
-#else
|
|
|
-#define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb)
|
|
|
-#endif
|
|
|
-
|
|
|
#ifdef CONFIG_NET_CLS_ACT
|
|
|
/* TODO: Maybe we should just force sch_ingress to be compiled in
|
|
|
* when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
|
|
@@ -2763,6 +2707,47 @@ void netif_nit_deliver(struct sk_buff *skb)
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * netdev_rx_handler_register - register receive handler
|
|
|
+ * @dev: device to register a handler for
|
|
|
+ * @rx_handler: receive handler to register
|
|
|
+ *
|
|
|
+ * Register a receive hander for a device. This handler will then be
|
|
|
+ * called from __netif_receive_skb. A negative errno code is returned
|
|
|
+ * on a failure.
|
|
|
+ *
|
|
|
+ * The caller must hold the rtnl_mutex.
|
|
|
+ */
|
|
|
+int netdev_rx_handler_register(struct net_device *dev,
|
|
|
+ rx_handler_func_t *rx_handler)
|
|
|
+{
|
|
|
+ ASSERT_RTNL();
|
|
|
+
|
|
|
+ if (dev->rx_handler)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ rcu_assign_pointer(dev->rx_handler, rx_handler);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(netdev_rx_handler_register);
|
|
|
+
|
|
|
+/**
|
|
|
+ * netdev_rx_handler_unregister - unregister receive handler
|
|
|
+ * @dev: device to unregister a handler from
|
|
|
+ *
|
|
|
+ * Unregister a receive hander from a device.
|
|
|
+ *
|
|
|
+ * The caller must hold the rtnl_mutex.
|
|
|
+ */
|
|
|
+void netdev_rx_handler_unregister(struct net_device *dev)
|
|
|
+{
|
|
|
+
|
|
|
+ ASSERT_RTNL();
|
|
|
+ rcu_assign_pointer(dev->rx_handler, NULL);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
|
|
|
+
|
|
|
static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
|
|
|
struct net_device *master)
|
|
|
{
|
|
@@ -2815,6 +2800,7 @@ EXPORT_SYMBOL(__skb_bond_should_drop);
|
|
|
static int __netif_receive_skb(struct sk_buff *skb)
|
|
|
{
|
|
|
struct packet_type *ptype, *pt_prev;
|
|
|
+ rx_handler_func_t *rx_handler;
|
|
|
struct net_device *orig_dev;
|
|
|
struct net_device *master;
|
|
|
struct net_device *null_or_orig;
|
|
@@ -2877,12 +2863,17 @@ static int __netif_receive_skb(struct sk_buff *skb)
|
|
|
ncls:
|
|
|
#endif
|
|
|
|
|
|
- skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
|
|
|
- if (!skb)
|
|
|
- goto out;
|
|
|
- skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
|
|
|
- if (!skb)
|
|
|
- goto out;
|
|
|
+ /* Handle special case of bridge or macvlan */
|
|
|
+ rx_handler = rcu_dereference(skb->dev->rx_handler);
|
|
|
+ if (rx_handler) {
|
|
|
+ if (pt_prev) {
|
|
|
+ ret = deliver_skb(skb, pt_prev, orig_dev);
|
|
|
+ pt_prev = NULL;
|
|
|
+ }
|
|
|
+ skb = rx_handler(skb);
|
|
|
+ if (!skb)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* Make sure frames received on VLAN interfaces stacked on
|