Author: sephe
Date: Mon Apr 10 03:23:57 2017
New Revision: 316672
URL: https://svnweb.freebsd.org/changeset/base/316672
Log:
MFC 316520
hyperv/hn: Fixat RNDIS rxfilter after the successful RNDIS init.
Under certain conditions on certain versions of Hyper-V, the RNDIS
rxfilter is _not_ zero on the hypervisor side after the successful
RNDIS initialization, which breaks the assumption of any following
code (well, it breaks the RNDIS API contract actually). Clear the
RNDIS rxfilter explicitly, drain packets sneaking through, and drain
the interrupt taskqueues scheduled due to the stealth packets.
Reported by:dexuan@
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D10230
Modified:
stable/10/sys/dev/hyperv/netvsc/hn_rndis.c
stable/10/sys/dev/hyperv/netvsc/hn_rndis.h
stable/10/sys/dev/hyperv/netvsc/if_hn.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/hyperv/netvsc/hn_rndis.c
==
--- stable/10/sys/dev/hyperv/netvsc/hn_rndis.c Mon Apr 10 03:09:12 2017
(r316671)
+++ stable/10/sys/dev/hyperv/netvsc/hn_rndis.c Mon Apr 10 03:23:57 2017
(r316672)
@@ -980,16 +980,19 @@ hn_rndis_query_hwcaps(struct hn_softc *s
}
int
-hn_rndis_attach(struct hn_softc *sc, int mtu)
+hn_rndis_attach(struct hn_softc *sc, int mtu, int *init_done)
{
int error;
+ *init_done = 0;
+
/*
* Initialize RNDIS.
*/
error = hn_rndis_init(sc);
if (error)
return (error);
+ *init_done = 1;
/*
* Configure NDIS offload settings.
Modified: stable/10/sys/dev/hyperv/netvsc/hn_rndis.h
==
--- stable/10/sys/dev/hyperv/netvsc/hn_rndis.h Mon Apr 10 03:09:12 2017
(r316671)
+++ stable/10/sys/dev/hyperv/netvsc/hn_rndis.h Mon Apr 10 03:23:57 2017
(r316672)
@@ -33,7 +33,7 @@
struct hn_softc;
-inthn_rndis_attach(struct hn_softc *sc, int mtu);
+inthn_rndis_attach(struct hn_softc *sc, int mtu, int *init_done);
void hn_rndis_detach(struct hn_softc *sc);
inthn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags);
inthn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt);
Modified: stable/10/sys/dev/hyperv/netvsc/if_hn.c
==
--- stable/10/sys/dev/hyperv/netvsc/if_hn.c Mon Apr 10 03:09:12 2017
(r316671)
+++ stable/10/sys/dev/hyperv/netvsc/if_hn.c Mon Apr 10 03:23:57 2017
(r316672)
@@ -256,6 +256,7 @@ static void hn_rndis_rx_data(struct hn
const void *, int);
static voidhn_rndis_rx_status(struct hn_softc *,
const void *, int);
+static voidhn_rndis_init_fixat(struct hn_softc *, int);
static voidhn_nvs_handle_notify(struct hn_softc *,
const struct vmbus_chanpkt_hdr *);
@@ -321,6 +322,8 @@ static void hn_resume_mgmt(struct hn_s
static voidhn_suspend_mgmt_taskfunc(void *, int);
static voidhn_chan_drain(struct hn_softc *,
struct vmbus_channel *);
+static voidhn_disable_rx(struct hn_softc *);
+static voidhn_drain_rxtx(struct hn_softc *, int);
static voidhn_polling(struct hn_softc *, u_int);
static voidhn_chan_polling(struct vmbus_channel *, u_int);
@@ -2256,6 +2259,18 @@ hn_rxpkt(struct hn_rx_ring *rxr, const v
/* If the VF is active, inject the packet through the VF */
ifp = rxr->hn_vf ? rxr->hn_vf : rxr->hn_ifp;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ /*
+* NOTE:
+* See the NOTE of hn_rndis_init_fixat(). This
+* function can be reached, immediately after the
+* RNDIS is initialized but before the ifnet is
+* setup on the hn_attach() path; drop the unexpected
+* packets.
+*/
+ return (0);
+ }
+
if (dlen <= MHLEN) {
m_new = m_gethdr(M_NOWAIT, MT_DATA);
if (m_new == NULL) {
@@ -4685,6 +4700,27 @@ hn_synth_attachable(const struct hn_soft
return (true);
}
+/*
+ * Make sure that the RX filter is zero after the successful
+ * RNDIS initialization.
+ *
+ * NOTE:
+ * Under certain conditions on certain versions of Hyper-V,
+ * the RNDIS rxfilter is _not_ zero on the hypervisor side
+ * after the successful RNDIS initialization, which breaks
+ * the assumption of any following code (well, it breaks the
+ *