Line data Source code
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 0 : hvn_match(struct device *parent, void *match, void *aux)
225 : {
226 0 : struct hv_attach_args *aa = aux;
227 :
228 0 : if (strcmp("network", aa->aa_ident))
229 0 : return (0);
230 :
231 0 : return (1);
232 0 : }
233 :
234 : void
235 0 : hvn_attach(struct device *parent, struct device *self, void *aux)
236 : {
237 0 : struct hv_attach_args *aa = aux;
238 0 : struct hvn_softc *sc = (struct hvn_softc *)self;
239 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
240 :
241 0 : sc->sc_hvsc = (struct hv_softc *)parent;
242 0 : sc->sc_chan = aa->aa_chan;
243 0 : sc->sc_dmat = aa->aa_dmat;
244 :
245 0 : strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
246 :
247 0 : printf(" channel %u", sc->sc_chan->ch_id);
248 :
249 0 : if (hvn_nvs_attach(sc)) {
250 0 : printf(": failed to init NVSP\n");
251 0 : return;
252 : }
253 :
254 0 : if (hvn_rx_ring_create(sc)) {
255 0 : printf(": failed to create Rx ring\n");
256 0 : goto detach;
257 : }
258 :
259 0 : if (hvn_tx_ring_create(sc)) {
260 0 : printf(": failed to create Tx ring\n");
261 0 : goto detach;
262 : }
263 :
264 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
265 0 : ifp->if_xflags = IFXF_MPSAFE;
266 0 : ifp->if_ioctl = hvn_ioctl;
267 0 : ifp->if_qstart = hvn_start;
268 0 : ifp->if_softc = sc;
269 :
270 0 : ifp->if_capabilities = IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
271 : IFCAP_CSUM_TCPv6;
272 0 : if (sc->sc_ndisver > NDIS_VERSION_6_30)
273 0 : ifp->if_capabilities |= IFCAP_CSUM_UDPv4 | IFCAP_CSUM_UDPv6;
274 :
275 0 : if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
276 0 : ifp->if_hardmtu = HVN_MAXMTU;
277 : #if NVLAN > 0
278 0 : ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU;
279 : #endif
280 0 : }
281 :
282 0 : IFQ_SET_MAXLEN(&ifp->if_snd, HVN_TX_DESC - 1);
283 :
284 0 : ifmedia_init(&sc->sc_media, IFM_IMASK, hvn_media_change,
285 : hvn_media_status);
286 0 : ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
287 0 : ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
288 :
289 0 : if_attach(ifp);
290 :
291 0 : if (hvn_rndis_attach(sc)) {
292 0 : printf(": failed to init RNDIS\n");
293 0 : goto detach;
294 : }
295 :
296 0 : printf(": NVS %d.%d NDIS %d.%d", sc->sc_proto >> 16,
297 0 : sc->sc_proto & 0xffff, sc->sc_ndisver >> 16 ,
298 0 : sc->sc_ndisver & 0xffff);
299 :
300 0 : if (hvn_set_capabilities(sc)) {
301 0 : printf(": failed to setup offloading\n");
302 0 : hvn_rndis_detach(sc);
303 0 : goto detach;
304 : }
305 :
306 0 : if (hvn_get_lladdr(sc)) {
307 0 : printf(": failed to obtain an ethernet address\n");
308 0 : hvn_rndis_detach(sc);
309 0 : goto detach;
310 : }
311 :
312 0 : printf(", address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));
313 :
314 0 : ether_ifattach(ifp);
315 0 : return;
316 :
317 : detach:
318 0 : hvn_rx_ring_destroy(sc);
319 0 : hvn_tx_ring_destroy(sc);
320 0 : hvn_nvs_detach(sc);
321 0 : if (ifp->if_qstart)
322 0 : if_detach(ifp);
323 0 : }
324 :
325 : int
326 0 : hvn_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
327 : {
328 0 : struct hvn_softc *sc = ifp->if_softc;
329 0 : struct ifreq *ifr = (struct ifreq *)data;
330 : int s, error = 0;
331 :
332 0 : s = splnet();
333 :
334 0 : switch (command) {
335 : case SIOCSIFADDR:
336 0 : ifp->if_flags |= IFF_UP;
337 0 : if (!(ifp->if_flags & IFF_RUNNING))
338 0 : hvn_init(sc);
339 : break;
340 : case SIOCSIFFLAGS:
341 0 : if (ifp->if_flags & IFF_UP) {
342 0 : if (ifp->if_flags & IFF_RUNNING)
343 0 : error = ENETRESET;
344 : else
345 0 : hvn_init(sc);
346 : } else {
347 0 : if (ifp->if_flags & IFF_RUNNING)
348 0 : hvn_stop(sc);
349 : }
350 : break;
351 : case SIOCGIFMEDIA:
352 : case SIOCSIFMEDIA:
353 0 : error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
354 0 : break;
355 : default:
356 0 : error = ether_ioctl(ifp, &sc->sc_ac, command, data);
357 0 : }
358 :
359 0 : if (error == ENETRESET) {
360 0 : if (ifp->if_flags & IFF_RUNNING)
361 0 : hvn_iff(sc);
362 : error = 0;
363 0 : }
364 :
365 0 : splx(s);
366 :
367 0 : return (error);
368 : }
369 :
370 : int
371 0 : hvn_media_change(struct ifnet *ifp)
372 : {
373 0 : return (0);
374 : }
375 :
376 : void
377 0 : hvn_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
378 : {
379 0 : struct hvn_softc *sc = ifp->if_softc;
380 :
381 0 : hvn_get_link_status(sc);
382 0 : hvn_link_status(sc);
383 :
384 0 : ifmr->ifm_status = IFM_AVALID;
385 0 : ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
386 0 : if (sc->sc_link_state == LINK_STATE_UP)
387 0 : ifmr->ifm_status |= IFM_ACTIVE;
388 0 : }
389 :
390 : void
391 0 : hvn_link_status(struct hvn_softc *sc)
392 : {
393 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
394 :
395 0 : if (sc->sc_link_state != ifp->if_link_state) {
396 0 : ifp->if_link_state = sc->sc_link_state;
397 0 : if_link_state_change(ifp);
398 0 : }
399 0 : }
400 :
401 : int
402 0 : hvn_iff(struct hvn_softc *sc)
403 : {
404 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
405 0 : uint32_t filter = 0;
406 : int rv;
407 :
408 0 : ifp->if_flags &= ~IFF_ALLMULTI;
409 :
410 0 : if ((ifp->if_flags & IFF_PROMISC) || sc->sc_ac.ac_multirangecnt > 0) {
411 0 : ifp->if_flags |= IFF_ALLMULTI;
412 0 : filter = NDIS_PACKET_TYPE_PROMISCUOUS;
413 0 : } else {
414 0 : filter = NDIS_PACKET_TYPE_BROADCAST |
415 : NDIS_PACKET_TYPE_DIRECTED;
416 0 : if (sc->sc_ac.ac_multicnt > 0) {
417 0 : ifp->if_flags |= IFF_ALLMULTI;
418 0 : filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
419 0 : }
420 : }
421 :
422 0 : 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 0 : return (rv);
428 0 : }
429 :
430 : void
431 0 : hvn_init(struct hvn_softc *sc)
432 : {
433 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
434 :
435 0 : hvn_stop(sc);
436 :
437 0 : if (hvn_iff(sc) == 0) {
438 0 : ifp->if_flags |= IFF_RUNNING;
439 0 : ifq_clr_oactive(&ifp->if_snd);
440 0 : }
441 0 : }
442 :
443 : void
444 0 : hvn_stop(struct hvn_softc *sc)
445 : {
446 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
447 :
448 0 : if (ifp->if_flags & IFF_RUNNING) {
449 0 : ifp->if_flags &= ~IFF_RUNNING;
450 0 : hvn_rndis_close(sc);
451 0 : }
452 :
453 0 : ifq_barrier(&ifp->if_snd);
454 0 : intr_barrier(sc->sc_chan);
455 :
456 0 : ifq_clr_oactive(&ifp->if_snd);
457 0 : }
458 :
459 : void
460 0 : hvn_start(struct ifqueue *ifq)
461 : {
462 0 : struct ifnet *ifp = ifq->ifq_if;
463 0 : struct hvn_softc *sc = ifp->if_softc;
464 0 : struct hvn_tx_desc *txd;
465 : struct mbuf *m;
466 :
467 0 : for (;;) {
468 0 : if (!sc->sc_tx_avail) {
469 : /* transient */
470 0 : ifq_set_oactive(ifq);
471 0 : break;
472 : }
473 :
474 0 : m = ifq_dequeue(ifq);
475 0 : if (m == NULL)
476 : break;
477 :
478 0 : if (hvn_encap(sc, m, &txd)) {
479 : /* the chain is too large */
480 0 : ifp->if_oerrors++;
481 0 : m_freem(m);
482 0 : continue;
483 : }
484 :
485 : #if NBPFILTER > 0
486 0 : if (ifp->if_bpf)
487 0 : bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
488 : #endif
489 :
490 0 : if (hvn_rndis_output(sc, txd)) {
491 0 : hvn_decap(sc, txd);
492 0 : ifp->if_oerrors++;
493 0 : m_freem(m);
494 0 : continue;
495 : }
496 :
497 0 : sc->sc_tx_next++;
498 : }
499 0 : }
500 :
501 : static inline char *
502 0 : 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 0 : size_t pi_size = sizeof(*pi) + datalen;
507 : char *cp;
508 :
509 0 : KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <=
510 : pktsize);
511 :
512 0 : cp = (char *)pkt + pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
513 0 : pi = (struct rndis_pktinfo *)cp;
514 0 : pi->rm_size = pi_size;
515 0 : pi->rm_type = type;
516 0 : pi->rm_pktinfooffset = sizeof(*pi);
517 0 : pkt->rm_pktinfolen += pi_size;
518 0 : pkt->rm_dataoffset += pi_size;
519 0 : pkt->rm_len += pi_size;
520 0 : return ((char *)pi->rm_data);
521 : }
522 :
523 : int
524 0 : 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 0 : do {
533 0 : txd = &sc->sc_tx_desc[sc->sc_tx_next % HVN_TX_DESC];
534 0 : sc->sc_tx_next++;
535 0 : } while (!txd->txd_ready);
536 0 : txd->txd_ready = 0;
537 :
538 0 : pkt = txd->txd_req;
539 0 : memset(pkt, 0, HVN_RNDIS_PKT_LEN);
540 0 : pkt->rm_type = REMOTE_NDIS_PACKET_MSG;
541 0 : pkt->rm_len = sizeof(*pkt) + m->m_pkthdr.len;
542 0 : pkt->rm_dataoffset = RNDIS_DATA_OFFSET;
543 0 : pkt->rm_datalen = m->m_pkthdr.len;
544 0 : pkt->rm_pktinfooffset = sizeof(*pkt); /* adjusted below */
545 0 : pkt->rm_pktinfolen = 0;
546 :
547 0 : rv = bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m, BUS_DMA_READ |
548 : BUS_DMA_NOWAIT);
549 0 : switch (rv) {
550 : case 0:
551 : break;
552 : case EFBIG:
553 0 : if (m_defrag(m, M_NOWAIT) == 0 &&
554 0 : bus_dmamap_load_mbuf(sc->sc_dmat, txd->txd_dmap, m,
555 0 : 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 0 : return (-1);
561 : }
562 0 : txd->txd_buf = m;
563 :
564 : #if NVLAN > 0
565 0 : if (m->m_flags & M_VLANTAG) {
566 : uint32_t vlan;
567 : char *cp;
568 :
569 0 : vlan = NDIS_VLAN_INFO(EVL_VLANOFTAG(m->m_pkthdr.ether_vtag),
570 : EVL_PRIOFTAG(m->m_pkthdr.ether_vtag));
571 0 : cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
572 : NDIS_VLAN_INFO_SIZE, NDIS_PKTINFO_TYPE_VLAN);
573 0 : memcpy(cp, &vlan, NDIS_VLAN_INFO_SIZE);
574 0 : }
575 : #endif
576 :
577 0 : 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 0 : if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
583 0 : csum |= NDIS_TXCSUM_INFO_IPCS;
584 0 : if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
585 0 : csum |= NDIS_TXCSUM_INFO_TCPCS;
586 0 : if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
587 0 : csum |= NDIS_TXCSUM_INFO_UDPCS;
588 0 : cp = hvn_rndis_pktinfo_append(pkt, HVN_RNDIS_PKT_LEN,
589 : NDIS_TXCSUM_INFO_SIZE, NDIS_PKTINFO_TYPE_CSUM);
590 0 : memcpy(cp, &csum, NDIS_TXCSUM_INFO_SIZE);
591 0 : }
592 :
593 0 : pktlen = pkt->rm_pktinfooffset + pkt->rm_pktinfolen;
594 0 : pkt->rm_pktinfooffset -= RNDIS_HEADER_OFFSET;
595 :
596 : /* Attach an RNDIS message to the first slot */
597 0 : txd->txd_sgl[0].gpa_page = txd->txd_gpa.gpa_page;
598 0 : txd->txd_sgl[0].gpa_ofs = txd->txd_gpa.gpa_ofs;
599 0 : txd->txd_sgl[0].gpa_len = pktlen;
600 0 : txd->txd_nsge = txd->txd_dmap->dm_nsegs + 1;
601 :
602 0 : for (i = 0; i < txd->txd_dmap->dm_nsegs; i++) {
603 0 : seg = &txd->txd_dmap->dm_segs[i];
604 0 : txd->txd_sgl[1 + i].gpa_page = atop(seg->ds_addr);
605 0 : txd->txd_sgl[1 + i].gpa_ofs = seg->ds_addr & PAGE_MASK;
606 0 : txd->txd_sgl[1 + i].gpa_len = seg->ds_len;
607 : }
608 :
609 0 : *txd0 = txd;
610 :
611 0 : atomic_dec_int(&sc->sc_tx_avail);
612 :
613 0 : return (0);
614 0 : }
615 :
616 : void
617 0 : hvn_decap(struct hvn_softc *sc, struct hvn_tx_desc *txd)
618 : {
619 0 : bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
620 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
621 0 : bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
622 0 : txd->txd_buf = NULL;
623 0 : txd->txd_nsge = 0;
624 0 : txd->txd_ready = 1;
625 0 : atomic_inc_int(&sc->sc_tx_avail);
626 0 : }
627 :
628 : void
629 0 : hvn_txeof(struct hvn_softc *sc, uint64_t tid)
630 : {
631 : struct hvn_tx_desc *txd;
632 : struct mbuf *m;
633 0 : uint32_t id = tid >> 32;
634 :
635 0 : if ((tid & 0xffffffffU) != 0)
636 0 : return;
637 0 : id -= HVN_NVS_CHIM_SIG;
638 0 : if (id >= HVN_TX_DESC)
639 0 : panic("tx packet index too large: %u", id);
640 :
641 0 : txd = &sc->sc_tx_desc[id];
642 :
643 0 : if ((m = txd->txd_buf) == NULL)
644 0 : panic("%s: no mbuf @%u\n", sc->sc_dev.dv_xname, id);
645 0 : txd->txd_buf = NULL;
646 :
647 0 : bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
648 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
649 0 : bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
650 0 : m_freem(m);
651 :
652 0 : txd->txd_ready = 1;
653 :
654 0 : atomic_inc_int(&sc->sc_tx_avail);
655 :
656 0 : }
657 :
658 : int
659 0 : hvn_rx_ring_create(struct hvn_softc *sc)
660 : {
661 0 : struct hvn_nvs_rxbuf_conn cmd;
662 : struct hvn_nvs_rxbuf_conn_resp *rsp;
663 : uint64_t tid;
664 :
665 0 : if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_2)
666 0 : sc->sc_rx_size = 15 * 1024 * 1024; /* 15MB */
667 : else
668 0 : sc->sc_rx_size = 16 * 1024 * 1024; /* 16MB */
669 0 : sc->sc_rx_ring = km_alloc(sc->sc_rx_size, &kv_any, &kp_zero,
670 0 : cold ? &kd_nowait : &kd_waitok);
671 0 : if (sc->sc_rx_ring == NULL) {
672 : DPRINTF("%s: failed to allocate Rx ring buffer\n",
673 : sc->sc_dev.dv_xname);
674 0 : return (-1);
675 : }
676 0 : if (hv_handle_alloc(sc->sc_chan, sc->sc_rx_ring, sc->sc_rx_size,
677 0 : &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 0 : memset(&cmd, 0, sizeof(cmd));
684 0 : cmd.nvs_type = HVN_NVS_TYPE_RXBUF_CONN;
685 0 : cmd.nvs_gpadl = sc->sc_rx_hndl;
686 0 : cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
687 :
688 0 : tid = atomic_inc_int_nv(&sc->sc_nvstid);
689 0 : if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
690 : goto errout;
691 :
692 0 : rsp = (struct hvn_nvs_rxbuf_conn_resp *)&sc->sc_nvsrsp;
693 0 : 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 0 : 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 0 : hvn_rx_ring_destroy(sc);
702 0 : return (-1);
703 : }
704 0 : return (0);
705 :
706 : errout:
707 0 : if (sc->sc_rx_hndl) {
708 0 : hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
709 0 : sc->sc_rx_hndl = 0;
710 0 : }
711 0 : if (sc->sc_rx_ring) {
712 0 : km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
713 0 : sc->sc_rx_ring = NULL;
714 0 : }
715 0 : return (-1);
716 0 : }
717 :
718 : int
719 0 : hvn_rx_ring_destroy(struct hvn_softc *sc)
720 : {
721 0 : struct hvn_nvs_rxbuf_disconn cmd;
722 : uint64_t tid;
723 :
724 0 : if (sc->sc_rx_ring == NULL)
725 0 : return (0);
726 :
727 0 : memset(&cmd, 0, sizeof(cmd));
728 0 : cmd.nvs_type = HVN_NVS_TYPE_RXBUF_DISCONN;
729 0 : cmd.nvs_sig = HVN_NVS_RXBUF_SIG;
730 :
731 0 : tid = atomic_inc_int_nv(&sc->sc_nvstid);
732 0 : if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 0))
733 0 : return (-1);
734 :
735 0 : delay(100);
736 :
737 0 : hv_handle_free(sc->sc_chan, sc->sc_rx_hndl);
738 :
739 0 : sc->sc_rx_hndl = 0;
740 :
741 0 : km_free(sc->sc_rx_ring, sc->sc_rx_size, &kv_any, &kp_zero);
742 0 : sc->sc_rx_ring = NULL;
743 :
744 0 : return (0);
745 0 : }
746 :
747 : int
748 0 : 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 0 : 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 0 : 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 0 : 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 0 : 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 0 : 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 0 : for (i = 0; i < HVN_TX_DESC; i++) {
785 0 : txd = &sc->sc_tx_desc[i];
786 0 : 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 0 : seg = &sc->sc_tx_rmap->dm_segs[0];
794 0 : pa = seg->ds_addr + (msgsize * i);
795 0 : txd->txd_gpa.gpa_page = atop(pa);
796 0 : txd->txd_gpa.gpa_ofs = pa & PAGE_MASK;
797 0 : txd->txd_gpa.gpa_len = msgsize;
798 0 : txd->txd_req = (void *)((caddr_t)sc->sc_tx_msgs +
799 : (msgsize * i));
800 0 : txd->txd_id = i + HVN_NVS_CHIM_SIG;
801 0 : txd->txd_ready = 1;
802 : }
803 0 : sc->sc_tx_avail = HVN_TX_DESC;
804 :
805 0 : return (0);
806 :
807 : errout:
808 0 : hvn_tx_ring_destroy(sc);
809 0 : return (-1);
810 0 : }
811 :
812 : void
813 0 : hvn_tx_ring_destroy(struct hvn_softc *sc)
814 : {
815 : struct hvn_tx_desc *txd;
816 : int i;
817 :
818 0 : for (i = 0; i < HVN_TX_DESC; i++) {
819 0 : txd = &sc->sc_tx_desc[i];
820 0 : if (txd->txd_dmap == NULL)
821 : continue;
822 0 : bus_dmamap_sync(sc->sc_dmat, txd->txd_dmap, 0, 0,
823 : BUS_DMASYNC_POSTWRITE);
824 0 : bus_dmamap_unload(sc->sc_dmat, txd->txd_dmap);
825 0 : bus_dmamap_destroy(sc->sc_dmat, txd->txd_dmap);
826 0 : txd->txd_dmap = NULL;
827 0 : if (txd->txd_buf == NULL)
828 : continue;
829 0 : m_free(txd->txd_buf);
830 0 : txd->txd_buf = NULL;
831 0 : }
832 0 : if (sc->sc_tx_rmap) {
833 0 : bus_dmamap_sync(sc->sc_dmat, sc->sc_tx_rmap, 0, 0,
834 : BUS_DMASYNC_POSTWRITE);
835 0 : bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
836 0 : bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
837 0 : }
838 0 : if (sc->sc_tx_msgs) {
839 : size_t msgsize = roundup(HVN_RNDIS_PKT_LEN, 128);
840 :
841 0 : bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_msgs,
842 : msgsize * HVN_TX_DESC);
843 0 : bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_mseg, 1);
844 0 : }
845 0 : sc->sc_tx_rmap = NULL;
846 0 : sc->sc_tx_msgs = NULL;
847 0 : }
848 :
849 : int
850 0 : hvn_get_lladdr(struct hvn_softc *sc)
851 : {
852 0 : char enaddr[ETHER_ADDR_LEN];
853 0 : size_t addrlen = ETHER_ADDR_LEN;
854 : int rv;
855 :
856 0 : rv = hvn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS,
857 0 : enaddr, &addrlen);
858 0 : if (rv == 0 && addrlen == ETHER_ADDR_LEN)
859 0 : memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
860 0 : return (rv);
861 0 : }
862 :
863 : int
864 0 : hvn_set_lladdr(struct hvn_softc *sc)
865 : {
866 0 : return (hvn_rndis_set(sc, OID_802_3_CURRENT_ADDRESS,
867 0 : sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN));
868 : }
869 :
870 : void
871 0 : hvn_get_link_status(struct hvn_softc *sc)
872 : {
873 0 : uint32_t state;
874 0 : size_t len = sizeof(state);
875 :
876 0 : if (hvn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS,
877 0 : &state, &len) == 0)
878 0 : sc->sc_link_state = (state == NDIS_MEDIA_STATE_CONNECTED) ?
879 : LINK_STATE_UP : LINK_STATE_DOWN;
880 0 : }
881 :
882 : int
883 0 : 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 0 : struct hvn_nvs_init cmd;
890 : struct hvn_nvs_init_resp *rsp;
891 0 : struct hvn_nvs_ndis_init ncmd;
892 0 : struct hvn_nvs_ndis_conf ccmd;
893 : uint32_t ndisver, ringsize;
894 : uint64_t tid;
895 : int i;
896 :
897 0 : sc->sc_nvsbuf = malloc(HVN_NVS_BUFSIZE, M_DEVBUF, M_ZERO |
898 0 : (cold ? M_NOWAIT : M_WAITOK));
899 0 : if (sc->sc_nvsbuf == NULL) {
900 : DPRINTF("%s: failed to allocate channel data buffer\n",
901 : sc->sc_dev.dv_xname);
902 0 : 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 0 : sc->sc_chan->ch_flags &= ~CHF_BATCHED;
912 :
913 : /* Associate our interrupt handler with the channel */
914 0 : if (hv_channel_open(sc->sc_chan, ringsize, NULL, 0,
915 0 : hvn_nvs_intr, sc)) {
916 : DPRINTF("%s: failed to open channel\n", sc->sc_dev.dv_xname);
917 0 : free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
918 0 : return (-1);
919 : }
920 :
921 0 : hv_evcount_attach(sc->sc_chan, sc->sc_dev.dv_xname);
922 :
923 0 : memset(&cmd, 0, sizeof(cmd));
924 0 : cmd.nvs_type = HVN_NVS_TYPE_INIT;
925 0 : for (i = 0; i < nitems(protos); i++) {
926 0 : cmd.nvs_ver_min = cmd.nvs_ver_max = protos[i];
927 0 : tid = atomic_inc_int_nv(&sc->sc_nvstid);
928 0 : if (hvn_nvs_cmd(sc, &cmd, sizeof(cmd), tid, 100))
929 0 : return (-1);
930 0 : rsp = (struct hvn_nvs_init_resp *)&sc->sc_nvsrsp;
931 0 : if (rsp->nvs_status == HVN_NVS_STATUS_OK) {
932 0 : sc->sc_proto = protos[i];
933 0 : break;
934 : }
935 : }
936 0 : if (!sc->sc_proto) {
937 : DPRINTF("%s: failed to negotiate NVSP version\n",
938 : sc->sc_dev.dv_xname);
939 0 : return (-1);
940 : }
941 :
942 0 : if (sc->sc_proto >= HVN_NVS_PROTO_VERSION_2) {
943 0 : memset(&ccmd, 0, sizeof(ccmd));
944 0 : ccmd.nvs_type = HVN_NVS_TYPE_NDIS_CONF;
945 0 : ccmd.nvs_mtu = HVN_MAXMTU;
946 0 : ccmd.nvs_caps = HVN_NVS_NDIS_CONF_VLAN;
947 :
948 0 : tid = atomic_inc_int_nv(&sc->sc_nvstid);
949 0 : if (hvn_nvs_cmd(sc, &ccmd, sizeof(ccmd), tid, 100))
950 0 : return (-1);
951 : }
952 :
953 0 : memset(&ncmd, 0, sizeof(ncmd));
954 0 : ncmd.nvs_type = HVN_NVS_TYPE_NDIS_INIT;
955 0 : if (sc->sc_proto <= HVN_NVS_PROTO_VERSION_4)
956 0 : ndisver = NDIS_VERSION_6_1;
957 : else
958 : ndisver = NDIS_VERSION_6_30;
959 0 : ncmd.nvs_ndis_major = (ndisver & 0xffff0000) >> 16;
960 0 : ncmd.nvs_ndis_minor = (ndisver & 0x0000ffff);
961 :
962 0 : tid = atomic_inc_int_nv(&sc->sc_nvstid);
963 0 : if (hvn_nvs_cmd(sc, &ncmd, sizeof(ncmd), tid, 100))
964 0 : return (-1);
965 :
966 0 : sc->sc_ndisver = ndisver;
967 :
968 0 : return (0);
969 0 : }
970 :
971 : void
972 0 : hvn_nvs_intr(void *arg)
973 : {
974 0 : struct hvn_softc *sc = arg;
975 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
976 : struct vmbus_chanpkt_hdr *cph;
977 : struct hvn_nvs_hdr *nvs;
978 0 : uint64_t rid;
979 0 : uint32_t rlen;
980 : int rv;
981 :
982 0 : for (;;) {
983 0 : rv = hv_channel_recv(sc->sc_chan, sc->sc_nvsbuf,
984 : HVN_NVS_BUFSIZE, &rlen, &rid, 1);
985 0 : if (rv != 0 || rlen == 0) {
986 0 : if (rv != EAGAIN)
987 0 : printf("%s: failed to receive an NVSP "
988 0 : "packet\n", sc->sc_dev.dv_xname);
989 : break;
990 : }
991 0 : cph = (struct vmbus_chanpkt_hdr *)sc->sc_nvsbuf;
992 0 : nvs = (struct hvn_nvs_hdr *)VMBUS_CHANPKT_CONST_DATA(cph);
993 :
994 0 : if (cph->cph_type == VMBUS_CHANPKT_TYPE_COMP) {
995 0 : 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 0 : memcpy(&sc->sc_nvsrsp, nvs, HVN_NVS_MSGSIZE);
1002 0 : sc->sc_nvsdone = 1;
1003 0 : wakeup_one(&sc->sc_nvsrsp);
1004 0 : break;
1005 : case HVN_NVS_TYPE_RNDIS_ACK:
1006 0 : hvn_txeof(sc, cph->cph_tid);
1007 0 : break;
1008 : default:
1009 0 : printf("%s: unhandled NVSP packet type %u "
1010 0 : "on completion\n", sc->sc_dev.dv_xname,
1011 : nvs->nvs_type);
1012 0 : }
1013 0 : } else if (cph->cph_type == VMBUS_CHANPKT_TYPE_RXBUF) {
1014 0 : switch (nvs->nvs_type) {
1015 : case HVN_NVS_TYPE_RNDIS:
1016 0 : hvn_rndis_input(sc, cph->cph_tid, cph);
1017 0 : break;
1018 : default:
1019 0 : printf("%s: unhandled NVSP packet type %u "
1020 0 : "on receive\n", sc->sc_dev.dv_xname,
1021 : nvs->nvs_type);
1022 0 : }
1023 : } else
1024 0 : printf("%s: unknown NVSP packet type %u\n",
1025 0 : sc->sc_dev.dv_xname, cph->cph_type);
1026 : }
1027 :
1028 0 : if (ifq_is_oactive(&ifp->if_snd))
1029 0 : ifq_restart(&ifp->if_snd);
1030 0 : }
1031 :
1032 : int
1033 0 : hvn_nvs_cmd(struct hvn_softc *sc, void *cmd, size_t cmdsize, uint64_t tid,
1034 : int timo)
1035 : {
1036 0 : struct hvn_nvs_hdr *hdr = cmd;
1037 : int tries = 10;
1038 : int rv, s;
1039 :
1040 0 : KERNEL_ASSERT_LOCKED();
1041 :
1042 0 : sc->sc_nvsdone = 0;
1043 :
1044 0 : do {
1045 0 : rv = hv_channel_send(sc->sc_chan, cmd, cmdsize,
1046 : tid, VMBUS_CHANPKT_TYPE_INBAND,
1047 0 : timo ? VMBUS_CHANPKT_FLAG_RC : 0);
1048 0 : if (rv == EAGAIN) {
1049 0 : if (cold)
1050 0 : delay(1000);
1051 : else
1052 0 : tsleep(cmd, PRIBIO, "nvsout", 1);
1053 0 : } else if (rv) {
1054 : DPRINTF("%s: NVSP operation %u send error %d\n",
1055 : sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1056 0 : return (rv);
1057 : }
1058 0 : } while (rv != 0 && --tries > 0);
1059 :
1060 0 : if (tries == 0 && rv != 0) {
1061 0 : printf("%s: NVSP operation %u send error %d\n",
1062 0 : sc->sc_dev.dv_xname, hdr->nvs_type, rv);
1063 0 : return (rv);
1064 : }
1065 :
1066 0 : if (timo == 0)
1067 0 : return (0);
1068 :
1069 0 : do {
1070 0 : if (cold)
1071 0 : delay(1000);
1072 : else
1073 0 : tsleep(sc, PRIBIO | PCATCH, "nvscmd", 1);
1074 0 : s = splnet();
1075 0 : hvn_nvs_intr(sc);
1076 0 : splx(s);
1077 0 : } while (--timo > 0 && sc->sc_nvsdone != 1);
1078 :
1079 0 : if (timo == 0 && sc->sc_nvsdone != 1) {
1080 0 : printf("%s: NVSP operation %u timed out\n",
1081 0 : sc->sc_dev.dv_xname, hdr->nvs_type);
1082 0 : return (ETIMEDOUT);
1083 : }
1084 0 : return (0);
1085 0 : }
1086 :
1087 : int
1088 0 : hvn_nvs_ack(struct hvn_softc *sc, uint64_t tid)
1089 : {
1090 0 : struct hvn_nvs_rndis_ack cmd;
1091 : int tries = 5;
1092 : int rv;
1093 :
1094 0 : cmd.nvs_type = HVN_NVS_TYPE_RNDIS_ACK;
1095 0 : cmd.nvs_status = HVN_NVS_STATUS_OK;
1096 0 : do {
1097 0 : rv = hv_channel_send(sc->sc_chan, &cmd, sizeof(cmd),
1098 : tid, VMBUS_CHANPKT_TYPE_COMP, 0);
1099 0 : if (rv == EAGAIN)
1100 0 : delay(10);
1101 0 : else if (rv) {
1102 : DPRINTF("%s: NVSP acknowledgement error %d\n",
1103 : sc->sc_dev.dv_xname, rv);
1104 0 : return (rv);
1105 : }
1106 0 : } while (rv != 0 && --tries > 0);
1107 0 : return (rv);
1108 0 : }
1109 :
1110 : void
1111 0 : hvn_nvs_detach(struct hvn_softc *sc)
1112 : {
1113 0 : if (hv_channel_close(sc->sc_chan) == 0) {
1114 0 : free(sc->sc_nvsbuf, M_DEVBUF, HVN_NVS_BUFSIZE);
1115 0 : sc->sc_nvsbuf = NULL;
1116 0 : }
1117 0 : }
1118 :
1119 : static inline struct rndis_cmd *
1120 0 : hvn_alloc_cmd(struct hvn_softc *sc)
1121 : {
1122 : struct rndis_cmd *rc;
1123 :
1124 0 : mtx_enter(&sc->sc_cntl_fqlck);
1125 0 : while ((rc = TAILQ_FIRST(&sc->sc_cntl_fq)) == NULL)
1126 0 : msleep(&sc->sc_cntl_fq, &sc->sc_cntl_fqlck,
1127 : PRIBIO, "nvsalloc", 1);
1128 0 : TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1129 0 : mtx_leave(&sc->sc_cntl_fqlck);
1130 0 : return (rc);
1131 : }
1132 :
1133 : static inline void
1134 0 : hvn_submit_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1135 : {
1136 0 : mtx_enter(&sc->sc_cntl_sqlck);
1137 0 : TAILQ_INSERT_TAIL(&sc->sc_cntl_sq, rc, rc_entry);
1138 0 : mtx_leave(&sc->sc_cntl_sqlck);
1139 0 : }
1140 :
1141 : static inline struct rndis_cmd *
1142 0 : hvn_complete_cmd(struct hvn_softc *sc, uint32_t id)
1143 : {
1144 : struct rndis_cmd *rc;
1145 :
1146 0 : mtx_enter(&sc->sc_cntl_sqlck);
1147 0 : TAILQ_FOREACH(rc, &sc->sc_cntl_sq, rc_entry) {
1148 0 : if (rc->rc_id == id) {
1149 0 : TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1150 0 : break;
1151 : }
1152 : }
1153 0 : mtx_leave(&sc->sc_cntl_sqlck);
1154 0 : if (rc != NULL) {
1155 0 : mtx_enter(&sc->sc_cntl_cqlck);
1156 0 : TAILQ_INSERT_TAIL(&sc->sc_cntl_cq, rc, rc_entry);
1157 0 : mtx_leave(&sc->sc_cntl_cqlck);
1158 0 : }
1159 0 : return (rc);
1160 : }
1161 :
1162 : static inline void
1163 0 : hvn_release_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1164 : {
1165 0 : mtx_enter(&sc->sc_cntl_cqlck);
1166 0 : TAILQ_REMOVE(&sc->sc_cntl_cq, rc, rc_entry);
1167 0 : mtx_leave(&sc->sc_cntl_cqlck);
1168 0 : }
1169 :
1170 : static inline int
1171 0 : hvn_rollback_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1172 : {
1173 : struct rndis_cmd *rn;
1174 :
1175 0 : mtx_enter(&sc->sc_cntl_sqlck);
1176 0 : TAILQ_FOREACH(rn, &sc->sc_cntl_sq, rc_entry) {
1177 0 : if (rn == rc) {
1178 0 : TAILQ_REMOVE(&sc->sc_cntl_sq, rc, rc_entry);
1179 0 : mtx_leave(&sc->sc_cntl_sqlck);
1180 0 : return (0);
1181 : }
1182 : }
1183 0 : mtx_leave(&sc->sc_cntl_sqlck);
1184 0 : return (-1);
1185 0 : }
1186 :
1187 : static inline void
1188 0 : hvn_free_cmd(struct hvn_softc *sc, struct rndis_cmd *rc)
1189 : {
1190 0 : memset(rc->rc_req, 0, sizeof(struct rndis_packet_msg));
1191 0 : memset(&rc->rc_cmp, 0, sizeof(rc->rc_cmp));
1192 0 : memset(&rc->rc_msg, 0, sizeof(rc->rc_msg));
1193 0 : mtx_enter(&sc->sc_cntl_fqlck);
1194 0 : TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1195 0 : mtx_leave(&sc->sc_cntl_fqlck);
1196 0 : wakeup(&sc->sc_cntl_fq);
1197 0 : }
1198 :
1199 : int
1200 0 : hvn_rndis_attach(struct hvn_softc *sc)
1201 : {
1202 : struct rndis_init_req *req;
1203 : struct rndis_init_comp *cmp;
1204 : struct rndis_cmd *rc;
1205 : int i, rv;
1206 :
1207 : /* RNDIS control message queues */
1208 0 : TAILQ_INIT(&sc->sc_cntl_sq);
1209 0 : TAILQ_INIT(&sc->sc_cntl_cq);
1210 0 : TAILQ_INIT(&sc->sc_cntl_fq);
1211 0 : mtx_init(&sc->sc_cntl_sqlck, IPL_NET);
1212 0 : mtx_init(&sc->sc_cntl_cqlck, IPL_NET);
1213 0 : mtx_init(&sc->sc_cntl_fqlck, IPL_NET);
1214 :
1215 0 : for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1216 0 : rc = &sc->sc_cntl_msgs[i];
1217 0 : if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1,
1218 : PAGE_SIZE, 0, BUS_DMA_WAITOK, &rc->rc_dmap)) {
1219 : DPRINTF("%s: failed to create RNDIS command map\n",
1220 : sc->sc_dev.dv_xname);
1221 : goto errout;
1222 : }
1223 0 : if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
1224 : 0, &rc->rc_segs, 1, &rc->rc_nsegs, BUS_DMA_NOWAIT |
1225 : BUS_DMA_ZERO)) {
1226 : DPRINTF("%s: failed to allocate RNDIS command\n",
1227 : sc->sc_dev.dv_xname);
1228 0 : bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1229 0 : goto errout;
1230 : }
1231 0 : if (bus_dmamem_map(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs,
1232 : PAGE_SIZE, (caddr_t *)&rc->rc_req, BUS_DMA_NOWAIT)) {
1233 : DPRINTF("%s: failed to allocate RNDIS command\n",
1234 : sc->sc_dev.dv_xname);
1235 0 : bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1236 : rc->rc_nsegs);
1237 0 : bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1238 0 : goto errout;
1239 : }
1240 0 : if (bus_dmamap_load(sc->sc_dmat, rc->rc_dmap, rc->rc_req,
1241 : PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
1242 : DPRINTF("%s: failed to load RNDIS command map\n",
1243 : sc->sc_dev.dv_xname);
1244 0 : bus_dmamem_free(sc->sc_dmat, &rc->rc_segs,
1245 : rc->rc_nsegs);
1246 0 : bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1247 0 : goto errout;
1248 : }
1249 0 : rc->rc_gpa = atop(rc->rc_dmap->dm_segs[0].ds_addr);
1250 0 : TAILQ_INSERT_TAIL(&sc->sc_cntl_fq, rc, rc_entry);
1251 : }
1252 :
1253 0 : rc = hvn_alloc_cmd(sc);
1254 :
1255 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1256 : BUS_DMASYNC_PREREAD);
1257 :
1258 0 : rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1259 :
1260 0 : req = rc->rc_req;
1261 0 : req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1262 0 : req->rm_len = sizeof(*req);
1263 0 : req->rm_rid = rc->rc_id;
1264 0 : req->rm_ver_major = RNDIS_VERSION_MAJOR;
1265 0 : req->rm_ver_minor = RNDIS_VERSION_MINOR;
1266 0 : req->rm_max_xfersz = HVN_RNDIS_XFER_SIZE;
1267 :
1268 0 : rc->rc_cmplen = sizeof(*cmp);
1269 :
1270 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1271 : BUS_DMASYNC_PREWRITE);
1272 :
1273 0 : if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1274 : DPRINTF("%s: INITIALIZE_MSG failed, error %d\n",
1275 : sc->sc_dev.dv_xname, rv);
1276 0 : hvn_free_cmd(sc, rc);
1277 0 : goto errout;
1278 : }
1279 0 : cmp = (struct rndis_init_comp *)&rc->rc_cmp;
1280 0 : if (cmp->rm_status != RNDIS_STATUS_SUCCESS) {
1281 : DPRINTF("%s: failed to init RNDIS, error %#x\n",
1282 : sc->sc_dev.dv_xname, cmp->rm_status);
1283 : hvn_free_cmd(sc, rc);
1284 : goto errout;
1285 : }
1286 :
1287 : hvn_free_cmd(sc, rc);
1288 :
1289 : /* Initialize RNDIS Data command */
1290 0 : memset(&sc->sc_data_msg, 0, sizeof(sc->sc_data_msg));
1291 0 : sc->sc_data_msg.nvs_type = HVN_NVS_TYPE_RNDIS;
1292 0 : sc->sc_data_msg.nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_DATA;
1293 0 : sc->sc_data_msg.nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1294 :
1295 0 : return (0);
1296 :
1297 : errout:
1298 0 : for (i = 0; i < HVN_RNDIS_CTLREQS; i++) {
1299 0 : rc = &sc->sc_cntl_msgs[i];
1300 0 : if (rc->rc_req == NULL)
1301 : continue;
1302 0 : TAILQ_REMOVE(&sc->sc_cntl_fq, rc, rc_entry);
1303 0 : bus_dmamem_free(sc->sc_dmat, &rc->rc_segs, rc->rc_nsegs);
1304 0 : rc->rc_req = NULL;
1305 0 : bus_dmamap_destroy(sc->sc_dmat, rc->rc_dmap);
1306 0 : }
1307 0 : return (-1);
1308 0 : }
1309 :
1310 : int
1311 0 : hvn_set_capabilities(struct hvn_softc *sc)
1312 : {
1313 0 : struct ndis_offload_params params;
1314 : size_t len = sizeof(params);
1315 :
1316 0 : memset(¶ms, 0, sizeof(params));
1317 :
1318 0 : params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
1319 0 : if (sc->sc_ndisver < NDIS_VERSION_6_30) {
1320 0 : params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
1321 0 : len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
1322 0 : } else {
1323 0 : params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
1324 0 : len = params.ndis_hdr.ndis_size = NDIS_OFFLOAD_PARAMS_SIZE;
1325 : }
1326 :
1327 0 : params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
1328 0 : params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1329 0 : params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1330 0 : if (sc->sc_ndisver >= NDIS_VERSION_6_30) {
1331 0 : params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
1332 0 : params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
1333 0 : }
1334 :
1335 0 : return (hvn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, len));
1336 0 : }
1337 :
1338 : int
1339 0 : hvn_rndis_cmd(struct hvn_softc *sc, struct rndis_cmd *rc, int timo)
1340 : {
1341 0 : struct hvn_nvs_rndis *msg = &rc->rc_msg;
1342 0 : struct rndis_msghdr *hdr = rc->rc_req;
1343 0 : struct vmbus_gpa sgl[1];
1344 : int tries = 10;
1345 : int rv, s;
1346 :
1347 0 : KERNEL_ASSERT_LOCKED();
1348 :
1349 0 : KASSERT(timo > 0);
1350 :
1351 0 : msg->nvs_type = HVN_NVS_TYPE_RNDIS;
1352 0 : msg->nvs_rndis_mtype = HVN_NVS_RNDIS_MTYPE_CTRL;
1353 0 : msg->nvs_chim_idx = HVN_NVS_CHIM_IDX_INVALID;
1354 :
1355 0 : sgl[0].gpa_page = rc->rc_gpa;
1356 0 : sgl[0].gpa_len = hdr->rm_len;
1357 0 : sgl[0].gpa_ofs = 0;
1358 :
1359 0 : rc->rc_done = 0;
1360 :
1361 0 : hvn_submit_cmd(sc, rc);
1362 :
1363 0 : do {
1364 0 : rv = hv_channel_send_sgl(sc->sc_chan, sgl, 1, &rc->rc_msg,
1365 0 : sizeof(*msg), rc->rc_id);
1366 0 : if (rv == EAGAIN) {
1367 0 : if (cold)
1368 0 : delay(100);
1369 : else
1370 0 : tsleep(rc, PRIBIO, "rndisout", 1);
1371 0 : } else if (rv) {
1372 : DPRINTF("%s: RNDIS operation %u send error %d\n",
1373 : sc->sc_dev.dv_xname, hdr->rm_type, rv);
1374 0 : hvn_rollback_cmd(sc, rc);
1375 0 : return (rv);
1376 : }
1377 0 : } while (rv != 0 && --tries > 0);
1378 :
1379 0 : if (tries == 0 && rv != 0) {
1380 0 : printf("%s: RNDIS operation %u send error %d\n",
1381 0 : sc->sc_dev.dv_xname, hdr->rm_type, rv);
1382 0 : return (rv);
1383 : }
1384 :
1385 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1386 : BUS_DMASYNC_POSTWRITE);
1387 :
1388 0 : do {
1389 0 : if (cold)
1390 0 : delay(1000);
1391 : else
1392 0 : tsleep(rc, PRIBIO | PCATCH, "rndiscmd", 1);
1393 0 : s = splnet();
1394 0 : hvn_nvs_intr(sc);
1395 0 : splx(s);
1396 0 : } while (--timo > 0 && rc->rc_done != 1);
1397 :
1398 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1399 : BUS_DMASYNC_POSTREAD);
1400 :
1401 0 : if (rc->rc_done != 1) {
1402 0 : rv = timo == 0 ? ETIMEDOUT : EINTR;
1403 0 : if (hvn_rollback_cmd(sc, rc)) {
1404 0 : hvn_release_cmd(sc, rc);
1405 : rv = 0;
1406 0 : } else if (rv == ETIMEDOUT) {
1407 0 : printf("%s: RNDIS operation %u timed out\n",
1408 0 : sc->sc_dev.dv_xname, hdr->rm_type);
1409 0 : }
1410 0 : return (rv);
1411 : }
1412 :
1413 0 : hvn_release_cmd(sc, rc);
1414 0 : return (0);
1415 0 : }
1416 :
1417 : void
1418 0 : hvn_rndis_input(struct hvn_softc *sc, uint64_t tid, void *arg)
1419 : {
1420 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
1421 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1422 0 : struct vmbus_chanpkt_prplist *cp = arg;
1423 : uint32_t off, len, type;
1424 : int i;
1425 :
1426 0 : if (sc->sc_rx_ring == NULL) {
1427 : DPRINTF("%s: invalid rx ring\n", sc->sc_dev.dv_xname);
1428 0 : return;
1429 : }
1430 0 : for (i = 0; i < cp->cp_range_cnt; i++) {
1431 0 : off = cp->cp_range[i].gpa_ofs;
1432 0 : len = cp->cp_range[i].gpa_len;
1433 :
1434 0 : KASSERT(off + len <= sc->sc_rx_size);
1435 0 : KASSERT(len >= RNDIS_HEADER_OFFSET + 4);
1436 :
1437 0 : memcpy(&type, (caddr_t)sc->sc_rx_ring + off, sizeof(type));
1438 0 : switch (type) {
1439 : /* data message */
1440 : case REMOTE_NDIS_PACKET_MSG:
1441 0 : hvn_rxeof(sc, (caddr_t)sc->sc_rx_ring +
1442 : off, len, &ml);
1443 0 : break;
1444 : /* completion messages */
1445 : case REMOTE_NDIS_INITIALIZE_CMPLT:
1446 : case REMOTE_NDIS_QUERY_CMPLT:
1447 : case REMOTE_NDIS_SET_CMPLT:
1448 : case REMOTE_NDIS_RESET_CMPLT:
1449 : case REMOTE_NDIS_KEEPALIVE_CMPLT:
1450 0 : hvn_rndis_complete(sc, (caddr_t)sc->sc_rx_ring +
1451 : off, len);
1452 0 : break;
1453 : /* notification message */
1454 : case REMOTE_NDIS_INDICATE_STATUS_MSG:
1455 0 : hvn_rndis_status(sc, (caddr_t)sc->sc_rx_ring +
1456 : off, len);
1457 0 : break;
1458 : default:
1459 0 : printf("%s: unhandled RNDIS message type %u\n",
1460 0 : sc->sc_dev.dv_xname, type);
1461 0 : }
1462 : }
1463 0 : hvn_nvs_ack(sc, tid);
1464 :
1465 0 : if_input(ifp, &ml);
1466 0 : }
1467 :
1468 : static inline struct mbuf *
1469 0 : hvn_devget(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1470 : {
1471 : struct mbuf *m;
1472 :
1473 0 : if (len + ETHER_ALIGN <= MHLEN)
1474 0 : MGETHDR(m, M_NOWAIT, MT_DATA);
1475 : else
1476 0 : m = MCLGETI(NULL, M_NOWAIT, NULL, len + ETHER_ALIGN);
1477 0 : if (m == NULL)
1478 0 : return (NULL);
1479 0 : m->m_len = m->m_pkthdr.len = len;
1480 0 : m_adj(m, ETHER_ALIGN);
1481 :
1482 0 : if (m_copyback(m, 0, len, buf, M_NOWAIT)) {
1483 0 : m_freem(m);
1484 0 : return (NULL);
1485 : }
1486 :
1487 0 : return (m);
1488 0 : }
1489 :
1490 : void
1491 0 : hvn_rxeof(struct hvn_softc *sc, caddr_t buf, uint32_t len, struct mbuf_list *ml)
1492 : {
1493 0 : struct ifnet *ifp = &sc->sc_ac.ac_if;
1494 : struct rndis_packet_msg *pkt;
1495 : struct rndis_pktinfo *pi;
1496 : uint32_t csum, vlan;
1497 : struct mbuf *m;
1498 :
1499 0 : if (!(ifp->if_flags & IFF_RUNNING))
1500 0 : return;
1501 :
1502 0 : if (len < sizeof(*pkt)) {
1503 0 : printf("%s: data packet too short: %u\n",
1504 0 : sc->sc_dev.dv_xname, len);
1505 0 : return;
1506 : }
1507 :
1508 0 : pkt = (struct rndis_packet_msg *)buf;
1509 :
1510 0 : if (pkt->rm_dataoffset + pkt->rm_datalen > len) {
1511 0 : printf("%s: data packet out of bounds: %u@%u\n",
1512 0 : sc->sc_dev.dv_xname, pkt->rm_dataoffset, pkt->rm_datalen);
1513 0 : return;
1514 : }
1515 :
1516 0 : if ((m = hvn_devget(sc, buf + RNDIS_HEADER_OFFSET + pkt->rm_dataoffset,
1517 0 : pkt->rm_datalen)) == NULL) {
1518 0 : ifp->if_ierrors++;
1519 0 : return;
1520 : }
1521 :
1522 0 : if (pkt->rm_pktinfooffset + pkt->rm_pktinfolen > len) {
1523 0 : printf("%s: pktinfo is out of bounds: %u@%u vs %u\n",
1524 0 : sc->sc_dev.dv_xname, pkt->rm_pktinfolen,
1525 : pkt->rm_pktinfooffset, len);
1526 0 : goto done;
1527 : }
1528 0 : pi = (struct rndis_pktinfo *)((caddr_t)pkt + RNDIS_HEADER_OFFSET +
1529 : pkt->rm_pktinfooffset);
1530 0 : while (pkt->rm_pktinfolen > 0) {
1531 0 : if (pi->rm_size > pkt->rm_pktinfolen) {
1532 0 : printf("%s: invalid pktinfo size: %u/%u\n",
1533 0 : sc->sc_dev.dv_xname, pi->rm_size,
1534 : pkt->rm_pktinfolen);
1535 0 : break;
1536 : }
1537 0 : switch (pi->rm_type) {
1538 : case NDIS_PKTINFO_TYPE_CSUM:
1539 0 : memcpy(&csum, pi->rm_data, sizeof(csum));
1540 0 : if (csum & NDIS_RXCSUM_INFO_IPCS_OK)
1541 0 : m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1542 0 : if (csum & NDIS_RXCSUM_INFO_TCPCS_OK)
1543 0 : m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK;
1544 0 : if (csum & NDIS_RXCSUM_INFO_UDPCS_OK)
1545 0 : m->m_pkthdr.csum_flags |= M_UDP_CSUM_IN_OK;
1546 : break;
1547 : case NDIS_PKTINFO_TYPE_VLAN:
1548 0 : memcpy(&vlan, pi->rm_data, sizeof(vlan));
1549 : #if NVLAN > 0
1550 0 : if (vlan != 0xffffffff) {
1551 0 : m->m_pkthdr.ether_vtag =
1552 0 : NDIS_VLAN_INFO_ID(vlan) |
1553 0 : (NDIS_VLAN_INFO_PRI(vlan) << EVL_PRIO_BITS);
1554 0 : m->m_flags |= M_VLANTAG;
1555 0 : }
1556 : #endif
1557 : break;
1558 : default:
1559 : DPRINTF("%s: unhandled pktinfo type %u\n",
1560 : sc->sc_dev.dv_xname, pi->rm_type);
1561 : }
1562 0 : pkt->rm_pktinfolen -= pi->rm_size;
1563 0 : pi = (struct rndis_pktinfo *)((caddr_t)pi + pi->rm_size);
1564 : }
1565 :
1566 : done:
1567 0 : ml_enqueue(ml, m);
1568 0 : }
1569 :
1570 : void
1571 0 : hvn_rndis_complete(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1572 : {
1573 : struct rndis_cmd *rc;
1574 : uint32_t id;
1575 :
1576 0 : memcpy(&id, buf + RNDIS_HEADER_OFFSET, sizeof(id));
1577 0 : if ((rc = hvn_complete_cmd(sc, id)) != NULL) {
1578 0 : if (len < rc->rc_cmplen)
1579 0 : printf("%s: RNDIS response %u too short: %u\n",
1580 0 : sc->sc_dev.dv_xname, id, len);
1581 : else
1582 0 : memcpy(&rc->rc_cmp, buf, rc->rc_cmplen);
1583 0 : if (len > rc->rc_cmplen &&
1584 0 : len - rc->rc_cmplen > HVN_RNDIS_BUFSIZE)
1585 0 : printf("%s: RNDIS response %u too large: %u\n",
1586 0 : sc->sc_dev.dv_xname, id, len);
1587 0 : else if (len > rc->rc_cmplen)
1588 0 : memcpy(&rc->rc_cmpbuf, buf + rc->rc_cmplen,
1589 : len - rc->rc_cmplen);
1590 0 : rc->rc_done = 1;
1591 0 : wakeup_one(rc);
1592 0 : } else
1593 : DPRINTF("%s: failed to complete RNDIS request id %u\n",
1594 : sc->sc_dev.dv_xname, id);
1595 0 : }
1596 :
1597 : int
1598 0 : hvn_rndis_output(struct hvn_softc *sc, struct hvn_tx_desc *txd)
1599 : {
1600 0 : uint64_t rid = (uint64_t)txd->txd_id << 32;
1601 : int rv;
1602 :
1603 0 : rv = hv_channel_send_sgl(sc->sc_chan, txd->txd_sgl, txd->txd_nsge,
1604 0 : &sc->sc_data_msg, sizeof(sc->sc_data_msg), rid);
1605 0 : if (rv) {
1606 : DPRINTF("%s: RNDIS data send error %d\n",
1607 : sc->sc_dev.dv_xname, rv);
1608 0 : return (rv);
1609 : }
1610 :
1611 0 : return (0);
1612 0 : }
1613 :
1614 : void
1615 0 : hvn_rndis_status(struct hvn_softc *sc, caddr_t buf, uint32_t len)
1616 : {
1617 : uint32_t status;
1618 :
1619 0 : memcpy(&status, buf + RNDIS_HEADER_OFFSET, sizeof(status));
1620 0 : switch (status) {
1621 : case RNDIS_STATUS_MEDIA_CONNECT:
1622 0 : sc->sc_link_state = LINK_STATE_UP;
1623 0 : break;
1624 : case RNDIS_STATUS_MEDIA_DISCONNECT:
1625 0 : sc->sc_link_state = LINK_STATE_DOWN;
1626 0 : break;
1627 : /* Ignore these */
1628 : case RNDIS_STATUS_OFFLOAD_CURRENT_CONFIG:
1629 0 : return;
1630 : default:
1631 : DPRINTF("%s: unhandled status %#x\n", sc->sc_dev.dv_xname,
1632 : status);
1633 0 : return;
1634 : }
1635 0 : KERNEL_LOCK();
1636 0 : hvn_link_status(sc);
1637 0 : KERNEL_UNLOCK();
1638 0 : }
1639 :
1640 : int
1641 0 : hvn_rndis_query(struct hvn_softc *sc, uint32_t oid, void *res, size_t *length)
1642 : {
1643 : struct rndis_cmd *rc;
1644 : struct rndis_query_req *req;
1645 : struct rndis_query_comp *cmp;
1646 0 : size_t olength = *length;
1647 : int rv;
1648 :
1649 0 : rc = hvn_alloc_cmd(sc);
1650 :
1651 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1652 : BUS_DMASYNC_PREREAD);
1653 :
1654 0 : rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1655 :
1656 0 : req = rc->rc_req;
1657 0 : req->rm_type = REMOTE_NDIS_QUERY_MSG;
1658 0 : req->rm_len = sizeof(*req);
1659 0 : req->rm_rid = rc->rc_id;
1660 0 : req->rm_oid = oid;
1661 0 : req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1662 :
1663 0 : rc->rc_cmplen = sizeof(*cmp);
1664 :
1665 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1666 : BUS_DMASYNC_PREWRITE);
1667 :
1668 0 : if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1669 : DPRINTF("%s: QUERY_MSG failed, error %d\n",
1670 : sc->sc_dev.dv_xname, rv);
1671 0 : hvn_free_cmd(sc, rc);
1672 0 : return (rv);
1673 : }
1674 :
1675 0 : cmp = (struct rndis_query_comp *)&rc->rc_cmp;
1676 0 : switch (cmp->rm_status) {
1677 : case RNDIS_STATUS_SUCCESS:
1678 0 : if (cmp->rm_infobuflen > olength) {
1679 : rv = EINVAL;
1680 0 : break;
1681 : }
1682 0 : memcpy(res, rc->rc_cmpbuf, cmp->rm_infobuflen);
1683 0 : *length = cmp->rm_infobuflen;
1684 0 : break;
1685 : default:
1686 0 : *length = 0;
1687 : rv = EIO;
1688 0 : }
1689 :
1690 0 : hvn_free_cmd(sc, rc);
1691 :
1692 0 : return (rv);
1693 0 : }
1694 :
1695 : int
1696 0 : hvn_rndis_set(struct hvn_softc *sc, uint32_t oid, void *data, size_t length)
1697 : {
1698 : struct rndis_cmd *rc;
1699 : struct rndis_set_req *req;
1700 : struct rndis_set_comp *cmp;
1701 : int rv;
1702 :
1703 0 : rc = hvn_alloc_cmd(sc);
1704 :
1705 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1706 : BUS_DMASYNC_PREREAD);
1707 :
1708 0 : rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1709 :
1710 0 : req = rc->rc_req;
1711 0 : req->rm_type = REMOTE_NDIS_SET_MSG;
1712 0 : req->rm_len = sizeof(*req) + length;
1713 0 : req->rm_rid = rc->rc_id;
1714 0 : req->rm_oid = oid;
1715 0 : req->rm_infobufoffset = sizeof(*req) - RNDIS_HEADER_OFFSET;
1716 :
1717 0 : rc->rc_cmplen = sizeof(*cmp);
1718 :
1719 0 : if (length > 0) {
1720 0 : KASSERT(sizeof(*req) + length < PAGE_SIZE);
1721 0 : req->rm_infobuflen = length;
1722 0 : memcpy((caddr_t)(req + 1), data, length);
1723 0 : }
1724 :
1725 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1726 : BUS_DMASYNC_PREWRITE);
1727 :
1728 0 : if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0) {
1729 : DPRINTF("%s: SET_MSG failed, error %d\n",
1730 : sc->sc_dev.dv_xname, rv);
1731 0 : hvn_free_cmd(sc, rc);
1732 0 : return (rv);
1733 : }
1734 :
1735 0 : cmp = (struct rndis_set_comp *)&rc->rc_cmp;
1736 0 : if (cmp->rm_status != RNDIS_STATUS_SUCCESS)
1737 0 : rv = EIO;
1738 :
1739 0 : hvn_free_cmd(sc, rc);
1740 :
1741 0 : return (rv);
1742 0 : }
1743 :
1744 : int
1745 0 : hvn_rndis_close(struct hvn_softc *sc)
1746 : {
1747 0 : uint32_t filter = 0;
1748 : int rv;
1749 :
1750 0 : rv = hvn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
1751 : &filter, sizeof(filter));
1752 : if (rv)
1753 : DPRINTF("%s: failed to clear RNDIS filter\n",
1754 : sc->sc_dev.dv_xname);
1755 0 : return (rv);
1756 0 : }
1757 :
1758 : void
1759 0 : hvn_rndis_detach(struct hvn_softc *sc)
1760 : {
1761 : struct rndis_cmd *rc;
1762 : struct rndis_halt_req *req;
1763 : int rv;
1764 :
1765 0 : rc = hvn_alloc_cmd(sc);
1766 :
1767 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1768 : BUS_DMASYNC_PREREAD);
1769 :
1770 0 : rc->rc_id = atomic_inc_int_nv(&sc->sc_rndisrid);
1771 :
1772 0 : req = rc->rc_req;
1773 0 : req->rm_type = REMOTE_NDIS_HALT_MSG;
1774 0 : req->rm_len = sizeof(*req);
1775 0 : req->rm_rid = rc->rc_id;
1776 :
1777 0 : bus_dmamap_sync(sc->sc_dmat, rc->rc_dmap, 0, PAGE_SIZE,
1778 : BUS_DMASYNC_PREWRITE);
1779 :
1780 0 : if ((rv = hvn_rndis_cmd(sc, rc, 500)) != 0)
1781 : DPRINTF("%s: HALT_MSG failed, error %d\n",
1782 : sc->sc_dev.dv_xname, rv);
1783 :
1784 0 : hvn_free_cmd(sc, rc);
1785 0 : }
|