xref: /openbsd/sys/dev/pv/if_hvn.c (revision 9b7c3dbb)
1 /*-
2  * Copyright (c) 2009-2012 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 #include <dev/pv/rndisreg.h>
59 #include <dev/pv/if_hvnreg.h>
60 
61 #include <net/if.h>
62 #include <net/if_media.h>
63 
64 #include <netinet/in.h>
65 #include <netinet/if_ether.h>
66 
67 #ifdef INET6
68 #include <netinet/ip6.h>
69 #endif
70 
71 #if NBPFILTER > 0
72 #include <net/bpf.h>
73 #endif
74 
75 #define HVN_DEBUG			1
76 
77 #define HVN_NVS_BUFSIZE		  	PAGE_SIZE
78 #define HVN_NVS_MSGSIZE			32
79 
80 /*
81  * RNDIS control interface
82  */
83 #define HVN_RNDIS_CTLREQS		4
84 #define HVN_RNDIS_CMPBUFSZ		512
85 
86 struct rndis_cmd {
87 	uint32_t			 rc_id;
88 	struct hvn_nvs_rndis		 rc_msg;
89 	struct rndis			*rc_req;
90 	bus_dmamap_t			 rc_dmap;
91 	uint64_t			 rc_pfn;
92 	struct rndis			 rc_cmp;
93 	uint32_t			 rc_cmplen;
94 	uint8_t				 rc_cmpbuf[HVN_RNDIS_CMPBUFSZ];
95 	struct mutex			 rc_mtx;
96 	TAILQ_ENTRY(rndis_cmd)		 rc_entry;
97 };
98 TAILQ_HEAD(rndis_queue, rndis_cmd);
99 
100 /*
101  * Tx ring
102  */
103 #define HVN_TX_DESC			128
104 
105 struct hvn_softc {
106 	struct device			 sc_dev;
107 	struct hv_softc			*sc_hvsc;
108 	struct hv_channel		*sc_chan;
109 	bus_dma_tag_t			 sc_dmat;
110 
111 	struct arpcom			 sc_ac;
112 	struct ifmedia			 sc_media;
113 	int				 sc_link_state;
114 	int				 sc_promisc;
115 
116 	/* NVS protocol */
117 	int				 sc_proto;
118 	uint32_t			 sc_nvstid;
119 	uint8_t				 sc_nvsrsp[HVN_NVS_MSGSIZE];
120 	uint8_t				*sc_nvsbuf;
121 	struct mutex			 sc_nvslck;
122 
123 	/* RNDIS protocol */
124 	uint32_t			 sc_rndisrid;
125 	struct rndis_queue		 sc_cntl_sq; /* submission queue */
126 	struct mutex			 sc_cntl_sqlck;
127 	struct rndis_queue		 sc_cntl_cq; /* completion queue */
128 	struct mutex			 sc_cntl_cqlck;
129 	struct rndis_queue		 sc_cntl_fq; /* free queue */
130 	struct mutex			 sc_cntl_fqlck;
131 	struct rndis_cmd		 sc_cntl_msgs[HVN_RNDIS_CTLREQS];
132 
133 	/* Rx ring */
134 	void				*sc_rx_ring;
135 	int				 sc_rx_size;
136 	uint32_t			 sc_rx_hndl;
137 
138 	/* Tx ring */
139 	void				*sc_tx_ring;
140 	int				 sc_tx_size;
141 	uint32_t			 sc_tx_hndl;
142 };
143 
144 int	hvn_match(struct device *, void *, void *);
145 void	hvn_attach(struct device *, struct device *, void *);
146 int	hvn_ioctl(struct ifnet *, u_long, caddr_t);
147 int	hvn_media_change(struct ifnet *);
148 void	hvn_media_status(struct ifnet *, struct ifmediareq *);
149 int	hvn_iff(struct hvn_softc *);
150 void	hvn_init(struct hvn_softc *);
151 void	hvn_stop(struct hvn_softc *);
152 void	hvn_start(struct ifnet *);
153 void	hvn_txeof(struct hvn_softc *, uint64_t);
154 void	hvn_rxeof(struct hvn_softc *, void *);
155 int	hvn_rx_ring_create(struct hvn_softc *);
156 int	hvn_rx_ring_destroy(struct hvn_softc *);
157 int	hvn_tx_ring_create(struct hvn_softc *);
158 int	hvn_tx_ring_destroy(struct hvn_softc *);
159 int	hvn_get_lladdr(struct hvn_softc *);
160 int	hvn_set_lladdr(struct hvn_softc *);
161 void	hvn_get_link_status(struct hvn_softc *);
162 void	hvn_link_status(struct hvn_softc *);
163 
164 /* NSVP */
165 int	hvn_nvs_attach(struct hvn_softc *);
166 void	hvn_nvs_intr(void *);
167 int	hvn_nvs_cmd(struct hvn_softc *, void *, size_t, uint64_t, int);
168 int	hvn_nvs_ack(struct hvn_softc *, uint64_t);
169 void	hvn_nvs_detach(struct hvn_softc *);
170 
171 /* RNDIS */
172 int	hvn_rndis_attach(struct hvn_softc *);
173 int	hvn_rndis_cmd(struct hvn_softc *, struct rndis_cmd *, int);
174 void	hvn_rndis_filter(struct hvn_softc *sc, uint64_t, void *);
175 void	hvn_rndis_input(struct hvn_softc *, caddr_t, uint32_t,
176 	    struct mbuf_list *);
177 void	hvn_rndis_complete(struct hvn_softc *, caddr_t, uint32_t);
178 void	hvn_rndis_status(struct hvn_softc *, caddr_t, uint32_t);
179 int	hvn_rndis_query(struct hvn_softc *, uint32_t, void *, size_t *);
180 int	hvn_rndis_set(struct hvn_softc *, uint32_t, void *, size_t);
181 int	hvn_rndis_open(struct hvn_softc *);
182 int	hvn_rndis_close(struct hvn_softc *);
183 void	hvn_rndis_detach(struct hvn_softc *);
184 
185 struct cfdriver hvn_cd = {
186 	NULL, "hvn", DV_IFNET
187 };
188 
189 const struct cfattach hvn_ca = {
190 	sizeof(struct hvn_softc), hvn_match, hvn_attach
191 };
192 
193 int
194 hvn_match(struct device *parent, void *match, void *aux)
195 {
196 	struct hv_attach_args *aa = aux;
197 
198 	if (strcmp("network", aa->aa_ident))
199 		return (0);
200 
201 	return (1);
202 }
203 
204 void
205 hvn_attach(struct device *parent, struct device *self, void *aux)
206 {
207 	struct hv_attach_args *aa = aux;
208 	struct hvn_softc *sc = (struct hvn_softc *)self;
209 	struct ifnet *ifp = &sc->sc_ac.ac_if;
210 
211 	sc->sc_hvsc = (struct hv_softc *)parent;
212 	sc->sc_chan = aa->aa_chan;
213 	sc->sc_dmat = aa->aa_dmat;
214 
215 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
216 
217 	DPRINTF("\n");
218 
219 	if (hvn_nvs_attach(sc)) {
220 		printf(": failed to init NVSP\n");
221 		return;
222 	}
223 
224 	if (hvn_rx_ring_create(sc)) {
225 		printf(": failed to create Rx ring\n");
226 		goto detach;
227 	}
228 
229 	if (hvn_tx_ring_create(sc)) {
230 		printf(": failed to create Tx ring\n");
231 		goto detach;
232 	}
233 
234 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
235 	ifp->if_xflags = IFXF_MPSAFE;
236 	ifp->if_ioctl = hvn_ioctl;
237 	ifp->if_start = hvn_start;
238 	ifp->if_softc = sc;
239 
240 	ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
241 	    IFCAP_CSUM_UDPv4;
242 #if NVLAN > 0
243 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
244 #endif
245 
246 	IFQ_SET_MAXLEN(&ifp->if_snd, HVN_TX_DESC - 1);
247 
248 	ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
249 	    hvn_media_status);
250 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
251 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
252 
253 	if_attach(ifp);
254 
255 	if (hvn_rndis_attach(sc)) {
256 		printf(": failed to init RNDIS\n");
257 		goto detach;
258 	}
259 
260 	if (hvn_get_lladdr(sc)) {
261 		printf(": failed to obtain an ethernet address\n");
262 		hvn_rndis_detach(sc);
263 		goto detach;
264 	}
265 
266 	DPRINTF("%s", sc->sc_dev.dv_xname);
267 	printf(": channel %u, address %s\n", sc->sc_chan->ch_id,
268 	    ether_sprintf(sc->sc_ac.ac_enaddr));
269 
270 	ether_ifattach(ifp);
271 	return;
272 
273  detach:
274 	hvn_rx_ring_destroy(sc);
275 	hvn_tx_ring_destroy(sc);
276 	hvn_nvs_detach(sc);
277 	if (ifp->if_start)
278 		if_detach(ifp);
279 }
280 
281 int
282 hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
283 {
284 	struct hvn_softc *sc = ifp->if_softc;
285 	struct ifreq *ifr = (struct ifreq *)data;
286 	int s, error = 0;
287 
288 	s = splnet();
289 
290 	switch (command) {
291 	case SIOCSIFADDR:
292 		ifp->if_flags |= IFF_UP;
293 		if (!(ifp->if_flags & IFF_RUNNING))
294 			hvn_init(sc);
295 		break;
296 	case SIOCSIFFLAGS:
297 		if (ifp->if_flags & IFF_UP) {
298 			if (ifp->if_flags & IFF_RUNNING)
299 				error = ENETRESET;
300 			else
301 				hvn_init(sc);
302 		} else {
303 			if (ifp->if_flags & IFF_RUNNING)
304 				hvn_stop(sc);
305 		}
306 		break;
307 	case SIOCGIFMEDIA:
308 	case SIOCSIFMEDIA:
309 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
310 		break;
311 	default:
312 		error = ether_ioctl(ifp, &sc->sc_ac, command, data);
313 	}
314 
315 	if (error == ENETRESET) {
316 		if (ifp->if_flags & IFF_RUNNING)
317 			hvn_iff(sc);
318 		error = 0;
319 	}
320 
321 	splx(s);
322 
323 	return (error);
324 }
325 
326 int
327 hvn_media_change(struct ifnet *ifp)
328 {
329 	return (0);
330 }
331 
332 void
333 hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
334 {
335 	struct hvn_softc *sc = ifp->if_softc;
336 
337 	hvn_get_link_status(sc);
338 	hvn_link_status(sc);
339 
340 	ifmr->ifm_status = IFM_AVALID;
341 	ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
342 	if (sc->sc_link_state == LINK_STATE_UP)
343 		ifmr->ifm_status |= IFM_ACTIVE;
344 }
345 
346 void
347 hvn_link_status(struct hvn_softc *sc)
348 {
349 	struct ifnet *ifp = &sc->sc_ac.ac_if;
350 
351 	if (sc->sc_link_state != ifp->if_link_state) {
352 		ifp->if_link_state = sc->sc_link_state;
353 		if_link_state_change(ifp);
354 	}
355 }
356 
357 int
358 hvn_iff(struct hvn_softc *sc)
359 {
360 	/* XXX */
361 	sc->sc_promisc = 0;
362 
363 	return (0);
364 }
365 
366 void
367 hvn_init(struct hvn_softc *sc)
368 {
369 	struct ifnet *ifp = &sc->sc_ac.ac_if;
370 
371 	hvn_stop(sc);
372 
373 	hvn_iff(sc);
374 
375 	if (hvn_rndis_open(sc) == 0) {
376 		ifp->if_flags |= IFF_RUNNING;
377 		ifq_clr_oactive(&ifp->if_snd);
378 	}
379 }
380 
381 void
382 hvn_stop(struct hvn_softc *sc)
383 {
384 	struct ifnet *ifp = &sc->sc_ac.ac_if;
385 
386 	if (ifp->if_flags & IFF_RUNNING) {
387 		ifp->if_flags &= ~IFF_RUNNING;
388 		hvn_rndis_close(sc);
389 	}
390 
391 	ifq_barrier(&ifp->if_snd);
392 	intr_barrier(sc->sc_chan);
393 
394 	ifq_clr_oactive(&ifp->if_snd);
395 }
396 
397 void
398 hvn_start(struct ifnet *ifp)
399 {
400 	struct mbuf *m;
401 
402 	if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
403 		return;
404 
405 	for (;;) {
406 		m = ifq_deq_begin(&ifp->if_snd);
407 		if (m == NULL)
408 			break;
409 
410 		ifq_deq_commit(&ifp->if_snd, m);
411 
412 #if NBPFILTER > 0
413 		if (ifp->if_bpf)
414 			bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
415 #endif
416 
417 		m_freem(m);
418 		ifp->if_oerrors++;
419 	}
420 }
421 
422 void
423 hvn_txeof(struct hvn_softc *sc, uint64_t tid)
424 {
425 	struct ifnet *ifp = &sc->sc_ac.ac_if;
426 
427 	printf("%s: tx tid %llu\n", ifp->if_xname, tid);
428 }
429 
430 int
431 hvn_rx_ring_create(struct hvn_softc *sc)
432 {
433 	struct hvn_nvs_rxbuf_conn cmd;
434 	struct hvn_nvs_rxbuf_conn_resp *rsp;
435 	uint64_t tid;
436 
437 	if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2)
438 		sc->sc_rx_size = 15 * 1024 * 1024;	/* 15MB */
439 	else
440 		sc->sc_rx_size = 16 * 1024 * 1024; 	/* 16MB */
441 	sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
442 	    cold ? &kd_nowait : &kd_waitok);
443 	if (sc->sc_rx_ring == NULL) {
444 		DPRINTF("%s: failed to allocate Rx ring buffer\n",
445 		    sc->sc_dev.dv_xname);
446 		return (-1);
447 	}
448 	if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
449 	    &sc->sc_rx_hndl)) {
450 		DPRINTF("%s: failed to obtain a PA handle\n",
451 		    sc->sc_dev.dv_xname);
452 		goto errout;
453 	}
454 
455 	memset(&cmd, 0, sizeof(cmd));
456 	cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN;
457 	cmd.nvs_gpadl = sc->sc_rx_hndl;
458 	cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
459 
460 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
461 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
462 		goto errout;
463 
464 	rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp;
465 	if (rsp->nvs_status != HVN_NVS_STATUS_OK) {
466 		DPRINTF("%s: failed to set up the Rx ring\n",
467 		    sc->sc_dev.dv_xname);
468 		goto errout;
469 	}
470 	if (rsp->nvs_nsect > 1) {
471 		DPRINTF("%s: invalid number of Rx ring sections: %d\n",
472 		    sc->sc_dev.dv_xname, rsp->nvs_nsect);
473 		hvn_rx_ring_destroy(sc);
474 		return (-1);
475 	}
476 	return (0);
477 
478  errout:
479 	if (sc->sc_rx_hndl) {
480 		hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
481 		sc->sc_rx_hndl = 0;
482 	}
483 	if (sc->sc_rx_ring) {
484 		km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
485 		sc->sc_rx_ring = NULL;
486 	}
487 	return (-1);
488 }
489 
490 int
491 hvn_rx_ring_destroy(struct hvn_softc *sc)
492 {
493 	struct hvn_nvs_rxbuf_disconn cmd;
494 	uint64_t tid;
495 
496 	if (sc->sc_rx_ring == NULL)
497 		return (0);
498 
499 	memset(&cmd, 0, sizeof(cmd));
500 	cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN;
501 	cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
502 
503 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
504 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
505 		return (-1);
506 
507 	delay(100);
508 
509 	hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
510 
511 	sc->sc_rx_hndl = 0;
512 
513 	km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
514 	sc->sc_rx_ring = NULL;
515 
516 	return (0);
517 }
518 
519 int
520 hvn_tx_ring_create(struct hvn_softc *sc)
521 {
522 	struct hvn_nvs_chim_conn cmd;
523 	struct hvn_nvs_chim_conn_resp *rsp;
524 	uint64_t tid;
525 
526 	sc->sc_tx_size = 15 * 1024 * 1024;	/* 15MB */
527 	sc->sc_tx_ring = km_alloc(sc->sc_tx_size, &kv_any, &kp_zero,
528 	    cold ? &kd_nowait : &kd_waitok);
529 	if (sc->sc_tx_ring == NULL) {
530 		DPRINTF("%s: failed to allocate Tx ring buffer\n",
531 		    sc->sc_dev.dv_xname);
532 		return (-1);
533 	}
534 	if (hv_handle_alloc(sc->sc_chan, sc->sc_tx_ring, sc->sc_tx_size,
535 	    &sc->sc_tx_hndl)) {
536 		DPRINTF("%s: failed to obtain a PA handle\n",
537 		    sc->sc_dev.dv_xname);
538 		goto errout;
539 	}
540 
541 	memset(&cmd, 0, sizeof(cmd));
542 	cmd.nvs_type = HVN_NVS_TYPE_CHIM_CONN;
543 	cmd.nvs_gpadl = sc->sc_tx_hndl;
544 	cmd.nvs_sig = HVN_NVS_CHIM_SIG;
545 
546 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
547 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
548 		goto errout;
549 
550 	rsp = (struct hvn_nvs_chim_conn_resp *)&sc->sc_nvsrsp;
551 	if (rsp->nvs_status != HVN_NVS_STATUS_OK) {
552 		DPRINTF("%s: failed to set up the Tx ring\n",
553 		    sc->sc_dev.dv_xname);
554 		goto errout;
555 	}
556 	return (0);
557 
558  errout:
559 	if (sc->sc_tx_hndl) {
560 		hv_handle_free(sc->sc_chan, sc->sc_tx_hndl);
561 		sc->sc_tx_hndl = 0;
562 	}
563 	if (sc->sc_tx_ring) {
564 		km_free(sc->sc_tx_ring, sc->sc_tx_size, &kv_any, &kp_zero);
565 		sc->sc_tx_ring = NULL;
566 	}
567 	return (-1);
568 }
569 
570 int
571 hvn_tx_ring_destroy(struct hvn_softc *sc)
572 {
573 	struct hvn_nvs_chim_disconn cmd;
574 	uint64_t tid;
575 
576 	if (sc->sc_tx_ring == NULL)
577 		return (0);
578 
579 	memset(&cmd, 0, sizeof(cmd));
580 	cmd.nvs_type = HVN_NVS_TYPE_CHIM_DISCONN;
581 	cmd.nvs_sig = HVN_NVS_CHIM_SIG;
582 
583 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
584 	if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
585 		return (-1);
586 
587 	delay(100);
588 
589 	hv_handle_free(sc->sc_chan, sc->sc_tx_hndl);
590 
591 	sc->sc_tx_hndl = 0;
592 
593 	km_free(sc->sc_tx_ring, sc->sc_tx_size, &kv_any, &kp_zero);
594 	sc->sc_tx_ring = NULL;
595 	return (0);
596 }
597 
598 int
599 hvn_get_lladdr(struct hvn_softc *sc)
600 {
601 	char enaddr[ETHER_ADDR_LEN];
602 	size_t addrlen = ETHER_ADDR_LEN;
603 	int rv;
604 
605 	rv = hvn_rndis_query(sc, RNDIS_OID_802_3_PERMANENT_ADDRESS,
606 	    enaddr, &addrlen);
607 	if (rv == 0 && addrlen == ETHER_ADDR_LEN)
608 		memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
609 	return (rv);
610 }
611 
612 int
613 hvn_set_lladdr(struct hvn_softc *sc)
614 {
615 	return (hvn_rndis_set(sc, RNDIS_OID_802_3_CURRENT_ADDRESS,
616 	    sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
617 }
618 
619 void
620 hvn_get_link_status(struct hvn_softc *sc)
621 {
622 	uint32_t state;
623 	size_t len = sizeof(state);
624 
625 	if (hvn_rndis_query(sc, RNDIS_OID_GEN_MEDIA_CONNECT_STATUS,
626 	    &state, &len) == 0)
627 		sc->sc_link_state = (state == 0) ? LINK_STATE_UP :
628 		    LINK_STATE_DOWN;
629 }
630 
631 int
632 hvn_nvs_attach(struct hvn_softc *sc)
633 {
634 	const uint32_t protos[] = {
635 		HVN_NVS_PROTO_VERSION_5, HVN_NVS_PROTO_VERSION_4,
636 		HVN_NVS_PROTO_VERSION_2, HVN_NVS_PROTO_VERSION_1
637 	};
638 	struct hvn_nvs_init cmd;
639 	struct hvn_nvs_init_resp *rsp;
640 	struct hvn_nvs_ndis_init ncmd;
641 	uint64_t tid;
642 	uint32_t ndisver;
643 	int i;
644 
645 	/* 4 page sized buffer for channel messages */
646 	sc->sc_nvsbuf = km_alloc(HVN_NVS_BUFSIZE, &kv_any, &kp_zero,
647 	    (cold ? &kd_nowait : &kd_waitok));
648 	if (sc->sc_nvsbuf == NULL) {
649 		DPRINTF("%s: failed to allocate channel data buffer\n",
650 		    sc->sc_dev.dv_xname);
651 		return (-1);
652 	}
653 	sc->sc_chan->ch_buflen = PAGE_SIZE * 4;
654 
655 	/* Associate our interrupt handler with the channel */
656 	if (hv_channel_open(sc->sc_chan, NULL, 0, hvn_nvs_intr, sc)) {
657 		DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
658 		km_free(sc->sc_nvsbuf, HVN_NVS_BUFSIZE, &kv_any, &kp_zero);
659 		return (-1);
660 	}
661 
662 	mtx_init(&sc->sc_nvslck, IPL_NET);
663 
664 	memset(&cmd, 0, sizeof(cmd));
665 	cmd.nvs_type = HVN_NVS_TYPE_INIT;
666 	for (i = 0; i < nitems(protos); i++) {
667 		cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i];
668 		tid = atomic_inc_int_nv(&sc->sc_nvstid);
669 		if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
670 			return (-1);
671 		rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp;
672 		if (rsp->nvs_status == HVN_NVS_STATUS_OK) {
673 			sc->sc_proto = protos[i];
674 			break;
675 		}
676 	}
677 	if (!sc->sc_proto) {
678 		DPRINTF("%s: failed to negotiate NVSP version\n",
679 		    sc->sc_dev.dv_xname);
680 		return (-1);
681 	}
682 
683 	memset(&ncmd, 0, sizeof(ncmd));
684 	ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT;
685 	if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4)
686 		ndisver = NDIS_VERSION_6_1;
687 	else
688 		ndisver = NDIS_VERSION_6_30;
689 	ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16;
690 	ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff);
691 
692 	tid = atomic_inc_int_nv(&sc->sc_nvstid);
693 	if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100))
694 		return (-1);
695 
696 	DPRINTF("%s: NVSP %u.%u, NDIS %u.%u\n", sc->sc_dev.dv_xname,
697 	    sc->sc_proto >> 16, sc->sc_proto & 0xffff,
698 	    ndisver >> 16, ndisver & 0xffff);
699 
700 	return (0);
701 }
702 
703 void
704 hvn_nvs_intr(void *arg)
705 {
706 	struct hvn_softc *sc = arg;
707 	struct vmbus_chanpkt_hdr *cph;
708 	struct hvn_nvs_hdr *nvs;
709 	uint64_t rid;
710 	uint32_t rlen;
711 	int rv;
712 
713 	for (;;) {
714 		rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf,
715 		    HVN_NVS_BUFSIZE, &rlen, &rid, 1);
716 		if (rv != 0 || rlen == 0) {
717 			if (rv != EAGAIN)
718 				printf("%s: failed to receive an NVSP "
719 				    "packet\n", sc->sc_dev.dv_xname);
720 			break;
721 		}
722 		cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf;
723 		nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph);
724 
725 		if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) {
726 			switch (nvs->nvs_type) {
727 			case HVN_NVS_TYPE_INIT_RESP:
728 			case HVN_NVS_TYPE_RXBUF_CONNRESP:
729 			case HVN_NVS_TYPE_CHIM_CONNRESP:
730 			case HVN_NVS_TYPE_SUBCH_RESP:
731 				/* copy the response back */
732 				memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE);
733 				wakeup_one(&sc->sc_nvsrsp);
734 				break;
735 			case HVN_NVS_TYPE_RNDIS_ACK:
736 				hvn_txeof(sc, cph->cph_tid);
737 				break;
738 			default:
739 				printf("%s: unhandled NVSP packet type %d "
740 				    "on completion\n", sc->sc_dev.dv_xname,
741 				    nvs->nvs_type);
742 			}
743 		} else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) {
744 			switch (nvs->nvs_type) {
745 			case HVN_NVS_TYPE_RNDIS:
746 				hvn_rndis_filter(sc, cph->cph_tid, cph);
747 				break;
748 			default:
749 				printf("%s: unhandled NVSP packet type %d "
750 				    "on receive\n", sc->sc_dev.dv_xname,
751 				    nvs->nvs_type);
752 			}
753 		} else
754 			printf("%s: unknown NVSP packet type %u\n",
755 			    sc->sc_dev.dv_xname, cph->cph_type);
756 	}
757 }
758 
759 int
760 hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid,
761     int timo)
762 {
763 	struct hvn_nvs_hdr *hdr = cmd;
764 	int tries = 10;
765 	int rv;
766 
767 	do {
768 		rv = hv_channel_send(sc->sc_chan, cmd, cmdsize,
769 		    tid, VMBUS_CHANPKT_TYPE_INBAND,
770 		    timo ? VMBUS_CHANPKT_FLAG_RC : 0);
771 		if (rv == EAGAIN) {
772 			if (timo)
773 				tsleep(cmd, PRIBIO, "hvnsend", timo / 10);
774 			else
775 				delay(100);
776 		} else if (rv) {
777 			DPRINTF("%s: NVSP operation %d send error %d\n",
778 			    sc->sc_dev.dv_xname, hdr->nvs_type, rv);
779 			return (rv);
780 		}
781 	} while (rv != 0 && --tries > 0);
782 
783 	if (timo) {
784 		mtx_enter(&sc->sc_nvslck);
785 		rv = msleep(&sc->sc_nvsrsp, &sc->sc_nvslck, PRIBIO, "hvnvsp",
786 		    timo);
787 		mtx_leave(&sc->sc_nvslck);
788 #ifdef HVN_DEBUG
789 		switch (rv) {
790 		case EINTR:
791 			rv = 0;
792 			break;
793 		case EWOULDBLOCK:
794 			printf("%s: NVSP opertaion %d timed out\n",
795 			    sc->sc_dev.dv_xname, hdr->nvs_type);
796 		}
797 	}
798 #endif
799 	return (rv);
800 }
801 
802 int
803 hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid)
804 {
805 	struct hvn_nvs_rndis_ack cmd;
806 	int tries = 5;
807 	int rv;
808 
809 	cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK;
810 	cmd.nvs_status = HVN_NVS_STATUS_OK;
811 	do {
812 		rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd),
813 		    tid, VMBUS_CHANPKT_TYPE_COMP, 0);
814 		if (rv == EAGAIN)
815 			delay(100);
816 		else if (rv) {
817 			DPRINTF("%s: NVSP acknowledgement error %d\n",
818 			    sc->sc_dev.dv_xname, rv);
819 			return (rv);
820 		}
821 	} while (rv != 0 && --tries > 0);
822 	return (rv);
823 }
824 
825 void
826 hvn_nvs_detach(struct hvn_softc *sc)
827 {
828 	if (hv_channel_close(sc->sc_chan) == 0) {
829 		km_free(sc->sc_nvsbuf, HVN_NVS_BUFSIZE, &kv_any, &kp_zero);
830 		sc->sc_nvsbuf = NULL;
831 	}
832 }
833 
834 static inline struct rndis_cmd *
835 hvn_alloc_cmd(struct hvn_softc *sc)
836 {
837 	struct rndis_cmd *rc;
838 
839 	mtx_enter(&sc->sc_cntl_fqlck);
840 	while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
841 		msleep(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
842 		    PRIBIO, "hvnrr", 1);
843 	TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
844 	mtx_leave(&sc->sc_cntl_fqlck);
845 	return (rc);
846 }
847 
848 static inline void
849 hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
850 {
851 	mtx_enter(&sc->sc_cntl_sqlck);
852 	TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
853 	mtx_leave(&sc->sc_cntl_sqlck);
854 }
855 
856 static inline struct rndis_cmd *
857 hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
858 {
859 	struct rndis_cmd *rc;
860 
861 	mtx_enter(&sc->sc_cntl_sqlck);
862 	TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
863 		if (rc->rc_id == id) {
864 			TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
865 			break;
866 		}
867 	}
868 	mtx_leave(&sc->sc_cntl_sqlck);
869 	if (rc != NULL) {
870 		mtx_enter(&sc->sc_cntl_cqlck);
871 		TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
872 		mtx_leave(&sc->sc_cntl_cqlck);
873 	}
874 	return (rc);
875 }
876 
877 static inline int
878 hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
879 {
880 	struct rndis_cmd *rn;
881 
882 	mtx_enter(&sc->sc_cntl_sqlck);
883 	TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
884 		if (rn == rc) {
885 			TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
886 			mtx_leave(&sc->sc_cntl_sqlck);
887 			return (0);
888 		}
889 	}
890 	mtx_leave(&sc->sc_cntl_sqlck);
891 	return (-1);
892 }
893 
894 static inline void
895 hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
896 {
897 	memset(rc->rc_req, 0, sizeof(*rc->rc_req));
898 	memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
899 	memset(&rc->rc_msg, 0, sizeof(rc->rc_msg));
900 	mtx_enter(&sc->sc_cntl_fqlck);
901 	TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
902 	mtx_leave(&sc->sc_cntl_fqlck);
903 	wakeup(&sc->sc_cntl_fq);
904 }
905 
906 int
907 hvn_rndis_attach(struct hvn_softc *sc)
908 {
909 	struct rndis_init_req *req;
910 	struct rndis_init_comp *cmp;
911 	struct rndis_cmd *rc;
912 	int i, rv;
913 
914 	/* RNDIS control message queues */
915 	TAILQ_INIT(&sc->sc_cntl_sq);
916 	TAILQ_INIT(&sc->sc_cntl_cq);
917 	TAILQ_INIT(&sc->sc_cntl_fq);
918 	mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
919 	mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
920 	mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
921 
922 	for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
923 		rc = &sc->sc_cntl_msgs[i];
924 		if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
925 		    PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
926 			DPRINTF("%s: failed to create RNDIS command map\n",
927 			    sc->sc_dev.dv_xname);
928 			goto errout;
929 		}
930 		rc->rc_req = km_alloc(PAGE_SIZE, &kv_any, &kp_zero,
931 		    &kd_waitok);
932 		if (rc->rc_req == NULL) {
933 			DPRINTF("%s: failed to allocate RNDIS command\n",
934 			    sc->sc_dev.dv_xname);
935 			bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
936 			goto errout;
937 		}
938 		if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
939 		    PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
940 			DPRINTF("%s: failed to load RNDIS command map\n",
941 			    sc->sc_dev.dv_xname);
942 			km_free(rc->rc_req, PAGE_SIZE, &kv_any, &kp_zero);
943 			bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
944 			goto errout;
945 		}
946 		rc->rc_pfn = atop(rc->rc_dmap->dm_segs[0].ds_addr);
947 		mtx_init(&rc->rc_mtx, IPL_NET);
948 		TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
949 	}
950 
951 	rc = hvn_alloc_cmd(sc);
952 
953 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
954 	    BUS_DMASYNC_PREREAD);
955 
956 	rc->rc_req->msg_type = RNDIS_INITIALIZE_MSG;
957 	rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
958 	rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
959 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
960 	req = (struct rndis_init_req *)&rc->rc_req->msg;
961 	req->request_id = rc->rc_id;
962 	req->major_version = RNDIS_MAJOR_VERSION;
963 	req->minor_version = RNDIS_MINOR_VERSION;
964 	req->max_xfer_size = 2048; /* XXX */
965 
966 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
967 	    BUS_DMASYNC_PREWRITE);
968 
969 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
970 		DPRINTF("%s: INITIALIZE_MSG failed, error %u\n",
971 		    sc->sc_dev.dv_xname, rv);
972 		hvn_free_cmd(sc, rc);
973 		goto errout;
974 	}
975 	cmp = (struct rndis_init_comp *)&rc->rc_cmp.msg;
976 	if (cmp->status != RNDIS_STATUS_SUCCESS) {
977 		DPRINTF("%s: failed to init RNDIS, error %#x\n",
978 		    sc->sc_dev.dv_xname, cmp->status);
979 		hvn_free_cmd(sc, rc);
980 		goto errout;
981 	}
982 	DPRINTF("%s: RNDIS %u.%u\n", sc->sc_dev.dv_xname,
983 	    cmp->major_version, cmp->minor_version);
984 
985 	hvn_free_cmd(sc, rc);
986 
987 	return (0);
988 
989 errout:
990 	for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
991 		rc = &sc->sc_cntl_msgs[i];
992 		if (rc->rc_req == NULL)
993 			continue;
994 		TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
995 		km_free(rc->rc_req, PAGE_SIZE, &kv_any, &kp_zero);
996 		rc->rc_req = NULL;
997 		bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
998 	}
999 	return (-1);
1000 }
1001 
1002 int
1003 hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
1004 {
1005 	struct hvn_nvs_rndis *msg = &rc->rc_msg;
1006 	struct vmbus_gpa sgl[1];
1007 	int tries = 10;
1008 	int rv;
1009 
1010 	KASSERT(timo > 0);
1011 
1012 	msg->nvs_type = HVN_NVS_TYPE_RNDIS;
1013 	msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL;
1014 	msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1015 
1016 	sgl[0].gpa_page = rc->rc_pfn;
1017 	sgl[0].gpa_len = rc->rc_req->msg_len;
1018 	sgl[0].gpa_ofs = 0;
1019 
1020 	hvn_submit_cmd(sc, rc);
1021 
1022 	do {
1023 		rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg,
1024 		    sizeof(struct hvn_nvs_rndis), rc->rc_id);
1025 		if (rv == EAGAIN)
1026 			tsleep(rc, PRIBIO, "hvnsendbuf", timo / 10);
1027 		else if (rv) {
1028 			DPRINTF("%s: RNDIS operation %d send error %d\n",
1029 			    sc->sc_dev.dv_xname, rc->rc_req->msg_type, rv);
1030 			return (rv);
1031 		}
1032 	} while (rv != 0 && --tries > 0);
1033 
1034 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1035 	    BUS_DMASYNC_POSTWRITE);
1036 
1037 	mtx_enter(&rc->rc_mtx);
1038 	rv = msleep(rc, &rc->rc_mtx, PRIBIO, "rndisctl", timo);
1039 	mtx_leave(&rc->rc_mtx);
1040 
1041 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1042 	    BUS_DMASYNC_POSTREAD);
1043 
1044 #ifdef HVN_DEBUG
1045 	switch (rv) {
1046 	case EINTR:
1047 		rv = 0;
1048 		break;
1049 	case EWOULDBLOCK:
1050 		if (hvn_rollback_cmd(sc, rc)) {
1051 			/* failed to rollback? go for one sleep cycle */
1052 			tsleep(rc, PRIBIO, "rndisctl2", 1);
1053 			rv = 0;
1054 			break;
1055 		}
1056 		printf("%s: RNDIS opertaion %d timed out\n", sc->sc_dev.dv_xname,
1057 		    rc->rc_req->msg_type);
1058 	}
1059 #endif
1060 	return (rv);
1061 }
1062 
1063 void
1064 hvn_rndis_filter(struct hvn_softc *sc, uint64_t tid, void *arg)
1065 {
1066 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1067 	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1068 	struct vmbus_chanpkt_prplist *cp = arg;
1069 	uint32_t off, len, type;
1070 	int i;
1071 
1072 	if (sc->sc_rx_ring == NULL) {
1073 		DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
1074 		return;
1075 	}
1076 	for (i = 0; i < cp->cp_range_cnt; i++) {
1077 		off = cp->cp_range[i].gpa_ofs;
1078 		len = cp->cp_range[i].gpa_len;
1079 
1080 		KASSERT(off + len <= sc->sc_rx_size);
1081 		KASSERT(len >= RNDIS_HEADER_SIZE + 4);
1082 
1083 		memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
1084 		switch (type) {
1085 		/* data message */
1086 		case RNDIS_PACKET_MSG:
1087 			hvn_rndis_input(sc, (caddr_t)sc->sc_rx_ring +
1088 			    off, len, &ml);
1089 			break;
1090 		/* completion messages */
1091 		case RNDIS_INITIALIZE_CMPLT:
1092 		case RNDIS_QUERY_CMPLT:
1093 		case RNDIS_SET_CMPLT:
1094 		case RNDIS_RESET_CMPLT:
1095 		case RNDIS_KEEPALIVE_CMPLT:
1096 			hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
1097 			    off, len);
1098 			break;
1099 		/* notification message */
1100 		case RNDIS_INDICATE_STATUS_MSG:
1101 			hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
1102 			    off, len);
1103 			break;
1104 		default:
1105 			printf("%s: unhandled RNDIS message type %u\n",
1106 			    sc->sc_dev.dv_xname, type);
1107 		}
1108 	}
1109 	hvn_nvs_ack(sc, tid);
1110 
1111 	if (MBUF_LIST_FIRST(&ml))
1112 		if_input(ifp, &ml);
1113 }
1114 
1115 static inline struct mbuf *
1116 hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1117 {
1118 	struct mbuf *m;
1119 
1120 	if (len + ETHER_ALIGN <= MHLEN)
1121 		MGETHDR(m, M_NOWAIT, MT_DATA);
1122 	else
1123 		m = MCLGETI(NULL, M_NOWAIT, NULL, len + ETHER_ALIGN);
1124 	if (m == NULL)
1125 		return (NULL);
1126 	m->m_len = m->m_pkthdr.len = len;
1127 	m_adj(m, ETHER_ALIGN);
1128 
1129 	if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
1130 		m_freem(m);
1131 		return (NULL);
1132 	}
1133 
1134 	return (m);
1135 }
1136 
1137 void
1138 hvn_rndis_input(struct hvn_softc *sc, caddr_t buf, uint32_t len,
1139     struct mbuf_list *ml)
1140 {
1141 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1142 	struct rndis_pkt *pkt;
1143 	struct rndis_pkt_info *ppi;
1144 	struct rndis_tcp_ip_csum_info *csum;
1145 	struct ndis_8021q_info *vlan;
1146 	struct mbuf *m;
1147 
1148 	if (!(ifp->if_flags & IFF_RUNNING))
1149 		return;
1150 
1151 	if (len < RNDIS_HEADER_SIZE + sizeof(*pkt)) {
1152 		printf("%s: data packet too short: %u\n",
1153 		    sc->sc_dev.dv_xname, len);
1154 		return;
1155 	}
1156 
1157 	pkt = (struct rndis_pkt *)(buf + RNDIS_HEADER_SIZE);
1158 
1159 	if (pkt->data_offset + pkt->data_length > len) {
1160 		printf("%s: data packet out of bounds: %u@%u\n",
1161 		    sc->sc_dev.dv_xname, pkt->data_offset, pkt->data_length);
1162 		return;
1163 	}
1164 
1165 	if ((m = hvn_devget(sc, buf + RNDIS_HEADER_SIZE + pkt->data_offset,
1166 	    pkt->data_length)) == NULL) {
1167 		ifp->if_ierrors++;
1168 		return;
1169 	}
1170 
1171 	while (pkt->pkt_info_length > 0) {
1172 		if (pkt->pkt_info_offset + pkt->pkt_info_length > len) {
1173 			printf("%s: PPI out of bounds: %u@%u\n",
1174 			    sc->sc_dev.dv_xname, pkt->pkt_info_length,
1175 			    pkt->pkt_info_offset);
1176 			break;
1177 		}
1178 		ppi = (struct rndis_pkt_info *)((caddr_t)pkt +
1179 		    pkt->pkt_info_offset);
1180 		if (ppi->size > pkt->pkt_info_length) {
1181 			printf("%s: invalid PPI size: %u/%u\n",
1182 			    sc->sc_dev.dv_xname, ppi->size,
1183 			    pkt->pkt_info_length);
1184 			break;
1185 		}
1186 		switch (ppi->type) {
1187 		case tcpip_chksum_info:
1188 			csum = (struct rndis_tcp_ip_csum_info *)
1189 			    ((caddr_t)ppi + ppi->size);
1190 			if (csum->recv.ip_csum_succeeded)
1191 				m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1192 			if (csum->recv.tcp_csum_succeeded)
1193 				m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
1194 			if (csum->recv.udp_csum_succeeded)
1195 				m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
1196 			break;
1197 		case ieee_8021q_info:
1198 			vlan = (struct ndis_8021q_info *)
1199 			    ((caddr_t)ppi + ppi->size);
1200 #if NVLAN > 0
1201 			m->m_pkthdr.ether_vtag = vlan->vlan_id;
1202 			m->m_flags |= M_VLANTAG;
1203 #endif
1204 			break;
1205 		default:
1206 			DPRINTF("%s: unhandled PPI %u\n", sc->sc_dev.dv_xname,
1207 			    ppi->type);
1208 		}
1209 		pkt->pkt_info_length -= ppi->size;
1210 	}
1211 
1212 	ml_enqueue(ml, m);
1213 }
1214 
1215 void
1216 hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1217 {
1218 	struct rndis_cmd *rc;
1219 	uint32_t id;
1220 
1221 	memcpy(&id, buf + RNDIS_HEADER_SIZE, sizeof(id));
1222 	if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
1223 		if (len < rc->rc_cmplen)
1224 			printf("%s: RNDIS response %u too short: %u\n",
1225 			    sc->sc_dev.dv_xname, id, len);
1226 		else
1227 			memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
1228 		if (len > rc->rc_cmplen &&
1229 		    len - rc->rc_cmplen > HVN_RNDIS_CMPBUFSZ)
1230 			printf("%s: RNDIS response %u too large: %u\n",
1231 			    sc->sc_dev.dv_xname, id, len);
1232 		else if (len > rc->rc_cmplen)
1233 			memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
1234 			    len - rc->rc_cmplen);
1235 		wakeup_one(rc);
1236 	} else
1237 		DPRINTF("%s: failed to complete RNDIS request id %u\n",
1238 		    sc->sc_dev.dv_xname, id);
1239 }
1240 
1241 void
1242 hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1243 {
1244 	uint32_t sta;
1245 
1246 	memcpy(&sta, buf + RNDIS_HEADER_SIZE, sizeof(sta));
1247 	switch (sta) {
1248 	case RNDIS_STATUS_MEDIA_CONNECT:
1249 		sc->sc_link_state = LINK_STATE_UP;
1250 		break;
1251 	case RNDIS_STATUS_MEDIA_DISCONNECT:
1252 		sc->sc_link_state = LINK_STATE_DOWN;
1253 		break;
1254 	/* Ignore these */
1255 	case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
1256 		return;
1257 	default:
1258 		DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname, sta);
1259 		return;
1260 	}
1261 	KERNEL_LOCK();
1262 	hvn_link_status(sc);
1263 	KERNEL_UNLOCK();
1264 }
1265 
1266 int
1267 hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
1268 {
1269 	struct rndis_cmd *rc;
1270 	struct rndis_query_req *req;
1271 	struct rndis_query_comp *cmp;
1272 	size_t olength = *length;
1273 	int rv;
1274 
1275 	rc = hvn_alloc_cmd(sc);
1276 
1277 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1278 	    BUS_DMASYNC_PREREAD);
1279 
1280 	rc->rc_req->msg_type = RNDIS_QUERY_MSG;
1281 	rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
1282 	rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
1283 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1284 	req = (struct rndis_query_req *)&rc->rc_req->msg;
1285 	req->request_id = rc->rc_id;
1286 	req->oid = oid;
1287 	req->info_buffer_offset = sizeof(*req);
1288 
1289 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1290 	    BUS_DMASYNC_PREWRITE);
1291 
1292 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1293 		DPRINTF("%s: QUERY_MSG failed, error %d\n",
1294 		    sc->sc_dev.dv_xname, rv);
1295 		hvn_free_cmd(sc, rc);
1296 		return (rv);
1297 	}
1298 
1299 	cmp = (struct rndis_query_comp *)&rc->rc_cmp.msg;
1300 	switch (cmp->status) {
1301 	case RNDIS_STATUS_SUCCESS:
1302 		if (cmp->info_buffer_length > olength) {
1303 			rv = EINVAL;
1304 			break;
1305 		}
1306 		memcpy(res, rc->rc_cmpbuf, cmp->info_buffer_length);
1307 		*length = cmp->info_buffer_length;
1308 		break;
1309 	default:
1310 		*length = 0;
1311 		rv = EIO;
1312 	}
1313 
1314 	hvn_free_cmd(sc, rc);
1315 
1316 	return (rv);
1317 }
1318 
1319 int
1320 hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
1321 {
1322 	struct rndis_cmd *rc;
1323 	struct rndis_set_req *req;
1324 	struct rndis_set_comp *cmp;
1325 	int rv;
1326 
1327 	rc = hvn_alloc_cmd(sc);
1328 
1329 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1330 	    BUS_DMASYNC_PREREAD);
1331 
1332 	rc->rc_req->msg_type = RNDIS_SET_MSG;
1333 	rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req) + length;
1334 	rc->rc_cmplen = RNDIS_MESSAGE_SIZE(*cmp);
1335 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1336 	req = (struct rndis_set_req *)&rc->rc_req->msg;
1337 	memset(req, 0, sizeof(*req));
1338 	req->request_id = rc->rc_id;
1339 	req->oid = oid;
1340 	req->info_buffer_offset = sizeof(*req);
1341 
1342 	if (length > 0) {
1343 		KASSERT(sizeof(*req) + length < sizeof(struct rndis));
1344 		req->info_buffer_length = length;
1345 		memcpy((caddr_t)(req + 1), data, length);
1346 	}
1347 
1348 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1349 	    BUS_DMASYNC_PREWRITE);
1350 
1351 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1352 		DPRINTF("%s: SET_MSG failed, error %u\n",
1353 		    sc->sc_dev.dv_xname, rv);
1354 		hvn_free_cmd(sc, rc);
1355 		return (rv);
1356 	}
1357 
1358 	cmp = (struct rndis_set_comp *)&rc->rc_cmp.msg;
1359 	if (cmp->status != RNDIS_STATUS_SUCCESS)
1360 		rv = EIO;
1361 
1362 	hvn_free_cmd(sc, rc);
1363 
1364 	return (rv);
1365 }
1366 
1367 int
1368 hvn_rndis_open(struct hvn_softc *sc)
1369 {
1370 	uint32_t filter;
1371 	int rv;
1372 
1373 	if (sc->sc_promisc)
1374 		filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1375 	else
1376 		filter = NDIS_PACKET_TYPE_BROADCAST |
1377 		    NDIS_PACKET_TYPE_ALL_MULTICAST |
1378 		    NDIS_PACKET_TYPE_DIRECTED;
1379 
1380 	rv = hvn_rndis_set(sc, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
1381 	    &filter, sizeof(filter));
1382 	if (rv)
1383 		DPRINTF("%s: failed to set RNDIS filter to %#x\n",
1384 		    sc->sc_dev.dv_xname, filter);
1385 	return (rv);
1386 }
1387 
1388 int
1389 hvn_rndis_close(struct hvn_softc *sc)
1390 {
1391 	uint32_t filter = 0;
1392 	int rv;
1393 
1394 	rv = hvn_rndis_set(sc, RNDIS_OID_GEN_CURRENT_PACKET_FILTER,
1395 	    &filter, sizeof(filter));
1396 	if (rv)
1397 		DPRINTF("%s: failed to clear RNDIS filter\n",
1398 		    sc->sc_dev.dv_xname);
1399 	return (rv);
1400 }
1401 
1402 void
1403 hvn_rndis_detach(struct hvn_softc *sc)
1404 {
1405 	struct rndis_cmd *rc;
1406 	struct rndis_halt_req *req;
1407 	int rv;
1408 
1409 	rc = hvn_alloc_cmd(sc);
1410 
1411 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1412 	    BUS_DMASYNC_PREREAD);
1413 
1414 	rc->rc_req->msg_type = RNDIS_HALT_MSG;
1415 	rc->rc_req->msg_len = RNDIS_MESSAGE_SIZE(*req);
1416 	rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1417 	req = (struct rndis_halt_req *)&rc->rc_req->msg;
1418 	req->request_id = rc->rc_id;
1419 
1420 	bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1421 	    BUS_DMASYNC_PREWRITE);
1422 
1423 	if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0)
1424 		DPRINTF("%s: HALT_MSG failed, error %u\n",
1425 		    sc->sc_dev.dv_xname, rv);
1426 
1427 	hvn_free_cmd(sc, rc);
1428 }
1429