FDDI: defza: Support capturing outgoing SMT traffic
authorMaciej W. Rozycki <macro@linux-mips.org>
Tue, 9 Oct 2018 22:57:49 +0000 (23:57 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Oct 2018 04:46:06 +0000 (21:46 -0700)
DEC FDDIcontroller 700 (DEFZA) uses a Tx/Rx queue pair to communicate
SMT frames with adapter's firmware.  Any SMT frame received from the RMC
via the Rx queue is queued back by the driver to the SMT Rx queue for
the firmware to process.  Similarly the firmware uses the SMT Tx queue
to supply the driver with SMT frames which are queued back to the Tx
queue for the RMC to send to the ring.

When a network tap is attached to an FDDI interface handled by `defza'
any incoming SMT frames captured are queued to our usual processing of
network data received, which in turn delivers them to any listening
taps.

However the outgoing SMT frames produced by the firmware bypass our
network protocol stack and are therefore not delivered to taps.  This in
turn means that taps are missing a part of network traffic sent by the
adapter, which may make it more difficult to track down network problems
or do general traffic analysis.

Call `dev_queue_xmit_nit' then in the SMT Tx path, having checked that
a network tap is attached, with a newly-created `dev_nit_active' helper
wrapping the usual condition used in the transmit path.

Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/fddi/defza.c
include/linux/netdevice.h
net/core/dev.c

index 7d01b70f7ed8b4c8c66b6c8fb233e66791f20c82..3b7f10a5f06a660fbf6408f7adbcd0851ad79921 100644 (file)
@@ -797,11 +797,40 @@ static void fza_tx_smt(struct net_device *dev)
                smt_tx_ptr = fp->mmio + readl_u(&fp->ring_smt_tx[i].buffer);
                len = readl_u(&fp->ring_smt_tx[i].rmc) & FZA_RING_PBC_MASK;
 
-               /* Queue the frame to the RMC transmit ring. */
-               if (!netif_queue_stopped(dev))
+               if (!netif_queue_stopped(dev)) {
+                       if (dev_nit_active(dev)) {
+                               struct sk_buff *skb;
+
+                               /* Length must be a multiple of 4 as only word
+                                * reads are permitted!
+                                */
+                               skb = fza_alloc_skb_irq(dev, (len + 3) & ~3);
+                               if (!skb)
+                                       goto err_no_skb;        /* Drop. */
+
+                               skb_data_ptr = (struct fza_buffer_tx *)
+                                              skb->data;
+
+                               fza_reads(smt_tx_ptr, skb_data_ptr,
+                                         (len + 3) & ~3);
+                               skb->dev = dev;
+                               skb_reserve(skb, 3);    /* Skip over PRH. */
+                               skb_put(skb, len - 3);
+                               skb_reset_network_header(skb);
+
+                               dev_queue_xmit_nit(skb, dev);
+
+                               dev_kfree_skb_irq(skb);
+
+err_no_skb:
+                               ;
+                       }
+
+                       /* Queue the frame to the RMC transmit ring. */
                        fza_do_xmit((union fza_buffer_txp)
                                    { .mmio_ptr = smt_tx_ptr },
                                    len, dev, 1);
+               }
 
                writel_o(FZA_RING_OWN_FZA, &fp->ring_smt_tx[i].own);
                fp->ring_smt_tx_index =
index 22e4ef7bb7010a6cc205f5ed76c66e9a9ea0c79f..dc1d9ed33b3192e9406b17c3107b3235b28ff1b9 100644 (file)
@@ -3645,6 +3645,7 @@ static __always_inline int ____dev_forward_skb(struct net_device *dev,
        return 0;
 }
 
+bool dev_nit_active(struct net_device *dev);
 void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 
 extern int             netdev_budget;
index a4d39b87b4e59f2db03f8e894e7ef83b6c7a80fa..8497feea8fb58401177c3056190351bfadea215d 100644 (file)
@@ -1976,6 +1976,17 @@ static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb)
        return false;
 }
 
+/**
+ * dev_nit_active - return true if any network interface taps are in use
+ *
+ * @dev: network device to check for the presence of taps
+ */
+bool dev_nit_active(struct net_device *dev)
+{
+       return !list_empty(&ptype_all) || !list_empty(&dev->ptype_all);
+}
+EXPORT_SYMBOL_GPL(dev_nit_active);
+
 /*
  *     Support routine. Sends outgoing frames to any network
  *     taps currently in use.
@@ -3233,7 +3244,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
        unsigned int len;
        int rc;
 
-       if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
+       if (dev_nit_active(dev))
                dev_queue_xmit_nit(skb, dev);
 
        len = skb->len;