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