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>
33 #include <sys/kernel.h>
35 #include <sys/socket.h>
37 #include <sys/mutex.h>
39 #include <net/if_arp.h>
40 #include <net/if_var.h>
41 #include <net/ethernet.h>
42 #include <net/rndis.h>
43 #include <sys/types.h>
44 #include <machine/atomic.h>
47 #include <vm/vm_param.h>
50 #include <dev/hyperv/include/hyperv.h>
51 #include <dev/hyperv/include/vmbus_xact.h>
52 #include <dev/hyperv/netvsc/hv_net_vsc.h>
53 #include <dev/hyperv/netvsc/hv_rndis_filter.h>
54 #include <dev/hyperv/netvsc/if_hnreg.h>
55 #include <dev/hyperv/netvsc/ndis.h>
57 #define HV_RF_RECVINFO_VLAN 0x1
58 #define HV_RF_RECVINFO_CSUM 0x2
59 #define HV_RF_RECVINFO_HASHINF 0x4
60 #define HV_RF_RECVINFO_HASHVAL 0x8
61 #define HV_RF_RECVINFO_ALL \
62 (HV_RF_RECVINFO_VLAN | \
63 HV_RF_RECVINFO_CSUM | \
64 HV_RF_RECVINFO_HASHINF | \
65 HV_RF_RECVINFO_HASHVAL)
67 #define HN_RNDIS_RID_COMPAT_MASK 0xffff
68 #define HN_RNDIS_RID_COMPAT_MAX HN_RNDIS_RID_COMPAT_MASK
70 #define HN_RNDIS_XFER_SIZE 2048
73 * Forward declarations
75 static void hv_rf_receive_indicate_status(struct hn_softc *sc,
76 const void *data, int dlen);
77 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
78 const void *data, int dlen);
79 static int hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr);
80 static int hv_rf_query_device_link_status(struct hn_softc *sc,
81 uint32_t *link_status);
82 static int hv_rf_init_device(struct hn_softc *sc);
84 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
85 const void *idata, size_t idlen, void *odata, size_t *odlen0);
86 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
88 static int hn_rndis_conf_offload(struct hn_softc *sc);
89 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
90 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
92 static __inline uint32_t
93 hn_rndis_rid(struct hn_softc *sc)
98 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
102 /* Use upper 16 bits for non-compat RNDIS messages. */
103 return ((rid & 0xffff) << 16);
107 hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
108 size_t pi_dlen, uint32_t pi_type)
110 const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
111 struct rndis_pktinfo *pi;
113 KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
114 ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
117 * Per-packet-info does not move; it only grows.
120 * rm_pktinfooffset in this phase counts from the beginning
121 * of rndis_packet_msg.
123 KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
124 ("%u pktinfo overflows RNDIS packet msg", pi_type));
125 pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
127 pkt->rm_pktinfolen += pi_size;
129 pi->rm_size = pi_size;
130 pi->rm_type = pi_type;
131 pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
133 /* Data immediately follow per-packet-info. */
134 pkt->rm_dataoffset += pi_size;
136 /* Update RNDIS packet msg length */
137 pkt->rm_len += pi_size;
139 return (pi->rm_data);
143 * RNDIS filter receive indicate status
146 hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
148 const struct rndis_status_msg *msg;
150 if (dlen < sizeof(*msg)) {
151 if_printf(sc->hn_ifp, "invalid RNDIS status\n");
156 switch (msg->rm_status) {
157 case RNDIS_STATUS_MEDIA_CONNECT:
158 netvsc_linkstatus_callback(sc, 1);
161 case RNDIS_STATUS_MEDIA_DISCONNECT:
162 netvsc_linkstatus_callback(sc, 0);
167 if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
174 hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
176 const struct rndis_pktinfo *pi = info_data;
179 while (info_dlen != 0) {
183 if (__predict_false(info_dlen < sizeof(*pi)))
185 if (__predict_false(info_dlen < pi->rm_size))
187 info_dlen -= pi->rm_size;
189 if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
191 if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
193 dlen = pi->rm_size - pi->rm_pktinfooffset;
196 switch (pi->rm_type) {
197 case NDIS_PKTINFO_TYPE_VLAN:
198 if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
200 info->vlan_info = *((const uint32_t *)data);
201 mask |= HV_RF_RECVINFO_VLAN;
204 case NDIS_PKTINFO_TYPE_CSUM:
205 if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
207 info->csum_info = *((const uint32_t *)data);
208 mask |= HV_RF_RECVINFO_CSUM;
211 case HN_NDIS_PKTINFO_TYPE_HASHVAL:
212 if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
214 info->hash_value = *((const uint32_t *)data);
215 mask |= HV_RF_RECVINFO_HASHVAL;
218 case HN_NDIS_PKTINFO_TYPE_HASHINF:
219 if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
221 info->hash_info = *((const uint32_t *)data);
222 mask |= HV_RF_RECVINFO_HASHINF;
229 if (mask == HV_RF_RECVINFO_ALL) {
230 /* All found; done */
234 pi = (const struct rndis_pktinfo *)
235 ((const uint8_t *)pi + pi->rm_size);
240 * - If there is no hash value, invalidate the hash info.
242 if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
243 info->hash_info = HN_NDIS_HASH_INFO_INVALID;
248 hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
251 if (off < check_off) {
252 if (__predict_true(off + len <= check_off))
254 } else if (off > check_off) {
255 if (__predict_true(check_off + check_len <= off))
262 * RNDIS filter receive data
265 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
267 const struct rndis_packet_msg *pkt;
268 struct hn_recvinfo info;
269 int data_off, pktinfo_off, data_len, pktinfo_len;
274 if (__predict_false(dlen < sizeof(*pkt))) {
275 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
280 if (__predict_false(dlen < pkt->rm_len)) {
281 if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
282 "dlen %d, msglen %u\n", dlen, pkt->rm_len);
285 if (__predict_false(pkt->rm_len <
286 pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
287 if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
288 "msglen %u, data %u, oob %u, pktinfo %u\n",
289 pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
293 if (__predict_false(pkt->rm_datalen == 0)) {
294 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
301 #define IS_OFFSET_INVALID(ofs) \
302 ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
303 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
305 /* XXX Hyper-V does not meet data offset alignment requirement */
306 if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
307 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
308 "data offset %u\n", pkt->rm_dataoffset);
311 if (__predict_false(pkt->rm_oobdataoffset > 0 &&
312 IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
313 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
314 "oob offset %u\n", pkt->rm_oobdataoffset);
317 if (__predict_true(pkt->rm_pktinfooffset > 0) &&
318 __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
319 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
320 "pktinfo offset %u\n", pkt->rm_pktinfooffset);
324 #undef IS_OFFSET_INVALID
326 data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
327 data_len = pkt->rm_datalen;
328 pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
329 pktinfo_len = pkt->rm_pktinfolen;
332 * Check OOB coverage.
334 if (__predict_false(pkt->rm_oobdatalen != 0)) {
335 int oob_off, oob_len;
337 if_printf(rxr->hn_ifp, "got oobdata\n");
338 oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
339 oob_len = pkt->rm_oobdatalen;
341 if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
342 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
343 "oob overflow, msglen %u, oob abs %d len %d\n",
344 pkt->rm_len, oob_off, oob_len);
349 * Check against data.
351 if (hn_rndis_check_overlap(oob_off, oob_len,
352 data_off, data_len)) {
353 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
354 "oob overlaps data, oob abs %d len %d, "
355 "data abs %d len %d\n",
356 oob_off, oob_len, data_off, data_len);
361 * Check against pktinfo.
363 if (pktinfo_len != 0 &&
364 hn_rndis_check_overlap(oob_off, oob_len,
365 pktinfo_off, pktinfo_len)) {
366 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
367 "oob overlaps pktinfo, oob abs %d len %d, "
368 "pktinfo abs %d len %d\n",
369 oob_off, oob_len, pktinfo_off, pktinfo_len);
375 * Check per-packet-info coverage and find useful per-packet-info.
377 info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
378 info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
379 info.hash_info = HN_NDIS_HASH_INFO_INVALID;
380 if (__predict_true(pktinfo_len != 0)) {
384 if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
385 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
386 "pktinfo overflow, msglen %u, "
387 "pktinfo abs %d len %d\n",
388 pkt->rm_len, pktinfo_off, pktinfo_len);
393 * Check packet info coverage.
395 overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
397 if (__predict_false(overlap)) {
398 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
399 "pktinfo overlap data, pktinfo abs %d len %d, "
400 "data abs %d len %d\n",
401 pktinfo_off, pktinfo_len, data_off, data_len);
406 * Find useful per-packet-info.
408 error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
410 if (__predict_false(error)) {
411 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
417 if (__predict_false(data_off + data_len > pkt->rm_len)) {
418 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
419 "data overflow, msglen %u, data abs %d len %d\n",
420 pkt->rm_len, data_off, data_len);
423 hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
427 * RNDIS filter on receive
430 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
431 const void *data, int dlen)
433 const struct rndis_comp_hdr *comp;
434 const struct rndis_msghdr *hdr;
436 if (__predict_false(dlen < sizeof(*hdr))) {
437 if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
442 switch (hdr->rm_type) {
443 case REMOTE_NDIS_PACKET_MSG:
444 hv_rf_receive_data(rxr, data, dlen);
447 case REMOTE_NDIS_INITIALIZE_CMPLT:
448 case REMOTE_NDIS_QUERY_CMPLT:
449 case REMOTE_NDIS_SET_CMPLT:
450 case REMOTE_NDIS_KEEPALIVE_CMPLT: /* unused */
451 if (dlen < sizeof(*comp)) {
452 if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
457 KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
458 ("invalid RNDIS rid 0x%08x\n", comp->rm_rid));
459 vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
462 case REMOTE_NDIS_INDICATE_STATUS_MSG:
463 hv_rf_receive_indicate_status(sc, data, dlen);
466 case REMOTE_NDIS_RESET_CMPLT:
468 * Reset completed, no rid.
471 * RESET is not issued by hn(4), so this message should
474 if_printf(rxr->hn_ifp, "RESET cmplt received\n");
478 if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
485 * RNDIS filter query device MAC address
488 hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
493 eaddr_len = ETHER_ADDR_LEN;
494 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
498 if (eaddr_len != ETHER_ADDR_LEN) {
499 if_printf(sc->hn_ifp, "invalid eaddr len %zu\n", eaddr_len);
506 * RNDIS filter query device link status
509 hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
514 size = sizeof(*link_status);
515 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
519 if (size != sizeof(uint32_t)) {
520 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
526 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
527 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
528 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
529 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
530 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
531 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
535 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
536 struct hn_send_ctx *sndc, size_t *comp_len)
538 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
542 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
543 ("invalid request length %zu", reqlen));
548 paddr = vmbus_xact_req_paddr(xact);
549 KASSERT((paddr & PAGE_MASK) == 0,
550 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
551 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
559 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
560 gpa[gpa_cnt].gpa_len = len;
561 gpa[gpa_cnt].gpa_ofs = 0;
565 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
568 * Send this RNDIS control message and wait for its completion
571 vmbus_xact_activate(xact);
572 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
575 vmbus_xact_deactivate(xact);
576 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
579 return (vmbus_xact_wait(xact, comp_len));
583 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
584 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
586 const struct rndis_comp_hdr *comp;
587 size_t comp_len, min_complen = *comp_len0;
589 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
590 KASSERT(min_complen >= sizeof(*comp),
591 ("invalid minimum complete len %zu", min_complen));
594 * Execute the xact setup by the caller.
596 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
602 * Check this RNDIS complete message.
604 if (comp_len < min_complen) {
605 if (comp_len >= sizeof(*comp)) {
606 /* rm_status field is valid */
607 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
608 "status 0x%08x\n", comp_len, comp->rm_status);
610 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
615 if (comp->rm_len < min_complen) {
616 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
620 if (comp->rm_type != comp_type) {
621 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
622 "expect 0x%08x\n", comp->rm_type, comp_type);
625 if (comp->rm_rid != rid) {
626 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
627 "expect %u\n", comp->rm_rid, rid);
631 *comp_len0 = comp_len;
636 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
637 const void *idata, size_t idlen, void *odata, size_t *odlen0)
639 struct rndis_query_req *req;
640 const struct rndis_query_comp *comp;
641 struct vmbus_xact *xact;
642 size_t reqlen, odlen = *odlen0, comp_len;
646 reqlen = sizeof(*req) + idlen;
647 xact = vmbus_xact_get(sc->hn_xact, reqlen);
649 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
652 rid = hn_rndis_rid(sc);
653 req = vmbus_xact_req_data(xact);
654 req->rm_type = REMOTE_NDIS_QUERY_MSG;
655 req->rm_len = reqlen;
660 * This is _not_ RNDIS Spec conforming:
661 * "This MUST be set to 0 when there is no input data
662 * associated with the OID."
664 * If this field was set to 0 according to the RNDIS Spec,
665 * Hyper-V would set non-SUCCESS status in the query
668 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
671 req->rm_infobuflen = idlen;
672 /* Input data immediately follows RNDIS query. */
673 memcpy(req + 1, idata, idlen);
676 comp_len = sizeof(*comp) + odlen;
677 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
678 REMOTE_NDIS_QUERY_CMPLT);
680 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
685 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
686 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
687 "status 0x%08x\n", oid, comp->rm_status);
691 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
692 /* No output data! */
693 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
700 * Check output data length and offset.
702 /* ofs is the offset from the beginning of comp. */
703 ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->rm_infobufoffset);
704 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
705 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
706 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
714 if (comp->rm_infobuflen < odlen)
715 odlen = comp->rm_infobuflen;
716 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
721 vmbus_xact_put(xact);
726 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
728 struct ndis_rss_caps in, caps;
733 * Only NDIS 6.30+ is supported.
735 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
736 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
739 memset(&in, 0, sizeof(in));
740 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
741 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
742 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
744 caps_len = NDIS_RSS_CAPS_SIZE;
745 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
746 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
749 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
750 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
755 if (caps.ndis_nrxr == 0) {
756 if_printf(sc->hn_ifp, "0 RX rings!?\n");
759 *rxr_cnt = caps.ndis_nrxr;
761 if (caps_len == NDIS_RSS_CAPS_SIZE) {
763 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
771 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
773 struct rndis_set_req *req;
774 const struct rndis_set_comp *comp;
775 struct vmbus_xact *xact;
776 size_t reqlen, comp_len;
780 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
782 reqlen = sizeof(*req) + dlen;
783 xact = vmbus_xact_get(sc->hn_xact, reqlen);
785 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
788 rid = hn_rndis_rid(sc);
789 req = vmbus_xact_req_data(xact);
790 req->rm_type = REMOTE_NDIS_SET_MSG;
791 req->rm_len = reqlen;
794 req->rm_infobuflen = dlen;
795 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
796 /* Data immediately follows RNDIS set. */
797 memcpy(req + 1, data, dlen);
799 comp_len = sizeof(*comp);
800 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
801 REMOTE_NDIS_SET_CMPLT);
803 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
808 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
809 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
810 "status 0x%08x\n", oid, comp->rm_status);
816 vmbus_xact_put(xact);
821 hn_rndis_conf_offload(struct hn_softc *sc)
823 struct ndis_offload_params params;
827 /* NOTE: 0 means "no change" */
828 memset(¶ms, 0, sizeof(params));
830 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
831 if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
832 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
833 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
835 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
836 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
838 params.ndis_hdr.ndis_size = paramsz;
840 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
841 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
842 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
843 if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
844 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
845 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
847 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
848 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
850 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
852 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
855 if_printf(sc->hn_ifp, "offload config done\n");
861 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
863 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
864 struct ndis_rss_params *prm = &rss->rss_params;
868 * Only NDIS 6.30+ is supported.
870 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
871 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
873 memset(rss, 0, sizeof(*rss));
874 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
875 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
876 prm->ndis_hdr.ndis_size = sizeof(*rss);
877 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
878 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
879 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
880 /* TODO: Take ndis_rss_caps.ndis_nind into account */
881 prm->ndis_indsize = sizeof(rss->rss_ind);
882 prm->ndis_indoffset =
883 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
884 prm->ndis_keysize = sizeof(rss->rss_key);
885 prm->ndis_keyoffset =
886 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
889 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
891 /* Setup RSS indirect table */
892 /* TODO: Take ndis_rss_caps.ndis_nind into account */
893 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
894 rss->rss_ind[i] = i % nchan;
896 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
899 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
902 if_printf(sc->hn_ifp, "RSS config done\n");
908 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
912 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
913 &filter, sizeof(filter));
915 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
919 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
927 * RNDIS filter init device
930 hv_rf_init_device(struct hn_softc *sc)
932 struct rndis_init_req *req;
933 const struct rndis_init_comp *comp;
934 struct vmbus_xact *xact;
939 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
941 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
944 rid = hn_rndis_rid(sc);
945 req = vmbus_xact_req_data(xact);
946 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
947 req->rm_len = sizeof(*req);
949 req->rm_ver_major = RNDIS_VERSION_MAJOR;
950 req->rm_ver_minor = RNDIS_VERSION_MINOR;
951 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
953 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
954 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
955 REMOTE_NDIS_INITIALIZE_CMPLT);
957 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
962 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
963 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
969 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u, "
970 "align %u\n", comp->rm_ver_major, comp->rm_ver_minor,
971 comp->rm_pktmaxsz, comp->rm_pktmaxcnt,
972 1U << comp->rm_align);
976 vmbus_xact_put(xact);
981 * RNDIS filter halt device
984 hv_rf_halt_device(struct hn_softc *sc)
986 struct vmbus_xact *xact;
987 struct rndis_halt_req *halt;
988 struct hn_send_ctx sndc;
991 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
993 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
996 halt = vmbus_xact_req_data(xact);
997 halt->rm_type = REMOTE_NDIS_HALT_MSG;
998 halt->rm_len = sizeof(*halt);
999 halt->rm_rid = hn_rndis_rid(sc);
1001 /* No RNDIS completion; rely on NVS message send completion */
1002 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
1003 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
1005 vmbus_xact_put(xact);
1007 if_printf(sc->hn_ifp, "RNDIS halt done\n");
1012 * RNDIS filter on device add
1015 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1016 int *nchan0, struct hn_rx_ring *rxr)
1019 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1020 device_t dev = sc->hn_dev;
1021 struct hn_nvs_subch_req *req;
1022 const struct hn_nvs_subch_resp *resp;
1024 struct vmbus_xact *xact = NULL;
1025 uint32_t status, nsubch;
1026 int nchan = *nchan0;
1030 * Let the inner driver handle this first to create the netvsc channel
1031 * NOTE! Once the channel is created, we may get a receive callback
1032 * (hv_rf_on_receive()) before this call is completed.
1033 * Note: Earlier code used a function pointer here.
1035 ret = hv_nv_on_device_add(sc, rxr);
1040 * Initialize the rndis device
1043 /* Send the rndis initialization message */
1044 ret = hv_rf_init_device(sc);
1047 * TODO: If rndis init failed, we will need to shut down
1052 /* Get the mac address */
1053 ret = hv_rf_query_device_mac(sc, dev_info->mac_addr);
1055 /* TODO: shut down rndis device and the channel */
1058 /* Configure NDIS offload settings */
1059 hn_rndis_conf_offload(sc);
1061 hv_rf_query_device_link_status(sc, &dev_info->link_state);
1063 if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) {
1065 * Either RSS is not supported, or multiple RX/TX rings
1066 * are not requested.
1073 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1076 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1078 /* No RSS; this is benign. */
1082 if (nchan > rxr_cnt)
1084 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1088 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1093 * Ask NVS to allocate sub-channels.
1095 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1097 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1101 req = vmbus_xact_req_data(xact);
1102 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1103 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1104 req->nvs_nsubch = nchan - 1;
1106 resp_len = sizeof(*resp);
1107 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
1108 HN_NVS_TYPE_SUBCH_RESP);
1110 if_printf(sc->hn_ifp, "exec subch failed\n");
1115 status = resp->nvs_status;
1116 nsubch = resp->nvs_nsubch;
1117 vmbus_xact_put(xact);
1120 if (status != HN_NVS_STATUS_OK) {
1121 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1125 if (nsubch > nchan - 1) {
1126 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1132 ret = hn_rndis_conf_rss(sc, nchan);
1139 vmbus_xact_put(xact);
1144 * RNDIS filter on device remove
1147 hv_rf_on_device_remove(struct hn_softc *sc)
1151 /* Halt and release the rndis device */
1152 ret = hv_rf_halt_device(sc);
1154 /* Pass control to inner driver to remove the device */
1155 ret |= hv_nv_on_device_remove(sc);
1161 * RNDIS filter on open
1164 hv_rf_on_open(struct hn_softc *sc)
1169 if (hv_promisc_mode != 1) {
1170 filter = NDIS_PACKET_TYPE_BROADCAST |
1171 NDIS_PACKET_TYPE_ALL_MULTICAST |
1172 NDIS_PACKET_TYPE_DIRECTED;
1174 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1176 return (hn_rndis_set_rxfilter(sc, filter));
1180 * RNDIS filter on close
1183 hv_rf_on_close(struct hn_softc *sc)
1186 return (hn_rndis_set_rxfilter(sc, 0));
1190 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1193 hn_chan_rollup(rxr, txr);