2 * Copyright (c) 2009-2012,2016 Microsoft Corp.
3 * Copyright (c) 2010-2012 Citrix Inc.
4 * Copyright (c) 2012 NetApp Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
34 #include <sys/socket.h>
36 #include <sys/mutex.h>
38 #include <net/if_arp.h>
39 #include <net/if_var.h>
40 #include <net/ethernet.h>
41 #include <net/rndis.h>
42 #include <sys/types.h>
43 #include <machine/atomic.h>
46 #include <vm/vm_param.h>
49 #include <dev/hyperv/include/hyperv.h>
50 #include <dev/hyperv/include/vmbus_xact.h>
51 #include <dev/hyperv/netvsc/hv_net_vsc.h>
52 #include <dev/hyperv/netvsc/hv_rndis_filter.h>
53 #include <dev/hyperv/netvsc/if_hnreg.h>
54 #include <dev/hyperv/netvsc/ndis.h>
56 #define HV_RF_RECVINFO_VLAN 0x1
57 #define HV_RF_RECVINFO_CSUM 0x2
58 #define HV_RF_RECVINFO_HASHINF 0x4
59 #define HV_RF_RECVINFO_HASHVAL 0x8
60 #define HV_RF_RECVINFO_ALL \
61 (HV_RF_RECVINFO_VLAN | \
62 HV_RF_RECVINFO_CSUM | \
63 HV_RF_RECVINFO_HASHINF | \
64 HV_RF_RECVINFO_HASHVAL)
66 #define HN_RNDIS_RID_COMPAT_MASK 0xffff
67 #define HN_RNDIS_RID_COMPAT_MAX HN_RNDIS_RID_COMPAT_MASK
69 #define HN_RNDIS_XFER_SIZE 2048
72 * Forward declarations
74 static void hv_rf_receive_indicate_status(struct hn_softc *sc,
75 const void *data, int dlen);
76 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
77 const void *data, int dlen);
78 static int hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr);
79 static int hv_rf_query_device_link_status(struct hn_softc *sc,
80 uint32_t *link_status);
81 static int hv_rf_init_device(struct hn_softc *sc);
83 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
84 const void *idata, size_t idlen, void *odata, size_t *odlen0);
85 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
87 static int hn_rndis_conf_offload(struct hn_softc *sc);
88 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
89 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
91 static __inline uint32_t
92 hn_rndis_rid(struct hn_softc *sc)
97 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
101 /* Use upper 16 bits for non-compat RNDIS messages. */
102 return ((rid & 0xffff) << 16);
106 hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
107 size_t pi_dlen, uint32_t pi_type)
109 const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
110 struct rndis_pktinfo *pi;
112 KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
113 ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
116 * Per-packet-info does not move; it only grows.
119 * rm_pktinfooffset in this phase counts from the beginning
120 * of rndis_packet_msg.
122 KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
123 ("%u pktinfo overflows RNDIS packet msg", pi_type));
124 pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
126 pkt->rm_pktinfolen += pi_size;
128 pi->rm_size = pi_size;
129 pi->rm_type = pi_type;
130 pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
132 /* Data immediately follow per-packet-info. */
133 pkt->rm_dataoffset += pi_size;
135 /* Update RNDIS packet msg length */
136 pkt->rm_len += pi_size;
138 return (pi->rm_data);
142 * RNDIS filter receive indicate status
145 hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
147 const struct rndis_status_msg *msg;
149 if (dlen < sizeof(*msg)) {
150 if_printf(sc->hn_ifp, "invalid RNDIS status\n");
155 switch (msg->rm_status) {
156 case RNDIS_STATUS_MEDIA_CONNECT:
157 netvsc_linkstatus_callback(sc, 1);
160 case RNDIS_STATUS_MEDIA_DISCONNECT:
161 netvsc_linkstatus_callback(sc, 0);
166 if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
173 hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
175 const struct rndis_pktinfo *pi = info_data;
178 while (info_dlen != 0) {
182 if (__predict_false(info_dlen < sizeof(*pi)))
184 if (__predict_false(info_dlen < pi->rm_size))
186 info_dlen -= pi->rm_size;
188 if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
190 if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
192 dlen = pi->rm_size - pi->rm_pktinfooffset;
195 switch (pi->rm_type) {
196 case NDIS_PKTINFO_TYPE_VLAN:
197 if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
199 info->vlan_info = *((const uint32_t *)data);
200 mask |= HV_RF_RECVINFO_VLAN;
203 case NDIS_PKTINFO_TYPE_CSUM:
204 if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
206 info->csum_info = *((const uint32_t *)data);
207 mask |= HV_RF_RECVINFO_CSUM;
210 case HN_NDIS_PKTINFO_TYPE_HASHVAL:
211 if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
213 info->hash_value = *((const uint32_t *)data);
214 mask |= HV_RF_RECVINFO_HASHVAL;
217 case HN_NDIS_PKTINFO_TYPE_HASHINF:
218 if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
220 info->hash_info = *((const uint32_t *)data);
221 mask |= HV_RF_RECVINFO_HASHINF;
228 if (mask == HV_RF_RECVINFO_ALL) {
229 /* All found; done */
233 pi = (const struct rndis_pktinfo *)
234 ((const uint8_t *)pi + pi->rm_size);
239 * - If there is no hash value, invalidate the hash info.
241 if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
242 info->hash_info = HN_NDIS_HASH_INFO_INVALID;
247 hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
250 if (off < check_off) {
251 if (__predict_true(off + len <= check_off))
253 } else if (off > check_off) {
254 if (__predict_true(check_off + check_len <= off))
261 * RNDIS filter receive data
264 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
266 const struct rndis_packet_msg *pkt;
267 struct hn_recvinfo info;
268 int data_off, pktinfo_off, data_len, pktinfo_len;
273 if (__predict_false(dlen < sizeof(*pkt))) {
274 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
279 if (__predict_false(dlen < pkt->rm_len)) {
280 if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
281 "dlen %d, msglen %u\n", dlen, pkt->rm_len);
284 if (__predict_false(pkt->rm_len <
285 pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
286 if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
287 "msglen %u, data %u, oob %u, pktinfo %u\n",
288 pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
292 if (__predict_false(pkt->rm_datalen == 0)) {
293 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
300 #define IS_OFFSET_INVALID(ofs) \
301 ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
302 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
304 /* XXX Hyper-V does not meet data offset alignment requirement */
305 if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
306 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
307 "data offset %u\n", pkt->rm_dataoffset);
310 if (__predict_false(pkt->rm_oobdataoffset > 0 &&
311 IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
312 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
313 "oob offset %u\n", pkt->rm_oobdataoffset);
316 if (__predict_true(pkt->rm_pktinfooffset > 0) &&
317 __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
318 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
319 "pktinfo offset %u\n", pkt->rm_pktinfooffset);
323 #undef IS_OFFSET_INVALID
325 data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
326 data_len = pkt->rm_datalen;
327 pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
328 pktinfo_len = pkt->rm_pktinfolen;
331 * Check OOB coverage.
333 if (__predict_false(pkt->rm_oobdatalen != 0)) {
334 int oob_off, oob_len;
336 if_printf(rxr->hn_ifp, "got oobdata\n");
337 oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
338 oob_len = pkt->rm_oobdatalen;
340 if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
341 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
342 "oob overflow, msglen %u, oob abs %d len %d\n",
343 pkt->rm_len, oob_off, oob_len);
348 * Check against data.
350 if (hn_rndis_check_overlap(oob_off, oob_len,
351 data_off, data_len)) {
352 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
353 "oob overlaps data, oob abs %d len %d, "
354 "data abs %d len %d\n",
355 oob_off, oob_len, data_off, data_len);
360 * Check against pktinfo.
362 if (pktinfo_len != 0 &&
363 hn_rndis_check_overlap(oob_off, oob_len,
364 pktinfo_off, pktinfo_len)) {
365 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
366 "oob overlaps pktinfo, oob abs %d len %d, "
367 "pktinfo abs %d len %d\n",
368 oob_off, oob_len, pktinfo_off, pktinfo_len);
374 * Check per-packet-info coverage and find useful per-packet-info.
376 info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
377 info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
378 info.hash_info = HN_NDIS_HASH_INFO_INVALID;
379 if (__predict_true(pktinfo_len != 0)) {
383 if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
384 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
385 "pktinfo overflow, msglen %u, "
386 "pktinfo abs %d len %d\n",
387 pkt->rm_len, pktinfo_off, pktinfo_len);
392 * Check packet info coverage.
394 overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
396 if (__predict_false(overlap)) {
397 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
398 "pktinfo overlap data, pktinfo abs %d len %d, "
399 "data abs %d len %d\n",
400 pktinfo_off, pktinfo_len, data_off, data_len);
405 * Find useful per-packet-info.
407 error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
409 if (__predict_false(error)) {
410 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
416 if (__predict_false(data_off + data_len > pkt->rm_len)) {
417 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
418 "data overflow, msglen %u, data abs %d len %d\n",
419 pkt->rm_len, data_off, data_len);
422 hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
426 * RNDIS filter on receive
429 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
430 const void *data, int dlen)
432 const struct rndis_comp_hdr *comp;
433 const struct rndis_msghdr *hdr;
435 if (__predict_false(dlen < sizeof(*hdr))) {
436 if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
441 switch (hdr->rm_type) {
442 case REMOTE_NDIS_PACKET_MSG:
443 hv_rf_receive_data(rxr, data, dlen);
446 case REMOTE_NDIS_INITIALIZE_CMPLT:
447 case REMOTE_NDIS_QUERY_CMPLT:
448 case REMOTE_NDIS_SET_CMPLT:
449 case REMOTE_NDIS_KEEPALIVE_CMPLT: /* unused */
450 if (dlen < sizeof(*comp)) {
451 if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
456 KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
457 ("invalid RNDIS rid 0x%08x\n", comp->rm_rid));
458 vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
461 case REMOTE_NDIS_INDICATE_STATUS_MSG:
462 hv_rf_receive_indicate_status(sc, data, dlen);
465 case REMOTE_NDIS_RESET_CMPLT:
467 * Reset completed, no rid.
470 * RESET is not issued by hn(4), so this message should
473 if_printf(rxr->hn_ifp, "RESET cmplt received\n");
477 if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
484 * RNDIS filter query device MAC address
487 hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
492 eaddr_len = ETHER_ADDR_LEN;
493 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
497 if (eaddr_len != ETHER_ADDR_LEN) {
498 if_printf(sc->hn_ifp, "invalid eaddr len %zu\n", eaddr_len);
505 * RNDIS filter query device link status
508 hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
513 size = sizeof(*link_status);
514 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
518 if (size != sizeof(uint32_t)) {
519 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
525 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
526 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
527 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
528 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
529 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
530 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
534 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
535 struct hn_send_ctx *sndc, size_t *comp_len)
537 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
541 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
542 ("invalid request length %zu", reqlen));
547 paddr = vmbus_xact_req_paddr(xact);
548 KASSERT((paddr & PAGE_MASK) == 0,
549 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
550 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
558 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
559 gpa[gpa_cnt].gpa_len = len;
560 gpa[gpa_cnt].gpa_ofs = 0;
564 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
567 * Send this RNDIS control message and wait for its completion
570 vmbus_xact_activate(xact);
571 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
574 vmbus_xact_deactivate(xact);
575 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
578 return (vmbus_xact_wait(xact, comp_len));
582 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
583 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
585 const struct rndis_comp_hdr *comp;
586 size_t comp_len, min_complen = *comp_len0;
588 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
589 KASSERT(min_complen >= sizeof(*comp),
590 ("invalid minimum complete len %zu", min_complen));
593 * Execute the xact setup by the caller.
595 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
601 * Check this RNDIS complete message.
603 if (comp_len < min_complen) {
604 if (comp_len >= sizeof(*comp)) {
605 /* rm_status field is valid */
606 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
607 "status 0x%08x\n", comp_len, comp->rm_status);
609 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
614 if (comp->rm_len < min_complen) {
615 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
619 if (comp->rm_type != comp_type) {
620 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
621 "expect 0x%08x\n", comp->rm_type, comp_type);
624 if (comp->rm_rid != rid) {
625 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
626 "expect %u\n", comp->rm_rid, rid);
630 *comp_len0 = comp_len;
635 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
636 const void *idata, size_t idlen, void *odata, size_t *odlen0)
638 struct rndis_query_req *req;
639 const struct rndis_query_comp *comp;
640 struct vmbus_xact *xact;
641 size_t reqlen, odlen = *odlen0, comp_len;
645 reqlen = sizeof(*req) + idlen;
646 xact = vmbus_xact_get(sc->hn_xact, reqlen);
648 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
651 rid = hn_rndis_rid(sc);
652 req = vmbus_xact_req_data(xact);
653 req->rm_type = REMOTE_NDIS_QUERY_MSG;
654 req->rm_len = reqlen;
659 * This is _not_ RNDIS Spec conforming:
660 * "This MUST be set to 0 when there is no input data
661 * associated with the OID."
663 * If this field was set to 0 according to the RNDIS Spec,
664 * Hyper-V would set non-SUCCESS status in the query
667 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
670 req->rm_infobuflen = idlen;
671 /* Input data immediately follows RNDIS query. */
672 memcpy(req + 1, idata, idlen);
675 comp_len = sizeof(*comp) + odlen;
676 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
677 REMOTE_NDIS_QUERY_CMPLT);
679 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
684 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
685 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
686 "status 0x%08x\n", oid, comp->rm_status);
690 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
691 /* No output data! */
692 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
699 * Check output data length and offset.
701 /* ofs is the offset from the beginning of comp. */
702 ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->rm_infobufoffset);
703 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
704 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
705 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
713 if (comp->rm_infobuflen < odlen)
714 odlen = comp->rm_infobuflen;
715 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
720 vmbus_xact_put(xact);
725 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
727 struct ndis_rss_caps in, caps;
732 * Only NDIS 6.30+ is supported.
734 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
735 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
738 memset(&in, 0, sizeof(in));
739 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
740 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
741 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
743 caps_len = NDIS_RSS_CAPS_SIZE;
744 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
745 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
748 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
749 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
754 if (caps.ndis_nrxr == 0) {
755 if_printf(sc->hn_ifp, "0 RX rings!?\n");
758 *rxr_cnt = caps.ndis_nrxr;
760 if (caps_len == NDIS_RSS_CAPS_SIZE) {
762 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
770 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
772 struct rndis_set_req *req;
773 const struct rndis_set_comp *comp;
774 struct vmbus_xact *xact;
775 size_t reqlen, comp_len;
779 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
781 reqlen = sizeof(*req) + dlen;
782 xact = vmbus_xact_get(sc->hn_xact, reqlen);
784 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
787 rid = hn_rndis_rid(sc);
788 req = vmbus_xact_req_data(xact);
789 req->rm_type = REMOTE_NDIS_SET_MSG;
790 req->rm_len = reqlen;
793 req->rm_infobuflen = dlen;
794 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
795 /* Data immediately follows RNDIS set. */
796 memcpy(req + 1, data, dlen);
798 comp_len = sizeof(*comp);
799 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
800 REMOTE_NDIS_SET_CMPLT);
802 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
807 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
808 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
809 "status 0x%08x\n", oid, comp->rm_status);
815 vmbus_xact_put(xact);
820 hn_rndis_conf_offload(struct hn_softc *sc)
822 struct ndis_offload_params params;
826 /* NOTE: 0 means "no change" */
827 memset(¶ms, 0, sizeof(params));
829 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
830 if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
831 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
832 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
834 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
835 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
837 params.ndis_hdr.ndis_size = paramsz;
839 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
840 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
841 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
842 if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
843 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
844 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
846 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
847 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
849 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
851 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
854 if_printf(sc->hn_ifp, "offload config done\n");
860 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
862 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
863 struct ndis_rss_params *prm = &rss->rss_params;
867 * Only NDIS 6.30+ is supported.
869 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
870 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
872 memset(rss, 0, sizeof(*rss));
873 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
874 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
875 prm->ndis_hdr.ndis_size = sizeof(*rss);
876 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
877 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
878 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
879 /* TODO: Take ndis_rss_caps.ndis_nind into account */
880 prm->ndis_indsize = sizeof(rss->rss_ind);
881 prm->ndis_indoffset =
882 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
883 prm->ndis_keysize = sizeof(rss->rss_key);
884 prm->ndis_keyoffset =
885 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
888 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
890 /* Setup RSS indirect table */
891 /* TODO: Take ndis_rss_caps.ndis_nind into account */
892 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
893 rss->rss_ind[i] = i % nchan;
895 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
898 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
901 if_printf(sc->hn_ifp, "RSS config done\n");
907 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
911 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
912 &filter, sizeof(filter));
914 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
918 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
926 * RNDIS filter init device
929 hv_rf_init_device(struct hn_softc *sc)
931 struct rndis_init_req *req;
932 const struct rndis_init_comp *comp;
933 struct vmbus_xact *xact;
938 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
940 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
943 rid = hn_rndis_rid(sc);
944 req = vmbus_xact_req_data(xact);
945 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
946 req->rm_len = sizeof(*req);
948 req->rm_ver_major = RNDIS_VERSION_MAJOR;
949 req->rm_ver_minor = RNDIS_VERSION_MINOR;
950 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
952 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
953 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
954 REMOTE_NDIS_INITIALIZE_CMPLT);
956 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
961 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
962 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
968 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u, "
969 "align %u\n", comp->rm_ver_major, comp->rm_ver_minor,
970 comp->rm_pktmaxsz, comp->rm_pktmaxcnt,
971 1U << comp->rm_align);
975 vmbus_xact_put(xact);
980 * RNDIS filter halt device
983 hv_rf_halt_device(struct hn_softc *sc)
985 struct vmbus_xact *xact;
986 struct rndis_halt_req *halt;
987 struct hn_send_ctx sndc;
990 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
992 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
995 halt = vmbus_xact_req_data(xact);
996 halt->rm_type = REMOTE_NDIS_HALT_MSG;
997 halt->rm_len = sizeof(*halt);
998 halt->rm_rid = hn_rndis_rid(sc);
1000 /* No RNDIS completion; rely on NVS message send completion */
1001 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
1002 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
1004 vmbus_xact_put(xact);
1006 if_printf(sc->hn_ifp, "RNDIS halt done\n");
1011 * RNDIS filter on device add
1014 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1015 int *nchan0, int mtu)
1018 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1019 device_t dev = sc->hn_dev;
1020 int nchan = *nchan0, rxr_cnt, nsubch;
1022 ret = hn_nvs_attach(sc, mtu);
1027 * Initialize the rndis device
1030 /* Send the rndis initialization message */
1031 ret = hv_rf_init_device(sc);
1034 * TODO: If rndis init failed, we will need to shut down
1039 /* Get the mac address */
1040 ret = hv_rf_query_device_mac(sc, dev_info->mac_addr);
1042 /* TODO: shut down rndis device and the channel */
1045 /* Configure NDIS offload settings */
1046 hn_rndis_conf_offload(sc);
1048 hv_rf_query_device_link_status(sc, &dev_info->link_state);
1050 if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
1052 * Either RSS is not supported, or multiple RX/TX rings
1053 * are not requested.
1060 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1063 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1065 /* No RSS; this is benign. */
1069 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1072 if (nchan > rxr_cnt)
1075 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1081 * Allocate sub-channels from NVS.
1084 ret = hn_nvs_alloc_subchans(sc, &nsubch);
1085 if (ret || nsubch == 0) {
1086 /* Failed to allocate sub-channels. */
1093 * Configure RSS key and indirect table after all sub-channels
1096 ret = hn_rndis_conf_rss(sc, nchan);
1098 /* Failed to configure RSS key or indirect table. */
1106 * RNDIS filter on device remove
1109 hv_rf_on_device_remove(struct hn_softc *sc)
1113 /* Halt and release the rndis device */
1114 ret = hv_rf_halt_device(sc);
1116 /* Pass control to inner driver to remove the device */
1117 ret |= hv_nv_on_device_remove(sc);
1123 * RNDIS filter on open
1126 hv_rf_on_open(struct hn_softc *sc)
1131 if (hv_promisc_mode != 1) {
1132 filter = NDIS_PACKET_TYPE_BROADCAST |
1133 NDIS_PACKET_TYPE_ALL_MULTICAST |
1134 NDIS_PACKET_TYPE_DIRECTED;
1136 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1138 return (hn_rndis_set_rxfilter(sc, filter));
1142 * RNDIS filter on close
1145 hv_rf_on_close(struct hn_softc *sc)
1148 return (hn_rndis_set_rxfilter(sc, 0));
1152 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1155 hn_chan_rollup(rxr, txr);