struct netconsole_target *nt;
        struct net_device *dev = ptr;
 
-       if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER))
+       if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
+             event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN))
                goto done;
 
        spin_lock_irqsave(&target_list_lock, flags);
                                strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
                                break;
                        case NETDEV_UNREGISTER:
-                               if (!nt->enabled)
-                                       break;
                                netpoll_cleanup(&nt->np);
+                               /* Fall through */
+                       case NETDEV_GOING_DOWN:
+                       case NETDEV_BONDING_DESLAVE:
                                nt->enabled = 0;
-                               printk(KERN_INFO "netconsole: network logging stopped"
-                                       ", interface %s unregistered\n",
-                                       dev->name);
                                break;
                        }
                }
                netconsole_target_put(nt);
        }
        spin_unlock_irqrestore(&target_list_lock, flags);
+       if (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE)
+               printk(KERN_INFO "netconsole: network logging stopped, "
+                       "interface %s %s\n",  dev->name,
+                       event == NETDEV_UNREGISTER ? "unregistered" : "released slaves");
 
 done:
        return NOTIFY_DONE;
 
                                         * release skb->dst
                                         */
 #define IFF_DONT_BRIDGE 0x800          /* disallow bridging this ether dev */
+#define IFF_IN_NETPOLL 0x1000          /* whether we are processing netpoll */
+#define IFF_DISABLE_NETPOLL    0x2000  /* disable netpoll at run-time */
 
 #define IF_GET_IFACE   0x0001          /* for querying only */
 #define IF_GET_PROTO   0x0002
 
                                                        unsigned short vid);
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
+       void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
                                                  int queue, u8 *mac);
 
 
 struct netpoll {
        struct net_device *dev;
+       struct net_device *real_dev;
        char dev_name[IFNAMSIZ];
        const char *name;
        void (*rx_hook)(struct netpoll *, int, char *, int);
        struct sk_buff_head txq;
 
        struct delayed_work tx_work;
+
+       struct netpoll *netpoll;
 };
 
+void netpoll_poll_dev(struct net_device *dev);
 void netpoll_poll(struct netpoll *np);
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
 void netpoll_set_trap(int trap);
 void netpoll_cleanup(struct netpoll *np);
 int __netpoll_rx(struct sk_buff *skb);
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb);
 
 
 #ifdef CONFIG_NETPOLL
 
 #define NETDEV_POST_TYPE_CHANGE        0x000F
 #define NETDEV_POST_INIT       0x0010
 #define NETDEV_UNREGISTER_BATCH 0x0011
+#define NETDEV_BONDING_DESLAVE  0x0012
 
 #define SYS_DOWN       0x0001  /* Notify of system down */
 #define SYS_RESTART    SYS_DOWN
 
        }
 }
 
-void netpoll_poll(struct netpoll *np)
+void netpoll_poll_dev(struct net_device *dev)
 {
-       struct net_device *dev = np->dev;
        const struct net_device_ops *ops;
 
        if (!dev || !netif_running(dev))
        zap_completion_queue();
 }
 
+void netpoll_poll(struct netpoll *np)
+{
+       netpoll_poll_dev(np->dev);
+}
+
 static void refill_skbs(void)
 {
        struct sk_buff *skb;
        return 0;
 }
 
-static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
+void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 {
        int status = NETDEV_TX_BUSY;
        unsigned long tries;
                     tries > 0; --tries) {
                        if (__netif_tx_trylock(txq)) {
                                if (!netif_tx_queue_stopped(txq)) {
+                                       dev->priv_flags |= IFF_IN_NETPOLL;
                                        status = ops->ndo_start_xmit(skb, dev);
+                                       dev->priv_flags &= ~IFF_IN_NETPOLL;
                                        if (status == NETDEV_TX_OK)
                                                txq_trans_update(txq);
                                }
                atomic_inc(&npinfo->refcnt);
        }
 
-       if (!ndev->netdev_ops->ndo_poll_controller) {
+       npinfo->netpoll = np;
+
+       if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
+           !ndev->netdev_ops->ndo_poll_controller) {
                printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
                       np->name, np->dev_name);
                err = -ENOTSUPP;
                        }
 
                        if (atomic_dec_and_test(&npinfo->refcnt)) {
+                               const struct net_device_ops *ops;
                                skb_queue_purge(&npinfo->arp_tx);
                                skb_queue_purge(&npinfo->txq);
                                cancel_rearming_delayed_work(&npinfo->tx_work);
                                /* clean after last, unfinished work */
                                __skb_queue_purge(&npinfo->txq);
                                kfree(npinfo);
-                               np->dev->npinfo = NULL;
+                               ops = np->dev->netdev_ops;
+                               if (ops->ndo_netpoll_cleanup)
+                                       ops->ndo_netpoll_cleanup(np->dev);
+                               else
+                                       np->dev->npinfo = NULL;
                        }
                }
 
                atomic_dec(&trapped);
 }
 
+EXPORT_SYMBOL(netpoll_send_skb);
 EXPORT_SYMBOL(netpoll_set_trap);
 EXPORT_SYMBOL(netpoll_trap);
 EXPORT_SYMBOL(netpoll_print_options);
 EXPORT_SYMBOL(netpoll_setup);
 EXPORT_SYMBOL(netpoll_cleanup);
 EXPORT_SYMBOL(netpoll_send_udp);
+EXPORT_SYMBOL(netpoll_poll_dev);
 EXPORT_SYMBOL(netpoll_poll);