Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142009956
D8295.id21524.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D8295.id21524.diff
View Options
Index: sys/dev/hyperv/netvsc/hv_net_vsc.h
===================================================================
--- sys/dev/hyperv/netvsc/hv_net_vsc.h
+++ sys/dev/hyperv/netvsc/hv_net_vsc.h
@@ -207,7 +207,6 @@
struct ifnet *hn_ifp;
struct ifmedia hn_media;
device_t hn_dev;
- int hn_carrier;
int hn_if_flags;
struct sx hn_lock;
struct vmbus_channel *hn_prichan;
@@ -236,6 +235,9 @@
struct taskqueue *hn_mgmt_taskq;
struct taskqueue *hn_mgmt_taskq0;
struct task hn_link_task;
+ struct task hn_netchg_init;
+ struct timeout_task hn_netchg_status;
+ uint32_t hn_link_flags; /* HN_LINK_FLAG_ */
uint32_t hn_caps; /* HN_CAP_ */
uint32_t hn_flags; /* HN_FLAG_ */
@@ -271,6 +273,9 @@
#define HN_CAP_TSO6 0x0100
#define HN_CAP_HASHVAL 0x0200
+#define HN_LINK_FLAG_LINKUP 0x0001
+#define HN_LINK_FLAG_NETCHG 0x0002
+
/*
* Externs
*/
Index: sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
===================================================================
--- sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
+++ sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
@@ -335,6 +335,8 @@
static void hn_start_taskfunc(void *, int);
static void hn_start_txeof_taskfunc(void *, int);
static void hn_link_taskfunc(void *, int);
+static void hn_netchg_init_taskfunc(void *, int);
+static void hn_netchg_status_taskfunc(void *, int);
static void hn_suspend_mgmt_taskfunc(void *, int);
static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
static int hn_create_rx_data(struct hn_softc *sc, int);
@@ -360,6 +362,7 @@
static void hn_tx_resume(struct hn_softc *, int);
static void hn_tx_ring_qflush(struct hn_tx_ring *);
static int netvsc_detach(device_t dev);
+static void hn_link_status(struct hn_softc *);
static void hn_nvs_handle_notify(struct hn_softc *sc,
const struct vmbus_chanpkt_hdr *pkt);
@@ -482,7 +485,7 @@
ifmr->ifm_status = IFM_AVALID;
ifmr->ifm_active = IFM_ETHER;
- if (!sc->hn_carrier) {
+ if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) {
ifmr->ifm_active |= IFM_NONE;
return;
}
@@ -563,6 +566,9 @@
taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
device_get_nameunit(dev));
TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
+ TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc);
+ TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0,
+ hn_netchg_status_taskfunc, sc);
/*
* Allocate ifnet and setup its name earlier, so that if_printf
@@ -808,10 +814,8 @@
}
static void
-hn_link_taskfunc(void *xsc, int pending __unused)
+hn_link_status(struct hn_softc *sc)
{
- struct hn_softc *sc = xsc;
- struct ifnet *ifp = sc->hn_ifp;
uint32_t link_status;
int error;
@@ -822,11 +826,51 @@
}
if (link_status == NDIS_MEDIA_STATE_CONNECTED)
- sc->hn_carrier = 1;
+ sc->hn_link_flags |= HN_LINK_FLAG_LINKUP;
else
- sc->hn_carrier = 0;
- if_link_state_change(ifp,
- sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
+ sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+ if_link_state_change(sc->hn_ifp,
+ (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ?
+ LINK_STATE_UP : LINK_STATE_DOWN);
+}
+
+static void
+hn_link_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG)
+ return;
+ hn_link_status(sc);
+}
+
+static void
+hn_netchg_init_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ /* Prevent any link status checks from running. */
+ sc->hn_link_flags |= HN_LINK_FLAG_NETCHG;
+
+ /*
+ * Fake up a [link down --> link up] state change; 5 seconds
+ * delay is used, which closely simulates miibus reaction
+ * upon link down event.
+ */
+ sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP;
+ if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN);
+ taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0,
+ &sc->hn_netchg_status, 5 * hz);
+}
+
+static void
+hn_netchg_status_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+
+ /* Re-allow link status checks. */
+ sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG;
+ hn_link_status(sc);
}
void
@@ -837,6 +881,14 @@
taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
}
+void
+hn_network_change(struct hn_softc *sc)
+{
+
+ if (sc->hn_mgmt_taskq != NULL)
+ taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init);
+}
+
static __inline int
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@@ -3718,6 +3770,8 @@
/*
* Make sure that all pending management tasks are completed.
*/
+ taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init);
+ taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status);
taskqueue_drain_all(sc->hn_mgmt_taskq0);
}
@@ -3795,10 +3849,11 @@
{
/*
- * Kick off link status check.
+ * Kick off network change detection, which will
+ * do link status check too.
*/
sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
- hn_link_status_update(sc);
+ hn_network_change(sc);
}
static void
Index: sys/dev/hyperv/netvsc/hv_rndis_filter.c
===================================================================
--- sys/dev/hyperv/netvsc/hv_rndis_filter.c
+++ sys/dev/hyperv/netvsc/hv_rndis_filter.c
@@ -158,6 +158,7 @@
hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
{
const struct rndis_status_msg *msg;
+ int ofs;
if (dlen < sizeof(*msg)) {
if_printf(sc->hn_ifp, "invalid RNDIS status\n");
@@ -176,8 +177,19 @@
break;
case RNDIS_STATUS_NETWORK_CHANGE:
- /* TODO */
- if_printf(sc->hn_ifp, "network changed\n");
+ ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset);
+ if (dlen < ofs + msg->rm_stbuflen ||
+ msg->rm_stbuflen < sizeof(uint32_t)) {
+ if_printf(sc->hn_ifp, "network changed\n");
+ } else {
+ uint32_t change;
+
+ memcpy(&change, ((const uint8_t *)msg) + ofs,
+ sizeof(change));
+ if_printf(sc->hn_ifp, "network changed, change %u\n",
+ change);
+ }
+ hn_network_change(sc);
break;
default:
Index: sys/dev/hyperv/netvsc/if_hnvar.h
===================================================================
--- sys/dev/hyperv/netvsc/if_hnvar.h
+++ sys/dev/hyperv/netvsc/if_hnvar.h
@@ -139,6 +139,7 @@
const struct hn_recvinfo *info);
void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
void hn_link_status_update(struct hn_softc *sc);
+void hn_network_change(struct hn_softc *sc);
extern struct hn_send_ctx hn_send_ctx_none;
Index: sys/dev/hyperv/netvsc/ndis.h
===================================================================
--- sys/dev/hyperv/netvsc/ndis.h
+++ sys/dev/hyperv/netvsc/ndis.h
@@ -32,6 +32,10 @@
#define NDIS_MEDIA_STATE_CONNECTED 0
#define NDIS_MEDIA_STATE_DISCONNECTED 1
+#define NDIS_NETCHANGE_TYPE_POSSIBLE 1
+#define NDIS_NETCHANGE_TYPE_DEFINITE 2
+#define NDIS_NETCHANGE_TYPE_FROMMEDIA 3
+
#define NDIS_OFFLOAD_SET_NOCHG 0
#define NDIS_OFFLOAD_SET_ON 1
#define NDIS_OFFLOAD_SET_OFF 2
Index: sys/net/rndis.h
===================================================================
--- sys/net/rndis.h
+++ sys/net/rndis.h
@@ -320,6 +320,10 @@
/* rndis_diag_info */
};
+/* stbuf offset from the beginning of rndis_status_msg. */
+#define RNDIS_STBUFOFFSET_ABS(ofs) \
+ ((ofs) + __offsetof(struct rndis_status_msg, rm_status))
+
/*
* Immediately after rndis_status_msg.rm_stbufoffset, if a control
* message is malformatted, or a packet message contains inappropriate
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 15, 9:14 PM (19 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27654877
Default Alt Text
D8295.id21524.diff (7 KB)
Attached To
Mode
D8295: hyperv/hn: Add network change support.
Attached
Detach File
Event Timeline
Log In to Comment