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);
80 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
81 const void *idata, size_t idlen, void *odata, size_t *odlen0);
82 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
84 static int hn_rndis_conf_offload(struct hn_softc *sc);
86 static __inline uint32_t
87 hn_rndis_rid(struct hn_softc *sc)
92 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
96 /* Use upper 16 bits for non-compat RNDIS messages. */
97 return ((rid & 0xffff) << 16);
101 hn_rndis_pktinfo_append(struct rndis_packet_msg *pkt, size_t pktsize,
102 size_t pi_dlen, uint32_t pi_type)
104 const size_t pi_size = HN_RNDIS_PKTINFO_SIZE(pi_dlen);
105 struct rndis_pktinfo *pi;
107 KASSERT((pi_size & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK) == 0,
108 ("unaligned pktinfo size %zu, pktinfo dlen %zu", pi_size, pi_dlen));
111 * Per-packet-info does not move; it only grows.
114 * rm_pktinfooffset in this phase counts from the beginning
115 * of rndis_packet_msg.
117 KASSERT(pkt->rm_pktinfooffset + pkt->rm_pktinfolen + pi_size <= pktsize,
118 ("%u pktinfo overflows RNDIS packet msg", pi_type));
119 pi = (struct rndis_pktinfo *)((uint8_t *)pkt + pkt->rm_pktinfooffset +
121 pkt->rm_pktinfolen += pi_size;
123 pi->rm_size = pi_size;
124 pi->rm_type = pi_type;
125 pi->rm_pktinfooffset = RNDIS_PKTINFO_OFFSET;
127 /* Data immediately follow per-packet-info. */
128 pkt->rm_dataoffset += pi_size;
130 /* Update RNDIS packet msg length */
131 pkt->rm_len += pi_size;
133 return (pi->rm_data);
137 * RNDIS filter receive indicate status
140 hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
142 const struct rndis_status_msg *msg;
144 if (dlen < sizeof(*msg)) {
145 if_printf(sc->hn_ifp, "invalid RNDIS status\n");
150 switch (msg->rm_status) {
151 case RNDIS_STATUS_MEDIA_CONNECT:
152 netvsc_linkstatus_callback(sc, 1);
155 case RNDIS_STATUS_MEDIA_DISCONNECT:
156 netvsc_linkstatus_callback(sc, 0);
159 case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
160 /* Not really useful; ignore. */
163 case RNDIS_STATUS_NETWORK_CHANGE:
165 if_printf(sc->hn_ifp, "network changed\n");
170 if_printf(sc->hn_ifp, "unknown RNDIS status 0x%08x\n",
177 hn_rndis_rxinfo(const void *info_data, int info_dlen, struct hn_recvinfo *info)
179 const struct rndis_pktinfo *pi = info_data;
182 while (info_dlen != 0) {
186 if (__predict_false(info_dlen < sizeof(*pi)))
188 if (__predict_false(info_dlen < pi->rm_size))
190 info_dlen -= pi->rm_size;
192 if (__predict_false(pi->rm_size & RNDIS_PKTINFO_SIZE_ALIGNMASK))
194 if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
196 dlen = pi->rm_size - pi->rm_pktinfooffset;
199 switch (pi->rm_type) {
200 case NDIS_PKTINFO_TYPE_VLAN:
201 if (__predict_false(dlen < NDIS_VLAN_INFO_SIZE))
203 info->vlan_info = *((const uint32_t *)data);
204 mask |= HV_RF_RECVINFO_VLAN;
207 case NDIS_PKTINFO_TYPE_CSUM:
208 if (__predict_false(dlen < NDIS_RXCSUM_INFO_SIZE))
210 info->csum_info = *((const uint32_t *)data);
211 mask |= HV_RF_RECVINFO_CSUM;
214 case HN_NDIS_PKTINFO_TYPE_HASHVAL:
215 if (__predict_false(dlen < HN_NDIS_HASH_VALUE_SIZE))
217 info->hash_value = *((const uint32_t *)data);
218 mask |= HV_RF_RECVINFO_HASHVAL;
221 case HN_NDIS_PKTINFO_TYPE_HASHINF:
222 if (__predict_false(dlen < HN_NDIS_HASH_INFO_SIZE))
224 info->hash_info = *((const uint32_t *)data);
225 mask |= HV_RF_RECVINFO_HASHINF;
232 if (mask == HV_RF_RECVINFO_ALL) {
233 /* All found; done */
237 pi = (const struct rndis_pktinfo *)
238 ((const uint8_t *)pi + pi->rm_size);
243 * - If there is no hash value, invalidate the hash info.
245 if ((mask & HV_RF_RECVINFO_HASHVAL) == 0)
246 info->hash_info = HN_NDIS_HASH_INFO_INVALID;
251 hn_rndis_check_overlap(int off, int len, int check_off, int check_len)
254 if (off < check_off) {
255 if (__predict_true(off + len <= check_off))
257 } else if (off > check_off) {
258 if (__predict_true(check_off + check_len <= off))
265 * RNDIS filter receive data
268 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
270 const struct rndis_packet_msg *pkt;
271 struct hn_recvinfo info;
272 int data_off, pktinfo_off, data_len, pktinfo_len;
277 if (__predict_false(dlen < sizeof(*pkt))) {
278 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg\n");
283 if (__predict_false(dlen < pkt->rm_len)) {
284 if_printf(rxr->hn_ifp, "truncated RNDIS packet msg, "
285 "dlen %d, msglen %u\n", dlen, pkt->rm_len);
288 if (__predict_false(pkt->rm_len <
289 pkt->rm_datalen + pkt->rm_oobdatalen + pkt->rm_pktinfolen)) {
290 if_printf(rxr->hn_ifp, "invalid RNDIS packet msglen, "
291 "msglen %u, data %u, oob %u, pktinfo %u\n",
292 pkt->rm_len, pkt->rm_datalen, pkt->rm_oobdatalen,
296 if (__predict_false(pkt->rm_datalen == 0)) {
297 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, no data\n");
304 #define IS_OFFSET_INVALID(ofs) \
305 ((ofs) < RNDIS_PACKET_MSG_OFFSET_MIN || \
306 ((ofs) & RNDIS_PACKET_MSG_OFFSET_ALIGNMASK))
308 /* XXX Hyper-V does not meet data offset alignment requirement */
309 if (__predict_false(pkt->rm_dataoffset < RNDIS_PACKET_MSG_OFFSET_MIN)) {
310 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
311 "data offset %u\n", pkt->rm_dataoffset);
314 if (__predict_false(pkt->rm_oobdataoffset > 0 &&
315 IS_OFFSET_INVALID(pkt->rm_oobdataoffset))) {
316 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
317 "oob offset %u\n", pkt->rm_oobdataoffset);
320 if (__predict_true(pkt->rm_pktinfooffset > 0) &&
321 __predict_false(IS_OFFSET_INVALID(pkt->rm_pktinfooffset))) {
322 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
323 "pktinfo offset %u\n", pkt->rm_pktinfooffset);
327 #undef IS_OFFSET_INVALID
329 data_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_dataoffset);
330 data_len = pkt->rm_datalen;
331 pktinfo_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_pktinfooffset);
332 pktinfo_len = pkt->rm_pktinfolen;
335 * Check OOB coverage.
337 if (__predict_false(pkt->rm_oobdatalen != 0)) {
338 int oob_off, oob_len;
340 if_printf(rxr->hn_ifp, "got oobdata\n");
341 oob_off = RNDIS_PACKET_MSG_OFFSET_ABS(pkt->rm_oobdataoffset);
342 oob_len = pkt->rm_oobdatalen;
344 if (__predict_false(oob_off + oob_len > pkt->rm_len)) {
345 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
346 "oob overflow, msglen %u, oob abs %d len %d\n",
347 pkt->rm_len, oob_off, oob_len);
352 * Check against data.
354 if (hn_rndis_check_overlap(oob_off, oob_len,
355 data_off, data_len)) {
356 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
357 "oob overlaps data, oob abs %d len %d, "
358 "data abs %d len %d\n",
359 oob_off, oob_len, data_off, data_len);
364 * Check against pktinfo.
366 if (pktinfo_len != 0 &&
367 hn_rndis_check_overlap(oob_off, oob_len,
368 pktinfo_off, pktinfo_len)) {
369 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
370 "oob overlaps pktinfo, oob abs %d len %d, "
371 "pktinfo abs %d len %d\n",
372 oob_off, oob_len, pktinfo_off, pktinfo_len);
378 * Check per-packet-info coverage and find useful per-packet-info.
380 info.vlan_info = HN_NDIS_VLAN_INFO_INVALID;
381 info.csum_info = HN_NDIS_RXCSUM_INFO_INVALID;
382 info.hash_info = HN_NDIS_HASH_INFO_INVALID;
383 if (__predict_true(pktinfo_len != 0)) {
387 if (__predict_false(pktinfo_off + pktinfo_len > pkt->rm_len)) {
388 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
389 "pktinfo overflow, msglen %u, "
390 "pktinfo abs %d len %d\n",
391 pkt->rm_len, pktinfo_off, pktinfo_len);
396 * Check packet info coverage.
398 overlap = hn_rndis_check_overlap(pktinfo_off, pktinfo_len,
400 if (__predict_false(overlap)) {
401 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
402 "pktinfo overlap data, pktinfo abs %d len %d, "
403 "data abs %d len %d\n",
404 pktinfo_off, pktinfo_len, data_off, data_len);
409 * Find useful per-packet-info.
411 error = hn_rndis_rxinfo(((const uint8_t *)pkt) + pktinfo_off,
413 if (__predict_false(error)) {
414 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg "
420 if (__predict_false(data_off + data_len > pkt->rm_len)) {
421 if_printf(rxr->hn_ifp, "invalid RNDIS packet msg, "
422 "data overflow, msglen %u, data abs %d len %d\n",
423 pkt->rm_len, data_off, data_len);
426 hn_rxpkt(rxr, ((const uint8_t *)pkt) + data_off, data_len, &info);
430 * RNDIS filter on receive
433 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
434 const void *data, int dlen)
436 const struct rndis_comp_hdr *comp;
437 const struct rndis_msghdr *hdr;
439 if (__predict_false(dlen < sizeof(*hdr))) {
440 if_printf(rxr->hn_ifp, "invalid RNDIS msg\n");
445 switch (hdr->rm_type) {
446 case REMOTE_NDIS_PACKET_MSG:
447 hv_rf_receive_data(rxr, data, dlen);
450 case REMOTE_NDIS_INITIALIZE_CMPLT:
451 case REMOTE_NDIS_QUERY_CMPLT:
452 case REMOTE_NDIS_SET_CMPLT:
453 case REMOTE_NDIS_KEEPALIVE_CMPLT: /* unused */
454 if (dlen < sizeof(*comp)) {
455 if_printf(rxr->hn_ifp, "invalid RNDIS cmplt\n");
460 KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
461 ("invalid RNDIS rid 0x%08x\n", comp->rm_rid));
462 vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
465 case REMOTE_NDIS_INDICATE_STATUS_MSG:
466 hv_rf_receive_indicate_status(sc, data, dlen);
469 case REMOTE_NDIS_RESET_CMPLT:
471 * Reset completed, no rid.
474 * RESET is not issued by hn(4), so this message should
477 if_printf(rxr->hn_ifp, "RESET cmplt received\n");
481 if_printf(rxr->hn_ifp, "unknown RNDIS msg 0x%x\n",
488 hn_rndis_get_eaddr(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 hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status)
511 size = sizeof(*link_status);
512 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
516 if (size != sizeof(uint32_t)) {
517 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
524 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
525 struct hn_send_ctx *sndc, size_t *comp_len)
527 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
531 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
532 ("invalid request length %zu", reqlen));
537 paddr = vmbus_xact_req_paddr(xact);
538 KASSERT((paddr & PAGE_MASK) == 0,
539 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
540 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
548 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
549 gpa[gpa_cnt].gpa_len = len;
550 gpa[gpa_cnt].gpa_ofs = 0;
554 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
557 * Send this RNDIS control message and wait for its completion
560 vmbus_xact_activate(xact);
561 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
564 vmbus_xact_deactivate(xact);
565 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
568 return (vmbus_xact_wait(xact, comp_len));
572 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
573 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
575 const struct rndis_comp_hdr *comp;
576 size_t comp_len, min_complen = *comp_len0;
578 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
579 KASSERT(min_complen >= sizeof(*comp),
580 ("invalid minimum complete len %zu", min_complen));
583 * Execute the xact setup by the caller.
585 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
591 * Check this RNDIS complete message.
593 if (comp_len < min_complen) {
594 if (comp_len >= sizeof(*comp)) {
595 /* rm_status field is valid */
596 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
597 "status 0x%08x\n", comp_len, comp->rm_status);
599 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
604 if (comp->rm_len < min_complen) {
605 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
609 if (comp->rm_type != comp_type) {
610 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
611 "expect 0x%08x\n", comp->rm_type, comp_type);
614 if (comp->rm_rid != rid) {
615 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
616 "expect %u\n", comp->rm_rid, rid);
620 *comp_len0 = comp_len;
625 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
626 const void *idata, size_t idlen, void *odata, size_t *odlen0)
628 struct rndis_query_req *req;
629 const struct rndis_query_comp *comp;
630 struct vmbus_xact *xact;
631 size_t reqlen, odlen = *odlen0, comp_len;
635 reqlen = sizeof(*req) + idlen;
636 xact = vmbus_xact_get(sc->hn_xact, reqlen);
638 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
641 rid = hn_rndis_rid(sc);
642 req = vmbus_xact_req_data(xact);
643 req->rm_type = REMOTE_NDIS_QUERY_MSG;
644 req->rm_len = reqlen;
649 * This is _not_ RNDIS Spec conforming:
650 * "This MUST be set to 0 when there is no input data
651 * associated with the OID."
653 * If this field was set to 0 according to the RNDIS Spec,
654 * Hyper-V would set non-SUCCESS status in the query
657 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
660 req->rm_infobuflen = idlen;
661 /* Input data immediately follows RNDIS query. */
662 memcpy(req + 1, idata, idlen);
665 comp_len = sizeof(*comp) + odlen;
666 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
667 REMOTE_NDIS_QUERY_CMPLT);
669 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
674 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
675 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
676 "status 0x%08x\n", oid, comp->rm_status);
680 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
681 /* No output data! */
682 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
689 * Check output data length and offset.
691 /* ofs is the offset from the beginning of comp. */
692 ofs = RNDIS_QUERY_COMP_INFOBUFOFFSET_ABS(comp->rm_infobufoffset);
693 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
694 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
695 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
703 if (comp->rm_infobuflen < odlen)
704 odlen = comp->rm_infobuflen;
705 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
710 vmbus_xact_put(xact);
715 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
717 struct ndis_rss_caps in, caps;
722 * Only NDIS 6.30+ is supported.
724 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
725 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
728 memset(&in, 0, sizeof(in));
729 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
730 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
731 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
733 caps_len = NDIS_RSS_CAPS_SIZE;
734 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
735 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
738 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
739 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
744 if (caps.ndis_nrxr == 0) {
745 if_printf(sc->hn_ifp, "0 RX rings!?\n");
748 *rxr_cnt = caps.ndis_nrxr;
750 if (caps_len == NDIS_RSS_CAPS_SIZE) {
752 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
760 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
762 struct rndis_set_req *req;
763 const struct rndis_set_comp *comp;
764 struct vmbus_xact *xact;
765 size_t reqlen, comp_len;
769 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
771 reqlen = sizeof(*req) + dlen;
772 xact = vmbus_xact_get(sc->hn_xact, reqlen);
774 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
777 rid = hn_rndis_rid(sc);
778 req = vmbus_xact_req_data(xact);
779 req->rm_type = REMOTE_NDIS_SET_MSG;
780 req->rm_len = reqlen;
783 req->rm_infobuflen = dlen;
784 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
785 /* Data immediately follows RNDIS set. */
786 memcpy(req + 1, data, dlen);
788 comp_len = sizeof(*comp);
789 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
790 REMOTE_NDIS_SET_CMPLT);
792 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
797 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
798 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
799 "status 0x%08x\n", oid, comp->rm_status);
805 vmbus_xact_put(xact);
810 hn_rndis_conf_offload(struct hn_softc *sc)
812 struct ndis_offload_params params;
817 /* NOTE: 0 means "no change" */
818 memset(¶ms, 0, sizeof(params));
820 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
821 if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) {
822 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
823 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
825 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
826 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
828 params.ndis_hdr.ndis_size = paramsz;
830 caps = HN_CAP_IPCS | HN_CAP_TCP4CS | HN_CAP_TCP6CS;
831 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
832 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
833 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
834 if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) {
835 caps |= HN_CAP_UDP4CS | HN_CAP_UDP6CS;
836 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
837 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
840 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
841 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
843 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
845 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
850 if_printf(sc->hn_ifp, "offload config done\n");
856 hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags)
858 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
859 struct ndis_rss_params *prm = &rss->rss_params;
863 * Only NDIS 6.30+ is supported.
865 KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30,
866 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
870 * DO NOT whack rss_key and rss_ind, which are setup by the caller.
872 memset(prm, 0, sizeof(*prm));
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_flags = flags;
878 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
879 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
880 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
881 /* TODO: Take ndis_rss_caps.ndis_nind into account */
882 prm->ndis_indsize = sizeof(rss->rss_ind);
883 prm->ndis_indoffset =
884 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
885 prm->ndis_keysize = sizeof(rss->rss_key);
886 prm->ndis_keyoffset =
887 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
889 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
892 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
895 if_printf(sc->hn_ifp, "RSS config done\n");
901 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
905 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
906 &filter, sizeof(filter));
908 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
912 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
920 hn_rndis_init(struct hn_softc *sc)
922 struct rndis_init_req *req;
923 const struct rndis_init_comp *comp;
924 struct vmbus_xact *xact;
929 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
931 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
934 rid = hn_rndis_rid(sc);
935 req = vmbus_xact_req_data(xact);
936 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
937 req->rm_len = sizeof(*req);
939 req->rm_ver_major = RNDIS_VERSION_MAJOR;
940 req->rm_ver_minor = RNDIS_VERSION_MINOR;
941 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
943 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
944 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
945 REMOTE_NDIS_INITIALIZE_CMPLT);
947 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
952 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
953 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
959 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u, "
960 "align %u\n", comp->rm_ver_major, comp->rm_ver_minor,
961 comp->rm_pktmaxsz, comp->rm_pktmaxcnt,
962 1U << comp->rm_align);
966 vmbus_xact_put(xact);
971 hn_rndis_halt(struct hn_softc *sc)
973 struct vmbus_xact *xact;
974 struct rndis_halt_req *halt;
975 struct hn_send_ctx sndc;
978 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
980 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
983 halt = vmbus_xact_req_data(xact);
984 halt->rm_type = REMOTE_NDIS_HALT_MSG;
985 halt->rm_len = sizeof(*halt);
986 halt->rm_rid = hn_rndis_rid(sc);
988 /* No RNDIS completion; rely on NVS message send completion */
989 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
990 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
992 vmbus_xact_put(xact);
994 if_printf(sc->hn_ifp, "RNDIS halt done\n");
999 hn_rndis_attach(struct hn_softc *sc)
1006 error = hn_rndis_init(sc);
1011 * Configure NDIS offload settings.
1012 * XXX no offloading, if error happened?
1014 hn_rndis_conf_offload(sc);
1019 hn_rndis_detach(struct hn_softc *sc)
1022 /* Halt the RNDIS. */
1027 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1030 hn_chan_rollup(rxr, txr);