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 <sys/types.h>
42 #include <machine/atomic.h>
45 #include <vm/vm_param.h>
48 #include <dev/hyperv/include/hyperv.h>
49 #include <dev/hyperv/include/vmbus_xact.h>
50 #include <dev/hyperv/netvsc/hv_net_vsc.h>
51 #include <dev/hyperv/netvsc/hv_rndis.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 rndis_msg *response);
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 * Set the Per-Packet-Info with the specified type
109 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
112 rndis_packet *rndis_pkt;
113 rndis_per_packet_info *rppi;
115 rndis_pkt = &rndis_mesg->msg.packet;
116 rndis_pkt->data_offset += rppi_size;
118 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
119 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
121 rppi->size = rppi_size;
122 rppi->type = pkt_type;
123 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
125 rndis_pkt->per_pkt_info_length += rppi_size;
131 * RNDIS filter receive indicate status
134 hv_rf_receive_indicate_status(struct hn_softc *sc, const rndis_msg *response)
136 const rndis_indicate_status *indicate = &response->msg.indicate_status;
138 switch(indicate->status) {
139 case RNDIS_STATUS_MEDIA_CONNECT:
140 netvsc_linkstatus_callback(sc, 1);
142 case RNDIS_STATUS_MEDIA_DISCONNECT:
143 netvsc_linkstatus_callback(sc, 0);
147 if_printf(sc->hn_ifp,
148 "unknown status %d received\n", indicate->status);
154 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
156 const struct rndis_pktinfo *pi;
157 uint32_t mask = 0, len;
159 info->vlan_info = NULL;
160 info->csum_info = NULL;
161 info->hash_info = NULL;
162 info->hash_value = NULL;
164 if (rpkt->per_pkt_info_offset == 0)
166 if (__predict_false(rpkt->per_pkt_info_offset &
167 (RNDIS_PKTINFO_ALIGN - 1)))
169 if (__predict_false(rpkt->per_pkt_info_offset <
170 RNDIS_PACKET_MSG_OFFSET_MIN))
173 pi = (const struct rndis_pktinfo *)
174 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
175 len = rpkt->per_pkt_info_length;
181 if (__predict_false(len < sizeof(*pi)))
183 if (__predict_false(len < pi->rm_size))
187 if (__predict_false(pi->rm_size & (RNDIS_PKTINFO_ALIGN - 1)))
189 if (__predict_false(pi->rm_size < pi->rm_pktinfooffset))
191 dlen = pi->rm_size - pi->rm_pktinfooffset;
194 switch (pi->rm_type) {
195 case ieee_8021q_info:
196 if (__predict_false(dlen < sizeof(ndis_8021q_info)))
198 info->vlan_info = data;
199 mask |= HV_RF_RECVINFO_VLAN;
202 case tcpip_chksum_info:
203 if (__predict_false(dlen <
204 sizeof(rndis_tcp_ip_csum_info)))
206 info->csum_info = data;
207 mask |= HV_RF_RECVINFO_CSUM;
211 if (__predict_false(dlen <
212 sizeof(struct rndis_hash_value)))
214 info->hash_value = data;
215 mask |= HV_RF_RECVINFO_HASHVAL;
219 if (__predict_false(dlen <
220 sizeof(struct rndis_hash_info)))
222 info->hash_info = data;
223 mask |= HV_RF_RECVINFO_HASHINF;
230 if (mask == HV_RF_RECVINFO_ALL) {
231 /* All found; done */
235 pi = (const struct rndis_pktinfo *)
236 ((const uint8_t *)pi + pi->rm_size);
242 * RNDIS filter receive data
245 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
247 const rndis_msg *message = data;
248 const rndis_packet *rndis_pkt;
249 uint32_t data_offset;
250 struct hn_recvinfo info;
252 rndis_pkt = &message->msg.packet;
255 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
256 * netvsc packet (ie tot_data_buf_len != message_length)
259 /* Remove rndis header, then pass data packet up the stack */
260 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
263 if (dlen < rndis_pkt->data_length) {
264 if_printf(rxr->hn_ifp,
265 "total length %u is less than data length %u\n",
266 dlen, rndis_pkt->data_length);
270 dlen = rndis_pkt->data_length;
271 data = (const uint8_t *)data + data_offset;
273 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
274 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
277 netvsc_recv(rxr, data, dlen, &info);
281 * RNDIS filter on receive
284 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
285 const void *data, int dlen)
287 const rndis_msg *rndis_hdr;
288 const struct rndis_comp_hdr *comp;
291 switch (rndis_hdr->ndis_msg_type) {
293 case REMOTE_NDIS_PACKET_MSG:
294 hv_rf_receive_data(rxr, data, dlen);
297 /* completion messages */
298 case REMOTE_NDIS_INITIALIZE_CMPLT:
299 case REMOTE_NDIS_QUERY_CMPLT:
300 case REMOTE_NDIS_SET_CMPLT:
301 case REMOTE_NDIS_KEEPALIVE_CMPLT:
303 KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
304 ("invalid rid 0x%08x\n", comp->rm_rid));
305 vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
308 /* notification message */
309 case REMOTE_NDIS_INDICATE_STATUS_MSG:
310 hv_rf_receive_indicate_status(sc, rndis_hdr);
313 case REMOTE_NDIS_RESET_CMPLT:
315 * Reset completed, no rid.
318 * RESET is not issued by hn(4), so this message should
321 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
325 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
326 rndis_hdr->ndis_msg_type);
333 * RNDIS filter query device MAC address
336 hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
341 eaddr_len = ETHER_ADDR_LEN;
342 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
346 if (eaddr_len != ETHER_ADDR_LEN) {
347 if_printf(sc->hn_ifp, "invalid eaddr len %zu\n", eaddr_len);
354 * RNDIS filter query device link status
357 hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
362 size = sizeof(*link_status);
363 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
367 if (size != sizeof(uint32_t)) {
368 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
374 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
375 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
376 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
377 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
378 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
379 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
383 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
384 struct hn_send_ctx *sndc, size_t *comp_len)
386 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
390 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
391 ("invalid request length %zu", reqlen));
396 paddr = vmbus_xact_req_paddr(xact);
397 KASSERT((paddr & PAGE_MASK) == 0,
398 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
399 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
407 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
408 gpa[gpa_cnt].gpa_len = len;
409 gpa[gpa_cnt].gpa_ofs = 0;
413 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
416 * Send this RNDIS control message and wait for its completion
419 vmbus_xact_activate(xact);
420 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
423 vmbus_xact_deactivate(xact);
424 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
427 return (vmbus_xact_wait(xact, comp_len));
431 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
432 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
434 const struct rndis_comp_hdr *comp;
435 size_t comp_len, min_complen = *comp_len0;
437 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
438 KASSERT(min_complen >= sizeof(*comp),
439 ("invalid minimum complete len %zu", min_complen));
442 * Execute the xact setup by the caller.
444 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
450 * Check this RNDIS complete message.
452 if (comp_len < min_complen) {
453 if (comp_len >= sizeof(*comp)) {
454 /* rm_status field is valid */
455 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
456 "status 0x%08x\n", comp_len, comp->rm_status);
458 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
463 if (comp->rm_len < min_complen) {
464 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
468 if (comp->rm_type != comp_type) {
469 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
470 "expect 0x%08x\n", comp->rm_type, comp_type);
473 if (comp->rm_rid != rid) {
474 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
475 "expect %u\n", comp->rm_rid, rid);
479 *comp_len0 = comp_len;
484 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
485 const void *idata, size_t idlen, void *odata, size_t *odlen0)
487 struct rndis_query_req *req;
488 const struct rndis_query_comp *comp;
489 struct vmbus_xact *xact;
490 size_t reqlen, odlen = *odlen0, comp_len;
494 reqlen = sizeof(*req) + idlen;
495 xact = vmbus_xact_get(sc->hn_xact, reqlen);
497 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
500 rid = hn_rndis_rid(sc);
501 req = vmbus_xact_req_data(xact);
502 req->rm_type = REMOTE_NDIS_QUERY_MSG;
503 req->rm_len = reqlen;
508 * This is _not_ RNDIS Spec conforming:
509 * "This MUST be set to 0 when there is no input data
510 * associated with the OID."
512 * If this field was set to 0 according to the RNDIS Spec,
513 * Hyper-V would set non-SUCCESS status in the query
516 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
519 req->rm_infobuflen = idlen;
520 /* Input data immediately follows RNDIS query. */
521 memcpy(req + 1, idata, idlen);
524 comp_len = sizeof(*comp) + odlen;
525 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
526 REMOTE_NDIS_QUERY_CMPLT);
528 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
533 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
534 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
535 "status 0x%08x\n", oid, comp->rm_status);
539 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
540 /* No output data! */
541 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
548 * Check output data length and offset.
550 /* ofs is the offset from the beginning of comp. */
551 ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
552 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
553 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
554 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
562 if (comp->rm_infobuflen < odlen)
563 odlen = comp->rm_infobuflen;
564 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
569 vmbus_xact_put(xact);
574 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
576 struct ndis_rss_caps in, caps;
581 * Only NDIS 6.30+ is supported.
583 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
584 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
587 memset(&in, 0, sizeof(in));
588 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
589 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
590 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
592 caps_len = NDIS_RSS_CAPS_SIZE;
593 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
594 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
597 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
598 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
603 if (caps.ndis_nrxr == 0) {
604 if_printf(sc->hn_ifp, "0 RX rings!?\n");
607 *rxr_cnt = caps.ndis_nrxr;
609 if (caps_len == NDIS_RSS_CAPS_SIZE) {
611 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
619 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
621 struct rndis_set_req *req;
622 const struct rndis_set_comp *comp;
623 struct vmbus_xact *xact;
624 size_t reqlen, comp_len;
628 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
630 reqlen = sizeof(*req) + dlen;
631 xact = vmbus_xact_get(sc->hn_xact, reqlen);
633 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
636 rid = hn_rndis_rid(sc);
637 req = vmbus_xact_req_data(xact);
638 req->rm_type = REMOTE_NDIS_SET_MSG;
639 req->rm_len = reqlen;
642 req->rm_infobuflen = dlen;
643 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
644 /* Data immediately follows RNDIS set. */
645 memcpy(req + 1, data, dlen);
647 comp_len = sizeof(*comp);
648 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
649 REMOTE_NDIS_SET_CMPLT);
651 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
656 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
657 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
658 "status 0x%08x\n", oid, comp->rm_status);
664 vmbus_xact_put(xact);
669 hn_rndis_conf_offload(struct hn_softc *sc)
671 struct ndis_offload_params params;
675 /* NOTE: 0 means "no change" */
676 memset(¶ms, 0, sizeof(params));
678 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
679 if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
680 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
681 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
683 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
684 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
686 params.ndis_hdr.ndis_size = paramsz;
688 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
689 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
690 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
691 if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
692 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
693 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
695 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
696 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
698 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
700 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
703 if_printf(sc->hn_ifp, "offload config done\n");
709 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
711 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
712 struct ndis_rss_params *prm = &rss->rss_params;
716 * Only NDIS 6.30+ is supported.
718 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
719 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
721 memset(rss, 0, sizeof(*rss));
722 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
723 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
724 prm->ndis_hdr.ndis_size = sizeof(*rss);
725 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
726 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
727 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
728 /* TODO: Take ndis_rss_caps.ndis_nind into account */
729 prm->ndis_indsize = sizeof(rss->rss_ind);
730 prm->ndis_indoffset =
731 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
732 prm->ndis_keysize = sizeof(rss->rss_key);
733 prm->ndis_keyoffset =
734 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
737 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
739 /* Setup RSS indirect table */
740 /* TODO: Take ndis_rss_caps.ndis_nind into account */
741 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
742 rss->rss_ind[i] = i % nchan;
744 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
747 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
750 if_printf(sc->hn_ifp, "RSS config done\n");
756 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
760 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
761 &filter, sizeof(filter));
763 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
767 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
775 * RNDIS filter init device
778 hv_rf_init_device(struct hn_softc *sc)
780 struct rndis_init_req *req;
781 const struct rndis_init_comp *comp;
782 struct vmbus_xact *xact;
787 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
789 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
792 rid = hn_rndis_rid(sc);
793 req = vmbus_xact_req_data(xact);
794 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
795 req->rm_len = sizeof(*req);
797 req->rm_ver_major = RNDIS_VERSION_MAJOR;
798 req->rm_ver_minor = RNDIS_VERSION_MINOR;
799 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
801 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
802 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
803 REMOTE_NDIS_INITIALIZE_CMPLT);
805 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
810 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
811 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
817 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u, "
818 "align %u\n", comp->rm_ver_major, comp->rm_ver_minor,
819 comp->rm_pktmaxsz, comp->rm_pktmaxcnt,
820 1U << comp->rm_align);
824 vmbus_xact_put(xact);
829 * RNDIS filter halt device
832 hv_rf_halt_device(struct hn_softc *sc)
834 struct vmbus_xact *xact;
835 struct rndis_halt_req *halt;
836 struct hn_send_ctx sndc;
839 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
841 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
844 halt = vmbus_xact_req_data(xact);
845 halt->rm_type = REMOTE_NDIS_HALT_MSG;
846 halt->rm_len = sizeof(*halt);
847 halt->rm_rid = hn_rndis_rid(sc);
849 /* No RNDIS completion; rely on NVS message send completion */
850 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
851 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
853 vmbus_xact_put(xact);
855 if_printf(sc->hn_ifp, "RNDIS halt done\n");
860 * RNDIS filter on device add
863 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
864 int *nchan0, struct hn_rx_ring *rxr)
867 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
868 device_t dev = sc->hn_dev;
869 struct hn_nvs_subch_req *req;
870 const struct hn_nvs_subch_resp *resp;
872 struct vmbus_xact *xact = NULL;
873 uint32_t status, nsubch;
878 * Let the inner driver handle this first to create the netvsc channel
879 * NOTE! Once the channel is created, we may get a receive callback
880 * (hv_rf_on_receive()) before this call is completed.
881 * Note: Earlier code used a function pointer here.
883 ret = hv_nv_on_device_add(sc, rxr);
888 * Initialize the rndis device
891 /* Send the rndis initialization message */
892 ret = hv_rf_init_device(sc);
895 * TODO: If rndis init failed, we will need to shut down
900 /* Get the mac address */
901 ret = hv_rf_query_device_mac(sc, dev_info->mac_addr);
903 /* TODO: shut down rndis device and the channel */
906 /* Configure NDIS offload settings */
907 hn_rndis_conf_offload(sc);
909 hv_rf_query_device_link_status(sc, &dev_info->link_state);
911 if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
913 * Either RSS is not supported, or multiple RX/TX rings
921 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
924 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
926 /* No RSS; this is benign. */
932 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
936 device_printf(dev, "only 1 channel is supported, no vRSS\n");
941 * Ask NVS to allocate sub-channels.
943 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
945 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
949 req = vmbus_xact_req_data(xact);
950 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
951 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
952 req->nvs_nsubch = nchan - 1;
954 resp_len = sizeof(*resp);
955 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
956 HN_NVS_TYPE_SUBCH_RESP);
958 if_printf(sc->hn_ifp, "exec subch failed\n");
963 status = resp->nvs_status;
964 nsubch = resp->nvs_nsubch;
965 vmbus_xact_put(xact);
968 if (status != HN_NVS_STATUS_OK) {
969 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
973 if (nsubch > nchan - 1) {
974 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
980 ret = hn_rndis_conf_rss(sc, nchan);
987 vmbus_xact_put(xact);
992 * RNDIS filter on device remove
995 hv_rf_on_device_remove(struct hn_softc *sc)
999 /* Halt and release the rndis device */
1000 ret = hv_rf_halt_device(sc);
1002 /* Pass control to inner driver to remove the device */
1003 ret |= hv_nv_on_device_remove(sc);
1009 * RNDIS filter on open
1012 hv_rf_on_open(struct hn_softc *sc)
1017 if (hv_promisc_mode != 1) {
1018 filter = NDIS_PACKET_TYPE_BROADCAST |
1019 NDIS_PACKET_TYPE_ALL_MULTICAST |
1020 NDIS_PACKET_TYPE_DIRECTED;
1022 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1024 return (hn_rndis_set_rxfilter(sc, filter));
1028 * RNDIS filter on close
1031 hv_rf_on_close(struct hn_softc *sc)
1034 return (hn_rndis_set_rxfilter(sc, 0));
1038 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1041 netvsc_channel_rollup(rxr, txr);