xref: /openbsd/sys/dev/pv/if_hvn.c (revision 5dea098c)
1 /*-
2  * Copyright (c) 2009-2012,2016 Microsoft Corp.
3  * Copyright (c) 2010-2012 Citrix Inc.
4  * Copyright (c) 2012 NetApp Inc.
5  * Copyright (c) 2016 Mike Belopuhov <mike@esdenera.com>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice unmodified, this list of conditions, and the following
13  *    disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /*
31  * The OpenBSD port was done under funding by Esdenera Networks GmbH.
32  */
33 
34 #include "bpfilter.h"
35 #include "vlan.h"
36 #include "hyperv.h"
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/atomic.h>
41 #include <sys/device.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/pool.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/task.h>
50 #include <sys/timeout.h>
51 
52 #include <machine/bus.h>
53 
54 #include <uvm/uvm_extern.h>
55 
56 #include <dev/pv/hypervreg.h>
57 #include <dev/pv/hypervvar.h>
58 
59 #include <dev/rndis.h>
60 #include <dev/pv/ndis.h>
61 #include <dev/pv/if_hvnreg.h>
62 
63 #include <net/if.h>
64 #include <net/if_media.h>
65 
66 #include <netinet/in.h>
67 #include <netinet/if_ether.h>
68 
69 #ifdef INET6
70 #include <netinet/ip6.h>
71 #endif
72 
73 #if NBPFILTER > 0
74 #include <net/bpf.h>
75 #endif
76 
77 #define HVN_NVS_MSGSIZE			32
78 #define HVN_NVS_BUFSIZE			PAGE_SIZE
79 
80 /*
81  * RNDIS control interface
82  */
83 #define HVN_RNDIS_CTLREQS		4
84 #define HVN_RNDIS_BUFSIZE		512
85 
86 struct rndis_cmd {
87 	uint32_t			 rc_id;
88 	struct hvn_nvs_rndis		 rc_msg;
89 	void				*rc_req;
90 	bus_dmamap_t			 rc_dmap;
91 	bus_dma_segment_t		 rc_segs;
92 	int				 rc_nsegs;
93 	uint64_t			 rc_gpa;
94 	struct rndis_packet_msg		 rc_cmp;
95 	uint32_t			 rc_cmplen;
96 	uint8_t				 rc_cmpbuf[HVN_RNDIS_BUFSIZE];
97 	int				 rc_done;
98 	TAILQ_ENTRY(rndis_cmd)		 rc_entry;
99 };
100 TAILQ_HEAD(rndis_queue, rndis_cmd);
101 
102 #define HVN_MAXMTU			(9 * 1024)
103 
104 #define HVN_RNDIS_XFER_SIZE		2048
105 
106 /*
107  * Tx ring
108  */
109 #define HVN_TX_DESC			256
110 #define HVN_TX_FRAGS			15		/* 31 is the max */
111 #define HVN_TX_FRAG_SIZE		PAGE_SIZE
112 #define HVN_TX_PKT_SIZE			16384
113 
114 #define HVN_RNDIS_PKT_LEN					\
115 	(sizeof(struct rndis_packet_msg) +			\
116 	 sizeof(struct rndis_pktinfo) + NDIS_VLAN_INFO_SIZE +	\
117 	 sizeof(struct rndis_pktinfo) + NDIS_TXCSUM_INFO_SIZE)
118 
119 struct hvn_tx_desc {
120 	uint32_t			 txd_id;
121 	int				 txd_ready;
122 	struct vmbus_gpa		 txd_sgl[HVN_TX_FRAGS + 1];
123 	int				 txd_nsge;
124 	struct mbuf			*txd_buf;
125 	bus_dmamap_t			 txd_dmap;
126 	struct vmbus_gpa		 txd_gpa;
127 	struct rndis_packet_msg		*txd_req;
128 };
129 
130 struct hvn_softc {
131 	struct device			 sc_dev;
132 	struct hv_softc			*sc_hvsc;
133 	struct hv_channel		*sc_chan;
134 	bus_dma_tag_t			 sc_dmat;
135 
136 	struct arpcom			 sc_ac;
137 	struct ifmedia			 sc_media;
138 	int				 sc_link_state;
139 
140 	/* NVS protocol */
141 	int				 sc_proto;
142 	uint32_t			 sc_nvstid;
143 	uint8_t				 sc_nvsrsp[HVN_NVS_MSGSIZE];
144 	uint8_t				*sc_nvsbuf;
145 	int				 sc_nvsdone;
146 
147 	/* RNDIS protocol */
148 	int				 sc_ndisver;
149 	uint32_t			 sc_rndisrid;
150 	struct rndis_queue		 sc_cntl_sq; /* submission queue */
151 	struct mutex			 sc_cntl_sqlck;
152 	struct rndis_queue		 sc_cntl_cq; /* completion queue */
153 	struct mutex			 sc_cntl_cqlck;
154 	struct rndis_queue		 sc_cntl_fq; /* free queue */
155 	struct mutex			 sc_cntl_fqlck;
156 	struct rndis_cmd		 sc_cntl_msgs[HVN_RNDIS_CTLREQS];
157 	struct hvn_nvs_rndis		 sc_data_msg;
158 
159 	/* Rx ring */
160 	void				*sc_rx_ring;
161 	int				 sc_rx_size;
162 	uint32_t			 sc_rx_hndl;
163 
164 	/* Tx ring */
165 	uint32_t			 sc_tx_next;
166 	uint32_t			 sc_tx_avail;
167 	struct hvn_tx_desc		 sc_tx_desc[HVN_TX_DESC];
168 	bus_dmamap_t			 sc_tx_rmap;
169 	void				*sc_tx_msgs;
170 	bus_dma_segment_t		 sc_tx_mseg;
171 };
172 
173 int	hvn_match(struct device *, void *, void *);
174 void	hvn_attach(struct device *, struct device *, void *);
175 int	hvn_ioctl(struct ifnet *, u_long, caddr_t);
176 int	hvn_media_change(struct ifnet *);
177 void	hvn_media_status(struct ifnet *, struct ifmediareq *);
178 int	hvn_iff(struct hvn_softc *);
179 void	hvn_init(struct hvn_softc *);
180 void	hvn_stop(struct hvn_softc *);
181 void	hvn_start(struct ifqueue *);
182 int	hvn_encap(struct hvn_softc *, struct mbuf *, struct hvn_tx_desc **);
183 void	hvn_decap(struct hvn_softc *, struct hvn_tx_desc *);
184 void	hvn_txeof(struct hvn_softc *, uint64_t);
185 int	hvn_rx_ring_create(struct hvn_softc *);
186 int	hvn_rx_ring_destroy(struct hvn_softc *);
187 int	hvn_tx_ring_create(struct hvn_softc *);
188 void	hvn_tx_ring_destroy(struct hvn_softc *);
189 int	hvn_set_capabilities(struct hvn_softc *);
190 int	hvn_get_lladdr(struct hvn_softc *);
191 int	hvn_set_lladdr(struct hvn_softc *);
192 void	hvn_get_link_status(struct hvn_softc *);
193 void	hvn_link_status(struct hvn_softc *);
194 
195 /* NSVP */
196 int	hvn_nvs_attach(struct hvn_softc *);
197 void	hvn_nvs_intr(void *);
198 int	hvn_nvs_cmd(struct hvn_softc *, void *, size_t, uint64_t, int);
199 int	hvn_nvs_ack(struct hvn_softc *, uint64_t);
200 void	hvn_nvs_detach(struct hvn_softc *);
201 
202 /* RNDIS */
203 int	hvn_rndis_attach(struct hvn_softc *);
204 int	hvn_rndis_cmd(struct hvn_softc *, struct rndis_cmd *, int);
205 void	hvn_rndis_input(struct hvn_softc *, uint64_t, void *);
206 void	hvn_rxeof(struct hvn_softc *, caddr_t, uint32_t, struct mbuf_list *);
207 void	hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t);
208 int	hvn_rndis_output(struct hvn_softc *, struct hvn_tx_desc *);
209 void	hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t);
210 int	hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *);
211 int	hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t);
212 int	hvn_rndis_close(struct hvn_softc *);
213 void	hvn_rndis_detach(struct hvn_softc *);
214 
215 struct cfdriver hvn_cd = {
216 	NULL, "hvn", DV_IFNET
217 };
218 
219 const struct cfattach hvn_ca = {
220 	sizeof(struct hvn_softc), hvn_match, hvn_attach
221 };
222 
223 int
224 hvn_match(struct device *parent, void *match, void *aux)
225 {
226 	struct hv_attach_args *aa = aux;
227 
228 	if (strcmp("network", aa->aa_ident))
229 		return (0);
230 
231 	return (1);
232 }
233 
234 void
235 hvn_attach(struct device *parent, struct device *self, void *aux)
236 {
237 	struct hv_attach_args *aa = aux;
238 	struct hvn_softc *sc = (struct hvn_softc *)self;
239 	struct ifnet *ifp = &sc->sc_ac.ac_if;
240 
241 	sc->sc_hvsc = (struct hv_softc *)parent;
242 	sc->sc_chan = aa->aa_chan;
243 	sc->sc_dmat = aa->aa_dmat;
244 
245 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
246 
247 	printf(" channel %u", sc->sc_chan->ch_id);
248 
249 	if (hvn_nvs_attach(sc)) {
250 		printf(": failed to init NVSP\n");
251 		return;
252 	}
253 
254 	if (hvn_rx_ring_create(sc)) {
255 		printf(": failed to create Rx ring\n");
256 		goto detach;
257 	}
258 
259 	if (hvn_tx_ring_create(sc)) {
260 		printf(": failed to create Tx ring\n");
261 		goto detach;
262 	}
263 
264 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
265 	ifp->if_xflags = IFXF_MPSAFE;
266 	ifp->if_ioctl = hvn_ioctl;
267 	ifp->if_qstart = hvn_start;
268 	ifp->if_softc = sc;
269 
270 	ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
271 	    IFCAP_CSUM_TCPv6;
272 	if (sc->sc_ndisver > NDIS_VERSION_6_30)
273 		ifp->if_capabilities |= IFCAP_CSUM_UDPv4 | IFCAP_CSUM_UDPv6;
274 
275 	if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
276 		ifp->if_hardmtu = HVN_MAXMTU;
277 #if NVLAN > 0
278 		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
279 #endif
280 	}
281 
282 	ifq_init_maxlen(&ifp->if_snd, HVN_TX_DESC - 1);
283 
284 	ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
285 	    hvn_media_status);
286 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
287 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
288 
289 	if_attach(ifp);
290 
291 	if (hvn_rndis_attach(sc)) {
292 		printf(": failed to init RNDIS\n");
293 		goto detach;
294 	}
295 
296 	printf(": NVS %d.%d NDIS %d.%d", sc->sc_proto >> 16,
297 	    sc->sc_proto & 0xffff, sc->sc_ndisver >> 16 ,
298 	    sc->sc_ndisver & 0xffff);
299 
300 	if (hvn_set_capabilities(sc)) {
301 		printf(": failed to setup offloading\n");
302 		hvn_rndis_detach(sc);
303 		goto detach;
304 	}
305 
306 	if (hvn_get_lladdr(sc)) {
307 		printf(": failed to obtain an ethernet address\n");
308 		hvn_rndis_detach(sc);
309 		goto detach;
310 	}
311 
312 	printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
313 
314 	ether_ifattach(ifp);
315 	return;
316 
317  detach:
318 	hvn_rx_ring_destroy(sc);
319 	hvn_tx_ring_destroy(sc);
320 	hvn_nvs_detach(sc);
321 	if (ifp->if_qstart)
322 		if_detach(ifp);
323 }
324 
325 int
326 hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
327 {
328 	struct hvn_softc *sc = ifp->if_softc;
329 	struct ifreq *ifr = (struct ifreq *)data;
330 	int s, error = 0;
331 
332 	s = splnet();
333 
334 	switch (command) {
335 	case SIOCSIFADDR:
336 		ifp->if_flags |= IFF_UP;
337 		if (!(ifp->if_flags & IFF_RUNNING))
338 			hvn_init(sc);
339 		break;
340 	case SIOCSIFFLAGS:
341 		if (ifp->if_flags & IFF_UP) {
342 			if (ifp->if_flags & IFF_RUNNING)
343 				error = ENETRESET;
344 			else
345 				hvn_init(sc);
346 		} else {
347 			if (ifp->if_flags & IFF_RUNNING)
348 				hvn_stop(sc);
349 		}
350 		break;
351 	case SIOCGIFMEDIA:
352 	case SIOCSIFMEDIA:
353 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
354 		break;
355 	default:
356 		error = ether_ioctl(ifp, &sc->sc_ac, command, data);
357 	}
358 
359 	if (error == ENETRESET) {
360 		if (ifp->if_flags & IFF_RUNNING)
361 			hvn_iff(sc);
362 		error = 0;
363 	}
364 
365 	splx(s);
366 
367 	return (error);
368 }
369 
370 int
371 hvn_media_change(struct ifnet *ifp)
372 {
373 	return (0);
374 }
375 
376 void
377 hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
378 {
379 	struct hvn_softc *sc = ifp->if_softc;
380 
381 	hvn_get_link_status(sc);
382 	hvn_link_status(sc);
383 
384 	ifmr->ifm_status = IFM_AVALID;
385 	ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
386 	if (sc->sc_link_state == LINK_STATE_UP)
387 		ifmr->ifm_status |= IFM_ACTIVE;
388 }
389 
390 void
391 hvn_link_status(struct hvn_softc *sc)
392 {
393 	struct ifnet *ifp = &sc->sc_ac.ac_if;
394 
395 	if (sc->sc_link_state != ifp->if_link_state) {
396 		ifp->if_link_state = sc->sc_link_state;
397 		if_link_state_change(ifp);
398 	}
399 }
400 
401 int
402 hvn_iff(struct hvn_softc *sc)
403 {
404 	struct ifnet *ifp = &sc->sc_ac.ac_if;
405 	uint32_t filter = 0;
406 	int rv;
407 
408 	ifp->if_flags &= ~IFF_ALLMULTI;
409 
410 	if ((ifp->if_flags & IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) {
411 		ifp->if_flags |= IFF_ALLMULTI;
412 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
413 	} else {
414 		filter = NDIS_PACKET_TYPE_BROADCAST |
415 		    NDIS_PACKET_TYPE_DIRECTED;
416 		if (sc->sc_ac.ac_multicnt > 0) {
417 			ifp->if_flags |= IFF_ALLMULTI;
418 			filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
419 		}
420 	}
421 
422 	rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
423 	    &filter, sizeof(filter));
424 	if (rv)
425 		DPRINTF("%s: failed to set RNDIS filter to %#x\n",
426 		    sc->sc_dev.dv_xname, filter);
427 	return (rv);
428 }
429 
430 void
431 hvn_init(struct hvn_softc *sc)
432 {
433 	struct ifnet *ifp = &sc->sc_ac.ac_if;
434 
435 	hvn_stop(sc);
436 
437 	if (hvn_iff(sc) == 0) {
438 		ifp->if_flags |= IFF_RUNNING;
439 		ifq_clr_oactive(&ifp->if_snd);
440 	}
441 }
442 
443 void
444 hvn_stop(struct hvn_softc *sc)
445 {
446 	struct ifnet *ifp = &sc->sc_ac.ac_if;
447 
448 	if (ifp->if_flags & IFF_RUNNING) {
449 		ifp->if_flags &= ~IFF_RUNNING;
450 		hvn_rndis_close(sc);
451 	}
452 
453 	ifq_barrier(&ifp->if_snd);
454 	sched_barrier(NULL);
455 
456 	ifq_clr_oactive(&ifp->if_snd);
457 }
458 
459 void
460 hvn_start(struct ifqueue *ifq)
461 {
462 	struct ifnet *ifp = ifq->ifq_if;
463 	struct hvn_softc *sc = ifp->if_softc;
464 	struct hvn_tx_desc *txd;
465 	struct mbuf *m;
466 
467 	for (;;) {
468 		if (!sc->sc_tx_avail) {
469 			/* transient */
470 			ifq_set_oactive(ifq);
471 			break;
472 		}
473 
474 		m = ifq_dequeue(ifq);
475 		if (m == NULL)
476 			break;
477 
478 		if (hvn_encap(sc, m, &txd)) {
479 			/* the chain is too large */
480 			ifp->if_oerrors++;
481 			m_freem(m);
482 			continue;
483 		}
484 
485 #if NBPFILTER > 0
486 		if (ifp->if_bpf)
487 			bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
488 #endif
489 
490 		if (hvn_rndis_output(sc, txd)) {
491 			hvn_decap(sc, txd);
492 			ifp->if_oerrors++;
493 			m_freem(m);
494 			continue;
495 		}
496 
497 		sc->sc_tx_next++;
498 	}
499 }
500 
501 static inline char *
502 hvn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
503     size_t datalen, uint32_t type)
504 {
505 	struct rndis_pktinfo *pi;
506 	size_t pi_size = sizeof(*pi) + datalen;
507 	char *cp;
508 
509 	KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <=
510 	    pktsize);
511 
512 	cp = (char *)pkt + pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
513 	pi = (struct rndis_pktinfo *)cp;
514 	pi->rm_size = pi_size;
515 	pi->rm_type = type;
516 	pi->rm_pktinfooffset = sizeof(*pi);
517 	pkt->rm_pktinfolen += pi_size;
518 	pkt->rm_dataoffset += pi_size;
519 	pkt->rm_len += pi_size;
520 	return ((char *)pi->rm_data);
521 }
522 
523 int
524 hvn_encap(struct hvn_softc *sc, struct mbuf *m, struct hvn_tx_desc **txd0)
525 {
526 	struct hvn_tx_desc *txd;
527 	struct rndis_packet_msg *pkt;
528 	bus_dma_segment_t *seg;
529 	size_t pktlen;
530 	int i, rv;
531 
532 	do {
533 		txd = &sc->sc_tx_desc[sc->sc_tx_next % HVN_TX_DESC];
534 		sc->sc_tx_next++;
535 	} while (!txd->txd_ready);
536 	txd->txd_ready = 0;
537 
538 	pkt = txd->txd_req;
539 	memset(pkt, 0, HVN_RNDIS_PKT_LEN);
540 	pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
541 	pkt->rm_len = sizeof(*pkt) + m->m_pkthdr.len;
542 	pkt->rm_dataoffset = RNDIS_DATA_OFFSET;
543 	pkt->rm_datalen = m->m_pkthdr.len;
544 	pkt->rm_pktinfooffset = sizeof(*pkt); /* adjusted below */
545 	pkt->rm_pktinfolen = 0;
546 
547 	rv = bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, BUS_DMA_READ |
548 	    BUS_DMA_NOWAIT);
549 	switch (rv) {
550 	case 0:
551 		break;
552 	case EFBIG:
553 		if (m_defrag(m, M_NOWAIT) == 0 &&
554 		    bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m,
555 		    BUS_DMA_READ | BUS_DMA_NOWAIT) == 0)
556 			break;
557 		/* FALLTHROUGH */
558 	default:
559 		DPRINTF("%s: failed to load mbuf\n", sc->sc_dev.dv_xname);
560 		return (-1);
561 	}
562 	txd->txd_buf = m;
563 
564 #if NVLAN > 0
565 	if (m->m_flags & M_VLANTAG) {
566 		uint32_t vlan;
567 		char *cp;
568 
569 		vlan = NDIS_VLAN_INFO(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag),
570 		    EVL_PRIOFTAG(m->m_pkthdr.ether_vtag));
571 		cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
572 		    NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
573 		memcpy(cp, &vlan, NDIS_VLAN_INFO_SIZE);
574 	}
575 #endif
576 
577 	if (m->m_pkthdr.csum_flags & (M_IPV4_CSUM_OUT | M_UDP_CSUM_OUT |
578 	    M_TCP_CSUM_OUT)) {
579 		uint32_t csum = NDIS_TXCSUM_INFO_IPV4;
580 		char *cp;
581 
582 		if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
583 			csum |= NDIS_TXCSUM_INFO_IPCS;
584 		if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
585 			csum |= NDIS_TXCSUM_INFO_TCPCS;
586 		if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
587 			csum |= NDIS_TXCSUM_INFO_UDPCS;
588 		cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
589 		    NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
590 		memcpy(cp, &csum, NDIS_TXCSUM_INFO_SIZE);
591 	}
592 
593 	pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
594 	pkt->rm_pktinfooffset -= RNDIS_HEADER_OFFSET;
595 
596 	/* Attach an RNDIS message to the first slot */
597 	txd->txd_sgl[0].gpa_page = txd->txd_gpa.gpa_page;
598 	txd->txd_sgl[0].gpa_ofs = txd->txd_gpa.gpa_ofs;
599 	txd->txd_sgl[0].gpa_len = pktlen;
600 	txd->txd_nsge = txd->txd_dmap->dm_nsegs + 1;
601 
602 	for (i = 0; i < txd->txd_dmap->dm_nsegs; i++) {
603 		seg = &txd->txd_dmap->dm_segs[i];
604 		txd->txd_sgl[1 + i].gpa_page = atop(seg->ds_addr);
605 		txd->txd_sgl[1 + i].gpa_ofs = seg->ds_addr & PAGE_MASK;
606 		txd->txd_sgl[1 + i].gpa_len = seg->ds_len;
607 	}
608 
609 	*txd0 = txd;
610 
611 	atomic_dec_int(&sc->sc_tx_avail);
612 
613 	return (0);
614 }
615 
616 void
617 hvn_decap(struct hvn_softc *sc, struct hvn_tx_desc *txd)
618 {
619 	bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
620 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
621 	bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
622 	txd->txd_buf = NULL;
623 	txd->txd_nsge = 0;
624 	txd->txd_ready = 1;
625 	atomic_inc_int(&sc->sc_tx_avail);
626 }
627 
628 void
629 hvn_txeof(struct hvn_softc *sc, uint64_t tid)
630 {
631 	struct hvn_tx_desc *txd;
632 	struct mbuf *m;
633 	uint32_t id = tid >> 32;
634 
635 	if ((tid & 0xffffffffU) != 0)
636 		return;
637 	id -= HVN_NVS_CHIM_SIG;
638 	if (id >= HVN_TX_DESC)
639 		panic("tx packet index too large: %u", id);
640 
641 	txd = &sc->sc_tx_desc[id];
642 
643 	if ((m = txd->txd_buf) == NULL)
644 		panic("%s: no mbuf @%u", sc->sc_dev.dv_xname, id);
645 	txd->txd_buf = NULL;
646 
647 	bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
648 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
649 	bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
650 	m_freem(m);
651 
652 	txd->txd_ready = 1;
653 
654 	atomic_inc_int(&sc->sc_tx_avail);
655 
656 }
657 
658 int
659 hvn_rx_ring_create(struct hvn_softc *sc)
660 {
661 	struct hvn_nvs_rxbuf_conn cmd;
662 	struct hvn_nvs_rxbuf_conn_resp *rsp;
663 	uint64_t tid;
664 
665 	if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2)
666 		sc->sc_rx_size = 15 * 1024 * 1024;	/* 15MB */
667 	else
668 		sc->sc_rx_size = 16 * 1024 * 1024; 	/* 16MB */
669 	sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
670 	    cold ? &kd_nowait : &kd_waitok);
671 	if (sc->sc_rx_ring == NULL) {
672 		DPRINTF("%s: failed to allocate Rx ring buffer\n",
673 		    sc->sc_dev.dv_xname);
674 		return (-1);
675 	}
676 	if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
677 	    &sc->sc_rx_hndl)) {
678 		DPRINTF("%s: failed to obtain a PA handle\n",
679 		    sc->sc_dev.dv_xname);
680 		goto errout;
681 	}
682 
683 	memset(&cmd, 0, sizeof(cmd));
684 	cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN;
685 	cmd.nvs_gpadl = sc->sc_rx_hndl;
686 	cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
687 
688 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
689 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
690 		goto errout;
691 
692 	rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp;
693 	if (rsp->nvs_status != HVN_NVS_STATUS_OK) {
694 		DPRINTF("%s: failed to set up the Rx ring\n",
695 		    sc->sc_dev.dv_xname);
696 		goto errout;
697 	}
698 	if (rsp->nvs_nsect > 1) {
699 		DPRINTF("%s: invalid number of Rx ring sections: %u\n",
700 		    sc->sc_dev.dv_xname, rsp->nvs_nsect);
701 		hvn_rx_ring_destroy(sc);
702 		return (-1);
703 	}
704 	return (0);
705 
706  errout:
707 	if (sc->sc_rx_hndl) {
708 		hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
709 		sc->sc_rx_hndl = 0;
710 	}
711 	if (sc->sc_rx_ring) {
712 		km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
713 		sc->sc_rx_ring = NULL;
714 	}
715 	return (-1);
716 }
717 
718 int
719 hvn_rx_ring_destroy(struct hvn_softc *sc)
720 {
721 	struct hvn_nvs_rxbuf_disconn cmd;
722 	uint64_t tid;
723 
724 	if (sc->sc_rx_ring == NULL)
725 		return (0);
726 
727 	memset(&cmd, 0, sizeof(cmd));
728 	cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN;
729 	cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
730 
731 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
732 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
733 		return (-1);
734 
735 	delay(100);
736 
737 	hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
738 
739 	sc->sc_rx_hndl = 0;
740 
741 	km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
742 	sc->sc_rx_ring = NULL;
743 
744 	return (0);
745 }
746 
747 int
748 hvn_tx_ring_create(struct hvn_softc *sc)
749 {
750 	struct hvn_tx_desc *txd;
751 	bus_dma_segment_t *seg;
752 	size_t msgsize;
753 	int i, rsegs;
754 	paddr_t pa;
755 
756 	msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
757 
758 	/* Allocate memory to store RNDIS messages */
759 	if (bus_dmamem_alloc(sc->sc_dmat, msgsize * HVN_TX_DESC, PAGE_SIZE, 0,
760 	    &sc->sc_tx_mseg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) {
761 		DPRINTF("%s: failed to allocate memory for RDNIS messages\n",
762 		    sc->sc_dev.dv_xname);
763 		goto errout;
764 	}
765 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_mseg, 1, msgsize *
766 	    HVN_TX_DESC, (caddr_t *)&sc->sc_tx_msgs, BUS_DMA_WAITOK)) {
767 		DPRINTF("%s: failed to establish mapping for RDNIS messages\n",
768 		    sc->sc_dev.dv_xname);
769 		goto errout;
770 	}
771 	if (bus_dmamap_create(sc->sc_dmat, msgsize * HVN_TX_DESC, 1,
772 	    msgsize * HVN_TX_DESC, 0, BUS_DMA_WAITOK, &sc->sc_tx_rmap)) {
773 		DPRINTF("%s: failed to create map for RDNIS messages\n",
774 		    sc->sc_dev.dv_xname);
775 		goto errout;
776 	}
777 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_msgs,
778 	    msgsize * HVN_TX_DESC, NULL, BUS_DMA_WAITOK)) {
779 		DPRINTF("%s: failed to create map for RDNIS messages\n",
780 		    sc->sc_dev.dv_xname);
781 		goto errout;
782 	}
783 
784 	for (i = 0; i < HVN_TX_DESC; i++) {
785 		txd = &sc->sc_tx_desc[i];
786 		if (bus_dmamap_create(sc->sc_dmat, HVN_TX_PKT_SIZE,
787 		    HVN_TX_FRAGS, HVN_TX_FRAG_SIZE, PAGE_SIZE,
788 		    BUS_DMA_WAITOK, &txd->txd_dmap)) {
789 			DPRINTF("%s: failed to create map for TX descriptors\n",
790 			    sc->sc_dev.dv_xname);
791 			goto errout;
792 		}
793 		seg = &sc->sc_tx_rmap->dm_segs[0];
794 		pa = seg->ds_addr + (msgsize * i);
795 		txd->txd_gpa.gpa_page = atop(pa);
796 		txd->txd_gpa.gpa_ofs = pa & PAGE_MASK;
797 		txd->txd_gpa.gpa_len = msgsize;
798 		txd->txd_req = (void *)((caddr_t)sc->sc_tx_msgs +
799 		    (msgsize * i));
800 		txd->txd_id = i + HVN_NVS_CHIM_SIG;
801 		txd->txd_ready = 1;
802 	}
803 	sc->sc_tx_avail = HVN_TX_DESC;
804 
805 	return (0);
806 
807  errout:
808 	hvn_tx_ring_destroy(sc);
809 	return (-1);
810 }
811 
812 void
813 hvn_tx_ring_destroy(struct hvn_softc *sc)
814 {
815 	struct hvn_tx_desc *txd;
816 	int i;
817 
818 	for (i = 0; i < HVN_TX_DESC; i++) {
819 		txd = &sc->sc_tx_desc[i];
820 		if (txd->txd_dmap == NULL)
821 			continue;
822 		bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
823 		    BUS_DMASYNC_POSTWRITE);
824 		bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
825 		bus_dmamap_destroy(sc->sc_dmat, txd->txd_dmap);
826 		txd->txd_dmap = NULL;
827 		if (txd->txd_buf == NULL)
828 			continue;
829 		m_free(txd->txd_buf);
830 		txd->txd_buf = NULL;
831 	}
832 	if (sc->sc_tx_rmap) {
833 		bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,
834 		    BUS_DMASYNC_POSTWRITE);
835 		bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
836 		bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
837 	}
838 	if (sc->sc_tx_msgs) {
839 		size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
840 
841 		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_msgs,
842 		    msgsize * HVN_TX_DESC);
843 		bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1);
844 	}
845 	sc->sc_tx_rmap = NULL;
846 	sc->sc_tx_msgs = NULL;
847 }
848 
849 int
850 hvn_get_lladdr(struct hvn_softc *sc)
851 {
852 	char enaddr[ETHER_ADDR_LEN];
853 	size_t addrlen = ETHER_ADDR_LEN;
854 	int rv;
855 
856 	rv = hvn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS,
857 	    enaddr, &addrlen);
858 	if (rv == 0 && addrlen == ETHER_ADDR_LEN)
859 		memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
860 	return (rv);
861 }
862 
863 int
864 hvn_set_lladdr(struct hvn_softc *sc)
865 {
866 	return (hvn_rndis_set(sc, OID_802_3_CURRENT_ADDRESS,
867 	    sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
868 }
869 
870 void
871 hvn_get_link_status(struct hvn_softc *sc)
872 {
873 	uint32_t state;
874 	size_t len = sizeof(state);
875 
876 	if (hvn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS,
877 	    &state, &len) == 0)
878 		sc->sc_link_state = (state == NDIS_MEDIA_STATE_CONNECTED) ?
879 		    LINK_STATE_UP : LINK_STATE_DOWN;
880 }
881 
882 int
883 hvn_nvs_attach(struct hvn_softc *sc)
884 {
885 	const uint32_t protos[] = {
886 		HVN_NVS_PROTO_VERSION_5, HVN_NVS_PROTO_VERSION_4,
887 		HVN_NVS_PROTO_VERSION_2, HVN_NVS_PROTO_VERSION_1
888 	};
889 	struct hvn_nvs_init cmd;
890 	struct hvn_nvs_init_resp *rsp;
891 	struct hvn_nvs_ndis_init ncmd;
892 	struct hvn_nvs_ndis_conf ccmd;
893 	uint32_t ndisver, ringsize;
894 	uint64_t tid;
895 	int i;
896 
897 	sc->sc_nvsbuf = malloc(HVN_NVS_BUFSIZE, M_DEVBUF, M_ZERO |
898 	    (cold ? M_NOWAIT : M_WAITOK));
899 	if (sc->sc_nvsbuf == NULL) {
900 		DPRINTF("%s: failed to allocate channel data buffer\n",
901 		    sc->sc_dev.dv_xname);
902 		return (-1);
903 	}
904 
905 	/* We need to be able to fit all RNDIS control and data messages */
906 	ringsize = HVN_RNDIS_CTLREQS *
907 	    (sizeof(struct hvn_nvs_rndis) + sizeof(struct vmbus_gpa)) +
908 	    HVN_TX_DESC * (sizeof(struct hvn_nvs_rndis) +
909 	    (HVN_TX_FRAGS + 1) * sizeof(struct vmbus_gpa));
910 
911 	sc->sc_chan->ch_flags &= ~CHF_BATCHED;
912 
913 	/* Associate our interrupt handler with the channel */
914 	if (hv_channel_open(sc->sc_chan, ringsize, NULL, 0,
915 	    hvn_nvs_intr, sc)) {
916 		DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
917 		free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
918 		return (-1);
919 	}
920 
921 	hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
922 
923 	memset(&cmd, 0, sizeof(cmd));
924 	cmd.nvs_type = HVN_NVS_TYPE_INIT;
925 	for (i = 0; i < nitems(protos); i++) {
926 		cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i];
927 		tid = atomic_inc_int_nv(&sc->sc_nvstid);
928 		if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
929 			return (-1);
930 		rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp;
931 		if (rsp->nvs_status == HVN_NVS_STATUS_OK) {
932 			sc->sc_proto = protos[i];
933 			break;
934 		}
935 	}
936 	if (!sc->sc_proto) {
937 		DPRINTF("%s: failed to negotiate NVSP version\n",
938 		    sc->sc_dev.dv_xname);
939 		return (-1);
940 	}
941 
942 	if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
943 		memset(&ccmd, 0, sizeof(ccmd));
944 		ccmd.nvs_type = HVN_NVS_TYPE_NDIS_CONF;
945 		ccmd.nvs_mtu = HVN_MAXMTU;
946 		ccmd.nvs_caps = HVN_NVS_NDIS_CONF_VLAN;
947 
948 		tid = atomic_inc_int_nv(&sc->sc_nvstid);
949 		if (hvn_nvs_cmd(sc, &ccmd, sizeof(ccmd), tid, 100))
950 			return (-1);
951 	}
952 
953 	memset(&ncmd, 0, sizeof(ncmd));
954 	ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT;
955 	if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4)
956 		ndisver = NDIS_VERSION_6_1;
957 	else
958 		ndisver = NDIS_VERSION_6_30;
959 	ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16;
960 	ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff);
961 
962 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
963 	if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100))
964 		return (-1);
965 
966 	sc->sc_ndisver = ndisver;
967 
968 	return (0);
969 }
970 
971 void
972 hvn_nvs_intr(void *arg)
973 {
974 	struct hvn_softc *sc = arg;
975 	struct ifnet *ifp = &sc->sc_ac.ac_if;
976 	struct vmbus_chanpkt_hdr *cph;
977 	struct hvn_nvs_hdr *nvs;
978 	uint64_t rid;
979 	uint32_t rlen;
980 	int rv;
981 
982 	for (;;) {
983 		rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf,
984 		    HVN_NVS_BUFSIZE, &rlen, &rid, 1);
985 		if (rv != 0 || rlen == 0) {
986 			if (rv != EAGAIN)
987 				printf("%s: failed to receive an NVSP "
988 				    "packet\n", sc->sc_dev.dv_xname);
989 			break;
990 		}
991 		cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf;
992 		nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph);
993 
994 		if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) {
995 			switch (nvs->nvs_type) {
996 			case HVN_NVS_TYPE_INIT_RESP:
997 			case HVN_NVS_TYPE_RXBUF_CONNRESP:
998 			case HVN_NVS_TYPE_CHIM_CONNRESP:
999 			case HVN_NVS_TYPE_SUBCH_RESP:
1000 				/* copy the response back */
1001 				memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE);
1002 				sc->sc_nvsdone = 1;
1003 				wakeup_one(&sc->sc_nvsrsp);
1004 				break;
1005 			case HVN_NVS_TYPE_RNDIS_ACK:
1006 				hvn_txeof(sc, cph->cph_tid);
1007 				break;
1008 			default:
1009 				printf("%s: unhandled NVSP packet type %u "
1010 				    "on completion\n", sc->sc_dev.dv_xname,
1011 				    nvs->nvs_type);
1012 			}
1013 		} else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) {
1014 			switch (nvs->nvs_type) {
1015 			case HVN_NVS_TYPE_RNDIS:
1016 				hvn_rndis_input(sc, cph->cph_tid, cph);
1017 				break;
1018 			default:
1019 				printf("%s: unhandled NVSP packet type %u "
1020 				    "on receive\n", sc->sc_dev.dv_xname,
1021 				    nvs->nvs_type);
1022 			}
1023 		} else
1024 			printf("%s: unknown NVSP packet type %u\n",
1025 			    sc->sc_dev.dv_xname, cph->cph_type);
1026 	}
1027 
1028 	if (ifq_is_oactive(&ifp->if_snd))
1029 		ifq_restart(&ifp->if_snd);
1030 }
1031 
1032 int
1033 hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid,
1034     int timo)
1035 {
1036 	struct hvn_nvs_hdr *hdr = cmd;
1037 	int tries = 10;
1038 	int rv, s;
1039 
1040 	KERNEL_ASSERT_LOCKED();
1041 
1042 	sc->sc_nvsdone = 0;
1043 
1044 	do {
1045 		rv = hv_channel_send(sc->sc_chan, cmd, cmdsize,
1046 		    tid, VMBUS_CHANPKT_TYPE_INBAND,
1047 		    timo ? VMBUS_CHANPKT_FLAG_RC : 0);
1048 		if (rv == EAGAIN) {
1049 			if (cold)
1050 				delay(1000);
1051 			else {
1052 				tsleep_nsec(cmd, PRIBIO, "nvsout",
1053 				    USEC_TO_NSEC(1000));
1054 			}
1055 		} else if (rv) {
1056 			DPRINTF("%s: NVSP operation %u send error %d\n",
1057 			    sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1058 			return (rv);
1059 		}
1060 	} while (rv != 0 && --tries > 0);
1061 
1062 	if (tries == 0 && rv != 0) {
1063 		printf("%s: NVSP operation %u send error %d\n",
1064 		    sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1065 		return (rv);
1066 	}
1067 
1068 	if (timo == 0)
1069 		return (0);
1070 
1071 	do {
1072 		if (cold)
1073 			delay(1000);
1074 		else {
1075 			tsleep_nsec(sc, PRIBIO | PCATCH, "nvscmd",
1076 			    USEC_TO_NSEC(1000));
1077 		}
1078 		s = splnet();
1079 		hvn_nvs_intr(sc);
1080 		splx(s);
1081 	} while (--timo > 0 && sc->sc_nvsdone != 1);
1082 
1083 	if (timo == 0 && sc->sc_nvsdone != 1) {
1084 		printf("%s: NVSP operation %u timed out\n",
1085 		    sc->sc_dev.dv_xname, hdr->nvs_type);
1086 		return (ETIMEDOUT);
1087 	}
1088 	return (0);
1089 }
1090 
1091 int
1092 hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid)
1093 {
1094 	struct hvn_nvs_rndis_ack cmd;
1095 	int tries = 5;
1096 	int rv;
1097 
1098 	cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK;
1099 	cmd.nvs_status = HVN_NVS_STATUS_OK;
1100 	do {
1101 		rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd),
1102 		    tid, VMBUS_CHANPKT_TYPE_COMP, 0);
1103 		if (rv == EAGAIN)
1104 			delay(10);
1105 		else if (rv) {
1106 			DPRINTF("%s: NVSP acknowledgement error %d\n",
1107 			    sc->sc_dev.dv_xname, rv);
1108 			return (rv);
1109 		}
1110 	} while (rv != 0 && --tries > 0);
1111 	return (rv);
1112 }
1113 
1114 void
1115 hvn_nvs_detach(struct hvn_softc *sc)
1116 {
1117 	if (hv_channel_close(sc->sc_chan) == 0) {
1118 		free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
1119 		sc->sc_nvsbuf = NULL;
1120 	}
1121 }
1122 
1123 static inline struct rndis_cmd *
1124 hvn_alloc_cmd(struct hvn_softc *sc)
1125 {
1126 	struct rndis_cmd *rc;
1127 
1128 	mtx_enter(&sc->sc_cntl_fqlck);
1129 	while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
1130 		msleep_nsec(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
1131 		    PRIBIO, "nvsalloc", INFSLP);
1132 	TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1133 	mtx_leave(&sc->sc_cntl_fqlck);
1134 	return (rc);
1135 }
1136 
1137 static inline void
1138 hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1139 {
1140 	mtx_enter(&sc->sc_cntl_sqlck);
1141 	TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
1142 	mtx_leave(&sc->sc_cntl_sqlck);
1143 }
1144 
1145 static inline struct rndis_cmd *
1146 hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
1147 {
1148 	struct rndis_cmd *rc;
1149 
1150 	mtx_enter(&sc->sc_cntl_sqlck);
1151 	TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
1152 		if (rc->rc_id == id) {
1153 			TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1154 			break;
1155 		}
1156 	}
1157 	mtx_leave(&sc->sc_cntl_sqlck);
1158 	if (rc != NULL) {
1159 		mtx_enter(&sc->sc_cntl_cqlck);
1160 		TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
1161 		mtx_leave(&sc->sc_cntl_cqlck);
1162 	}
1163 	return (rc);
1164 }
1165 
1166 static inline void
1167 hvn_release_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1168 {
1169 	mtx_enter(&sc->sc_cntl_cqlck);
1170 	TAILQ_REMOVE(&sc->sc_cntl_cq, rc, rc_entry);
1171 	mtx_leave(&sc->sc_cntl_cqlck);
1172 }
1173 
1174 static inline int
1175 hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1176 {
1177 	struct rndis_cmd *rn;
1178 
1179 	mtx_enter(&sc->sc_cntl_sqlck);
1180 	TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
1181 		if (rn == rc) {
1182 			TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1183 			mtx_leave(&sc->sc_cntl_sqlck);
1184 			return (0);
1185 		}
1186 	}
1187 	mtx_leave(&sc->sc_cntl_sqlck);
1188 	return (-1);
1189 }
1190 
1191 static inline void
1192 hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1193 {
1194 	memset(rc->rc_req, 0, sizeof(struct rndis_packet_msg));
1195 	memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
1196 	memset(&rc->rc_msg, 0, sizeof(rc->rc_msg));
1197 	mtx_enter(&sc->sc_cntl_fqlck);
1198 	TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1199 	mtx_leave(&sc->sc_cntl_fqlck);
1200 	wakeup(&sc->sc_cntl_fq);
1201 }
1202 
1203 int
1204 hvn_rndis_attach(struct hvn_softc *sc)
1205 {
1206 	struct rndis_init_req *req;
1207 	struct rndis_init_comp *cmp;
1208 	struct rndis_cmd *rc;
1209 	int i, rv;
1210 
1211 	/* RNDIS control message queues */
1212 	TAILQ_INIT(&sc->sc_cntl_sq);
1213 	TAILQ_INIT(&sc->sc_cntl_cq);
1214 	TAILQ_INIT(&sc->sc_cntl_fq);
1215 	mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
1216 	mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
1217 	mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
1218 
1219 	for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1220 		rc = &sc->sc_cntl_msgs[i];
1221 		if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
1222 		    PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
1223 			DPRINTF("%s: failed to create RNDIS command map\n",
1224 			    sc->sc_dev.dv_xname);
1225 			goto errout;
1226 		}
1227 		if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
1228 		    0, &rc->rc_segs, 1, &rc->rc_nsegs, BUS_DMA_NOWAIT |
1229 		    BUS_DMA_ZERO)) {
1230 			DPRINTF("%s: failed to allocate RNDIS command\n",
1231 			    sc->sc_dev.dv_xname);
1232 			bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1233 			goto errout;
1234 		}
1235 		if (bus_dmamem_map(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs,
1236 		    PAGE_SIZE, (caddr_t *)&rc->rc_req, BUS_DMA_NOWAIT)) {
1237 			DPRINTF("%s: failed to allocate RNDIS command\n",
1238 			    sc->sc_dev.dv_xname);
1239 			bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1240 			    rc->rc_nsegs);
1241 			bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1242 			goto errout;
1243 		}
1244 		if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
1245 		    PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
1246 			DPRINTF("%s: failed to load RNDIS command map\n",
1247 			    sc->sc_dev.dv_xname);
1248 			bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1249 			    rc->rc_nsegs);
1250 			bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1251 			goto errout;
1252 		}
1253 		rc->rc_gpa = atop(rc->rc_dmap->dm_segs[0].ds_addr);
1254 		TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1255 	}
1256 
1257 	rc = hvn_alloc_cmd(sc);
1258 
1259 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1260 	    BUS_DMASYNC_PREREAD);
1261 
1262 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1263 
1264 	req = rc->rc_req;
1265 	req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1266 	req->rm_len = sizeof(*req);
1267 	req->rm_rid = rc->rc_id;
1268 	req->rm_ver_major = RNDIS_VERSION_MAJOR;
1269 	req->rm_ver_minor = RNDIS_VERSION_MINOR;
1270 	req->rm_max_xfersz = HVN_RNDIS_XFER_SIZE;
1271 
1272 	rc->rc_cmplen = sizeof(*cmp);
1273 
1274 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1275 	    BUS_DMASYNC_PREWRITE);
1276 
1277 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1278 		DPRINTF("%s: INITIALIZE_MSG failed, error %d\n",
1279 		    sc->sc_dev.dv_xname, rv);
1280 		hvn_free_cmd(sc, rc);
1281 		goto errout;
1282 	}
1283 	cmp = (struct rndis_init_comp *)&rc->rc_cmp;
1284 	if (cmp->rm_status != RNDIS_STATUS_SUCCESS) {
1285 		DPRINTF("%s: failed to init RNDIS, error %#x\n",
1286 		    sc->sc_dev.dv_xname, cmp->rm_status);
1287 		hvn_free_cmd(sc, rc);
1288 		goto errout;
1289 	}
1290 
1291 	hvn_free_cmd(sc, rc);
1292 
1293 	/* Initialize RNDIS Data command */
1294 	memset(&sc->sc_data_msg, 0, sizeof(sc->sc_data_msg));
1295 	sc->sc_data_msg.nvs_type = HVN_NVS_TYPE_RNDIS;
1296 	sc->sc_data_msg.nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_DATA;
1297 	sc->sc_data_msg.nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1298 
1299 	return (0);
1300 
1301 errout:
1302 	for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1303 		rc = &sc->sc_cntl_msgs[i];
1304 		if (rc->rc_req == NULL)
1305 			continue;
1306 		TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1307 		bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs);
1308 		rc->rc_req = NULL;
1309 		bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1310 	}
1311 	return (-1);
1312 }
1313 
1314 int
1315 hvn_set_capabilities(struct hvn_softc *sc)
1316 {
1317 	struct ndis_offload_params params;
1318 	size_t len = sizeof(params);
1319 
1320 	memset(&params, 0, sizeof(params));
1321 
1322 	params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
1323 	if (sc->sc_ndisver < NDIS_VERSION_6_30) {
1324 		params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
1325 		len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
1326 	} else {
1327 		params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
1328 		len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
1329 	}
1330 
1331 	params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
1332 	params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1333 	params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1334 	if (sc->sc_ndisver >= NDIS_VERSION_6_30) {
1335 		params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1336 		params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1337 	}
1338 
1339 	return (hvn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, &params, len));
1340 }
1341 
1342 int
1343 hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
1344 {
1345 	struct hvn_nvs_rndis *msg = &rc->rc_msg;
1346 	struct rndis_msghdr *hdr = rc->rc_req;
1347 	struct vmbus_gpa sgl[1];
1348 	int tries = 10;
1349 	int rv, s;
1350 
1351 	KERNEL_ASSERT_LOCKED();
1352 
1353 	KASSERT(timo > 0);
1354 
1355 	msg->nvs_type = HVN_NVS_TYPE_RNDIS;
1356 	msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL;
1357 	msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1358 
1359 	sgl[0].gpa_page = rc->rc_gpa;
1360 	sgl[0].gpa_len = hdr->rm_len;
1361 	sgl[0].gpa_ofs = 0;
1362 
1363 	rc->rc_done = 0;
1364 
1365 	hvn_submit_cmd(sc, rc);
1366 
1367 	do {
1368 		rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg,
1369 		    sizeof(*msg), rc->rc_id);
1370 		if (rv == EAGAIN) {
1371 			if (cold)
1372 				delay(100);
1373 			else {
1374 				tsleep_nsec(rc, PRIBIO, "rndisout",
1375 				    USEC_TO_NSEC(100));
1376 			}
1377 		} else if (rv) {
1378 			DPRINTF("%s: RNDIS operation %u send error %d\n",
1379 			    sc->sc_dev.dv_xname, hdr->rm_type, rv);
1380 			hvn_rollback_cmd(sc, rc);
1381 			return (rv);
1382 		}
1383 	} while (rv != 0 && --tries > 0);
1384 
1385 	if (tries == 0 && rv != 0) {
1386 		printf("%s: RNDIS operation %u send error %d\n",
1387 		    sc->sc_dev.dv_xname, hdr->rm_type, rv);
1388 		return (rv);
1389 	}
1390 
1391 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1392 	    BUS_DMASYNC_POSTWRITE);
1393 
1394 	do {
1395 		if (cold)
1396 			delay(1000);
1397 		else {
1398 			tsleep_nsec(rc, PRIBIO | PCATCH, "rndiscmd",
1399 			    USEC_TO_NSEC(1000));
1400 		}
1401 		s = splnet();
1402 		hvn_nvs_intr(sc);
1403 		splx(s);
1404 	} while (--timo > 0 && rc->rc_done != 1);
1405 
1406 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1407 	    BUS_DMASYNC_POSTREAD);
1408 
1409 	if (rc->rc_done != 1) {
1410 		rv = timo == 0 ? ETIMEDOUT : EINTR;
1411 		if (hvn_rollback_cmd(sc, rc)) {
1412 			hvn_release_cmd(sc, rc);
1413 			rv = 0;
1414 		} else if (rv == ETIMEDOUT) {
1415 			printf("%s: RNDIS operation %u timed out\n",
1416 			    sc->sc_dev.dv_xname, hdr->rm_type);
1417 		}
1418 		return (rv);
1419 	}
1420 
1421 	hvn_release_cmd(sc, rc);
1422 	return (0);
1423 }
1424 
1425 void
1426 hvn_rndis_input(struct hvn_softc *sc, uint64_t tid, void *arg)
1427 {
1428 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1429 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1430 	struct vmbus_chanpkt_prplist *cp = arg;
1431 	uint32_t off, len, type;
1432 	int i;
1433 
1434 	if (sc->sc_rx_ring == NULL) {
1435 		DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
1436 		return;
1437 	}
1438 	for (i = 0; i < cp->cp_range_cnt; i++) {
1439 		off = cp->cp_range[i].gpa_ofs;
1440 		len = cp->cp_range[i].gpa_len;
1441 
1442 		KASSERT(off + len <= sc->sc_rx_size);
1443 		KASSERT(len >= RNDIS_HEADER_OFFSET + 4);
1444 
1445 		memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
1446 		switch (type) {
1447 		/* data message */
1448 		case REMOTE_NDIS_PACKET_MSG:
1449 			hvn_rxeof(sc, (caddr_t)sc->sc_rx_ring +
1450 			    off, len, &ml);
1451 			break;
1452 		/* completion messages */
1453 		case REMOTE_NDIS_INITIALIZE_CMPLT:
1454 		case REMOTE_NDIS_QUERY_CMPLT:
1455 		case REMOTE_NDIS_SET_CMPLT:
1456 		case REMOTE_NDIS_RESET_CMPLT:
1457 		case REMOTE_NDIS_KEEPALIVE_CMPLT:
1458 			hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
1459 			    off, len);
1460 			break;
1461 		/* notification message */
1462 		case REMOTE_NDIS_INDICATE_STATUS_MSG:
1463 			hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
1464 			    off, len);
1465 			break;
1466 		default:
1467 			printf("%s: unhandled RNDIS message type %u\n",
1468 			    sc->sc_dev.dv_xname, type);
1469 		}
1470 	}
1471 	hvn_nvs_ack(sc, tid);
1472 
1473 	if (ifp->if_flags & IFF_RUNNING)
1474 		if_input(ifp, &ml);
1475 	else
1476 		ml_purge(&ml);
1477 }
1478 
1479 static inline struct mbuf *
1480 hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1481 {
1482 	struct mbuf *m;
1483 
1484 	if (len + ETHER_ALIGN <= MHLEN)
1485 		MGETHDR(m, M_NOWAIT, MT_DATA);
1486 	else
1487 		m = MCLGETL(NULL, M_NOWAIT, len + ETHER_ALIGN);
1488 	if (m == NULL)
1489 		return (NULL);
1490 	m->m_len = m->m_pkthdr.len = len;
1491 	m_adj(m, ETHER_ALIGN);
1492 
1493 	if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
1494 		m_freem(m);
1495 		return (NULL);
1496 	}
1497 
1498 	return (m);
1499 }
1500 
1501 void
1502 hvn_rxeof(struct hvn_softc *sc, caddr_t buf, uint32_t len, struct mbuf_list *ml)
1503 {
1504 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1505 	struct rndis_packet_msg *pkt;
1506 	struct rndis_pktinfo *pi;
1507 	uint32_t csum, vlan;
1508 	struct mbuf *m;
1509 
1510 	if (!(ifp->if_flags & IFF_RUNNING))
1511 		return;
1512 
1513 	if (len < sizeof(*pkt)) {
1514 		printf("%s: data packet too short: %u\n",
1515 		    sc->sc_dev.dv_xname, len);
1516 		return;
1517 	}
1518 
1519 	pkt = (struct rndis_packet_msg *)buf;
1520 
1521 	if (pkt->rm_dataoffset + pkt->rm_datalen > len) {
1522 		printf("%s: data packet out of bounds: %u@%u\n",
1523 		    sc->sc_dev.dv_xname, pkt->rm_dataoffset, pkt->rm_datalen);
1524 		return;
1525 	}
1526 
1527 	if ((m = hvn_devget(sc, buf + RNDIS_HEADER_OFFSET + pkt->rm_dataoffset,
1528 	    pkt->rm_datalen)) == NULL) {
1529 		ifp->if_ierrors++;
1530 		return;
1531 	}
1532 
1533 	if (pkt->rm_pktinfooffset + pkt->rm_pktinfolen > len) {
1534 		printf("%s: pktinfo is out of bounds: %u@%u vs %u\n",
1535 		    sc->sc_dev.dv_xname, pkt->rm_pktinfolen,
1536 		    pkt->rm_pktinfooffset, len);
1537 		goto done;
1538 	}
1539 	pi = (struct rndis_pktinfo *)((caddr_t)pkt + RNDIS_HEADER_OFFSET +
1540 	    pkt->rm_pktinfooffset);
1541 	while (pkt->rm_pktinfolen > 0) {
1542 		if (pi->rm_size > pkt->rm_pktinfolen) {
1543 			printf("%s: invalid pktinfo size: %u/%u\n",
1544 			    sc->sc_dev.dv_xname, pi->rm_size,
1545 			    pkt->rm_pktinfolen);
1546 			break;
1547 		}
1548 		switch (pi->rm_type) {
1549 		case NDIS_PKTINFO_TYPE_CSUM:
1550 			memcpy(&csum, pi->rm_data, sizeof(csum));
1551 			if (csum & NDIS_RXCSUM_INFO_IPCS_OK)
1552 				m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1553 			if (csum & NDIS_RXCSUM_INFO_TCPCS_OK)
1554 				m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
1555 			if (csum & NDIS_RXCSUM_INFO_UDPCS_OK)
1556 				m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
1557 			break;
1558 		case NDIS_PKTINFO_TYPE_VLAN:
1559 			memcpy(&vlan, pi->rm_data, sizeof(vlan));
1560 #if NVLAN > 0
1561 			if (vlan != 0xffffffff) {
1562 				m->m_pkthdr.ether_vtag =
1563 				    NDIS_VLAN_INFO_ID(vlan) |
1564 				    (NDIS_VLAN_INFO_PRI(vlan) << EVL_PRIO_BITS);
1565 				m->m_flags |= M_VLANTAG;
1566 			}
1567 #endif
1568 			break;
1569 		default:
1570 			DPRINTF("%s: unhandled pktinfo type %u\n",
1571 			    sc->sc_dev.dv_xname, pi->rm_type);
1572 		}
1573 		pkt->rm_pktinfolen -= pi->rm_size;
1574 		pi = (struct rndis_pktinfo *)((caddr_t)pi + pi->rm_size);
1575 	}
1576 
1577  done:
1578 	ml_enqueue(ml, m);
1579 }
1580 
1581 void
1582 hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1583 {
1584 	struct rndis_cmd *rc;
1585 	uint32_t id;
1586 
1587 	memcpy(&id, buf + RNDIS_HEADER_OFFSET, sizeof(id));
1588 	if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
1589 		if (len < rc->rc_cmplen)
1590 			printf("%s: RNDIS response %u too short: %u\n",
1591 			    sc->sc_dev.dv_xname, id, len);
1592 		else
1593 			memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
1594 		if (len > rc->rc_cmplen &&
1595 		    len - rc->rc_cmplen > HVN_RNDIS_BUFSIZE)
1596 			printf("%s: RNDIS response %u too large: %u\n",
1597 			    sc->sc_dev.dv_xname, id, len);
1598 		else if (len > rc->rc_cmplen)
1599 			memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
1600 			    len - rc->rc_cmplen);
1601 		rc->rc_done = 1;
1602 		wakeup_one(rc);
1603 	} else
1604 		DPRINTF("%s: failed to complete RNDIS request id %u\n",
1605 		    sc->sc_dev.dv_xname, id);
1606 }
1607 
1608 int
1609 hvn_rndis_output(struct hvn_softc *sc, struct hvn_tx_desc *txd)
1610 {
1611 	uint64_t rid = (uint64_t)txd->txd_id << 32;
1612 	int rv;
1613 
1614 	rv = hv_channel_send_sgl(sc->sc_chan, txd->txd_sgl, txd->txd_nsge,
1615 	    &sc->sc_data_msg, sizeof(sc->sc_data_msg), rid);
1616 	if (rv) {
1617 		DPRINTF("%s: RNDIS data send error %d\n",
1618 		    sc->sc_dev.dv_xname, rv);
1619 		return (rv);
1620 	}
1621 
1622 	return (0);
1623 }
1624 
1625 void
1626 hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1627 {
1628 	uint32_t status;
1629 
1630 	memcpy(&status, buf + RNDIS_HEADER_OFFSET, sizeof(status));
1631 	switch (status) {
1632 	case RNDIS_STATUS_MEDIA_CONNECT:
1633 		sc->sc_link_state = LINK_STATE_UP;
1634 		break;
1635 	case RNDIS_STATUS_MEDIA_DISCONNECT:
1636 		sc->sc_link_state = LINK_STATE_DOWN;
1637 		break;
1638 	/* Ignore these */
1639 	case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
1640 		return;
1641 	default:
1642 		DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname,
1643 		    status);
1644 		return;
1645 	}
1646 	KERNEL_LOCK();
1647 	hvn_link_status(sc);
1648 	KERNEL_UNLOCK();
1649 }
1650 
1651 int
1652 hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
1653 {
1654 	struct rndis_cmd *rc;
1655 	struct rndis_query_req *req;
1656 	struct rndis_query_comp *cmp;
1657 	size_t olength = *length;
1658 	int rv;
1659 
1660 	rc = hvn_alloc_cmd(sc);
1661 
1662 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1663 	    BUS_DMASYNC_PREREAD);
1664 
1665 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1666 
1667 	req = rc->rc_req;
1668 	req->rm_type = REMOTE_NDIS_QUERY_MSG;
1669 	req->rm_len = sizeof(*req);
1670 	req->rm_rid = rc->rc_id;
1671 	req->rm_oid = oid;
1672 	req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1673 
1674 	rc->rc_cmplen = sizeof(*cmp);
1675 
1676 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1677 	    BUS_DMASYNC_PREWRITE);
1678 
1679 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1680 		DPRINTF("%s: QUERY_MSG failed, error %d\n",
1681 		    sc->sc_dev.dv_xname, rv);
1682 		hvn_free_cmd(sc, rc);
1683 		return (rv);
1684 	}
1685 
1686 	cmp = (struct rndis_query_comp *)&rc->rc_cmp;
1687 	switch (cmp->rm_status) {
1688 	case RNDIS_STATUS_SUCCESS:
1689 		if (cmp->rm_infobuflen > olength) {
1690 			rv = EINVAL;
1691 			break;
1692 		}
1693 		memcpy(res, rc->rc_cmpbuf, cmp->rm_infobuflen);
1694 		*length = cmp->rm_infobuflen;
1695 		break;
1696 	default:
1697 		*length = 0;
1698 		rv = EIO;
1699 	}
1700 
1701 	hvn_free_cmd(sc, rc);
1702 
1703 	return (rv);
1704 }
1705 
1706 int
1707 hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
1708 {
1709 	struct rndis_cmd *rc;
1710 	struct rndis_set_req *req;
1711 	struct rndis_set_comp *cmp;
1712 	int rv;
1713 
1714 	rc = hvn_alloc_cmd(sc);
1715 
1716 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1717 	    BUS_DMASYNC_PREREAD);
1718 
1719 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1720 
1721 	req = rc->rc_req;
1722 	req->rm_type = REMOTE_NDIS_SET_MSG;
1723 	req->rm_len = sizeof(*req) + length;
1724 	req->rm_rid = rc->rc_id;
1725 	req->rm_oid = oid;
1726 	req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1727 
1728 	rc->rc_cmplen = sizeof(*cmp);
1729 
1730 	if (length > 0) {
1731 		KASSERT(sizeof(*req) + length < PAGE_SIZE);
1732 		req->rm_infobuflen = length;
1733 		memcpy((caddr_t)(req + 1), data, length);
1734 	}
1735 
1736 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1737 	    BUS_DMASYNC_PREWRITE);
1738 
1739 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1740 		DPRINTF("%s: SET_MSG failed, error %d\n",
1741 		    sc->sc_dev.dv_xname, rv);
1742 		hvn_free_cmd(sc, rc);
1743 		return (rv);
1744 	}
1745 
1746 	cmp = (struct rndis_set_comp *)&rc->rc_cmp;
1747 	if (cmp->rm_status != RNDIS_STATUS_SUCCESS)
1748 		rv = EIO;
1749 
1750 	hvn_free_cmd(sc, rc);
1751 
1752 	return (rv);
1753 }
1754 
1755 int
1756 hvn_rndis_close(struct hvn_softc *sc)
1757 {
1758 	uint32_t filter = 0;
1759 	int rv;
1760 
1761 	rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
1762 	    &filter, sizeof(filter));
1763 	if (rv)
1764 		DPRINTF("%s: failed to clear RNDIS filter\n",
1765 		    sc->sc_dev.dv_xname);
1766 	return (rv);
1767 }
1768 
1769 void
1770 hvn_rndis_detach(struct hvn_softc *sc)
1771 {
1772 	struct rndis_cmd *rc;
1773 	struct rndis_halt_req *req;
1774 	int rv;
1775 
1776 	rc = hvn_alloc_cmd(sc);
1777 
1778 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1779 	    BUS_DMASYNC_PREREAD);
1780 
1781 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1782 
1783 	req = rc->rc_req;
1784 	req->rm_type = REMOTE_NDIS_HALT_MSG;
1785 	req->rm_len = sizeof(*req);
1786 	req->rm_rid = rc->rc_id;
1787 
1788 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1789 	    BUS_DMASYNC_PREWRITE);
1790 
1791 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0)
1792 		DPRINTF("%s: HALT_MSG failed, error %d\n",
1793 		    sc->sc_dev.dv_xname, rv);
1794 
1795 	hvn_free_cmd(sc, rc);
1796 }
1797