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 * Get the Per-Packet-Info with the specified type
132 * return NULL if not found.
135 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
137 rndis_per_packet_info *ppi;
140 if (rpkt->per_pkt_info_offset == 0)
143 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
144 rpkt->per_pkt_info_offset);
145 len = rpkt->per_pkt_info_length;
148 if (ppi->type == type)
149 return (void *)((unsigned long)ppi +
150 ppi->per_packet_info_offset);
153 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
160 * RNDIS filter receive indicate status
163 hv_rf_receive_indicate_status(struct hn_softc *sc, const rndis_msg *response)
165 const rndis_indicate_status *indicate = &response->msg.indicate_status;
167 switch(indicate->status) {
168 case RNDIS_STATUS_MEDIA_CONNECT:
169 netvsc_linkstatus_callback(sc, 1);
171 case RNDIS_STATUS_MEDIA_DISCONNECT:
172 netvsc_linkstatus_callback(sc, 0);
176 if_printf(sc->hn_ifp,
177 "unknown status %d received\n", indicate->status);
183 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
185 const rndis_per_packet_info *ppi;
188 info->vlan_info = NULL;
189 info->csum_info = NULL;
190 info->hash_info = NULL;
191 info->hash_value = NULL;
193 if (rpkt->per_pkt_info_offset == 0)
196 ppi = (const rndis_per_packet_info *)
197 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
198 len = rpkt->per_pkt_info_length;
202 const void *ppi_dptr;
205 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
207 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
208 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
211 case ieee_8021q_info:
212 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
214 info->vlan_info = ppi_dptr;
215 mask |= HV_RF_RECVINFO_VLAN;
218 case tcpip_chksum_info:
219 if (__predict_false(ppi_dlen <
220 sizeof(rndis_tcp_ip_csum_info)))
222 info->csum_info = ppi_dptr;
223 mask |= HV_RF_RECVINFO_CSUM;
227 if (__predict_false(ppi_dlen <
228 sizeof(struct rndis_hash_value)))
230 info->hash_value = ppi_dptr;
231 mask |= HV_RF_RECVINFO_HASHVAL;
235 if (__predict_false(ppi_dlen <
236 sizeof(struct rndis_hash_info)))
238 info->hash_info = ppi_dptr;
239 mask |= HV_RF_RECVINFO_HASHINF;
246 if (mask == HV_RF_RECVINFO_ALL) {
247 /* All found; done */
251 if (__predict_false(len < ppi->size))
254 ppi = (const rndis_per_packet_info *)
255 ((const uint8_t *)ppi + ppi->size);
261 * RNDIS filter receive data
264 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
266 const rndis_msg *message = data;
267 const rndis_packet *rndis_pkt;
268 uint32_t data_offset;
269 struct hn_recvinfo info;
271 rndis_pkt = &message->msg.packet;
274 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
275 * netvsc packet (ie tot_data_buf_len != message_length)
278 /* Remove rndis header, then pass data packet up the stack */
279 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
282 if (dlen < rndis_pkt->data_length) {
283 if_printf(rxr->hn_ifp,
284 "total length %u is less than data length %u\n",
285 dlen, rndis_pkt->data_length);
289 dlen = rndis_pkt->data_length;
290 data = (const uint8_t *)data + data_offset;
292 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
293 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
296 netvsc_recv(rxr, data, dlen, &info);
300 * RNDIS filter on receive
303 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
304 const void *data, int dlen)
306 const rndis_msg *rndis_hdr;
307 const struct rndis_comp_hdr *comp;
310 switch (rndis_hdr->ndis_msg_type) {
312 case REMOTE_NDIS_PACKET_MSG:
313 hv_rf_receive_data(rxr, data, dlen);
316 /* completion messages */
317 case REMOTE_NDIS_INITIALIZE_CMPLT:
318 case REMOTE_NDIS_QUERY_CMPLT:
319 case REMOTE_NDIS_SET_CMPLT:
320 case REMOTE_NDIS_KEEPALIVE_CMPLT:
322 KASSERT(comp->rm_rid > HN_RNDIS_RID_COMPAT_MAX,
323 ("invalid rid 0x%08x\n", comp->rm_rid));
324 vmbus_xact_ctx_wakeup(sc->hn_xact, comp, dlen);
327 /* notification message */
328 case REMOTE_NDIS_INDICATE_STATUS_MSG:
329 hv_rf_receive_indicate_status(sc, rndis_hdr);
332 case REMOTE_NDIS_RESET_CMPLT:
334 * Reset completed, no rid.
337 * RESET is not issued by hn(4), so this message should
340 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
344 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
345 rndis_hdr->ndis_msg_type);
352 * RNDIS filter query device MAC address
355 hv_rf_query_device_mac(struct hn_softc *sc, uint8_t *eaddr)
360 eaddr_len = ETHER_ADDR_LEN;
361 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
365 if (eaddr_len != ETHER_ADDR_LEN) {
366 if_printf(sc->hn_ifp, "invalid eaddr len %zu\n", eaddr_len);
373 * RNDIS filter query device link status
376 hv_rf_query_device_link_status(struct hn_softc *sc, uint32_t *link_status)
381 size = sizeof(*link_status);
382 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
386 if (size != sizeof(uint32_t)) {
387 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
393 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
394 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
395 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
396 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
397 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
398 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
402 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
403 struct hn_send_ctx *sndc, size_t *comp_len)
405 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
409 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
410 ("invalid request length %zu", reqlen));
415 paddr = vmbus_xact_req_paddr(xact);
416 KASSERT((paddr & PAGE_MASK) == 0,
417 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
418 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
426 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
427 gpa[gpa_cnt].gpa_len = len;
428 gpa[gpa_cnt].gpa_ofs = 0;
432 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
435 * Send this RNDIS control message and wait for its completion
438 vmbus_xact_activate(xact);
439 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
442 vmbus_xact_deactivate(xact);
443 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
446 return (vmbus_xact_wait(xact, comp_len));
450 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
451 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
453 const struct rndis_comp_hdr *comp;
454 size_t comp_len, min_complen = *comp_len0;
456 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
457 KASSERT(min_complen >= sizeof(*comp),
458 ("invalid minimum complete len %zu", min_complen));
461 * Execute the xact setup by the caller.
463 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
469 * Check this RNDIS complete message.
471 if (comp_len < min_complen) {
472 if (comp_len >= sizeof(*comp)) {
473 /* rm_status field is valid */
474 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
475 "status 0x%08x\n", comp_len, comp->rm_status);
477 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
482 if (comp->rm_len < min_complen) {
483 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
487 if (comp->rm_type != comp_type) {
488 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
489 "expect 0x%08x\n", comp->rm_type, comp_type);
492 if (comp->rm_rid != rid) {
493 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
494 "expect %u\n", comp->rm_rid, rid);
498 *comp_len0 = comp_len;
503 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
504 const void *idata, size_t idlen, void *odata, size_t *odlen0)
506 struct rndis_query_req *req;
507 const struct rndis_query_comp *comp;
508 struct vmbus_xact *xact;
509 size_t reqlen, odlen = *odlen0, comp_len;
513 reqlen = sizeof(*req) + idlen;
514 xact = vmbus_xact_get(sc->hn_xact, reqlen);
516 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
519 rid = hn_rndis_rid(sc);
520 req = vmbus_xact_req_data(xact);
521 req->rm_type = REMOTE_NDIS_QUERY_MSG;
522 req->rm_len = reqlen;
527 * This is _not_ RNDIS Spec conforming:
528 * "This MUST be set to 0 when there is no input data
529 * associated with the OID."
531 * If this field was set to 0 according to the RNDIS Spec,
532 * Hyper-V would set non-SUCCESS status in the query
535 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
538 req->rm_infobuflen = idlen;
539 /* Input data immediately follows RNDIS query. */
540 memcpy(req + 1, idata, idlen);
543 comp_len = sizeof(*comp) + odlen;
544 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
545 REMOTE_NDIS_QUERY_CMPLT);
547 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
552 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
553 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
554 "status 0x%08x\n", oid, comp->rm_status);
558 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
559 /* No output data! */
560 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
567 * Check output data length and offset.
569 /* ofs is the offset from the beginning of comp. */
570 ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
571 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
572 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
573 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
581 if (comp->rm_infobuflen < odlen)
582 odlen = comp->rm_infobuflen;
583 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
588 vmbus_xact_put(xact);
593 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
595 struct ndis_rss_caps in, caps;
600 * Only NDIS 6.30+ is supported.
602 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
603 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
606 memset(&in, 0, sizeof(in));
607 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
608 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
609 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
611 caps_len = NDIS_RSS_CAPS_SIZE;
612 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
613 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
616 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
617 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
622 if (caps.ndis_nrxr == 0) {
623 if_printf(sc->hn_ifp, "0 RX rings!?\n");
626 *rxr_cnt = caps.ndis_nrxr;
628 if (caps_len == NDIS_RSS_CAPS_SIZE) {
630 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
638 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
640 struct rndis_set_req *req;
641 const struct rndis_set_comp *comp;
642 struct vmbus_xact *xact;
643 size_t reqlen, comp_len;
647 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
649 reqlen = sizeof(*req) + dlen;
650 xact = vmbus_xact_get(sc->hn_xact, reqlen);
652 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
655 rid = hn_rndis_rid(sc);
656 req = vmbus_xact_req_data(xact);
657 req->rm_type = REMOTE_NDIS_SET_MSG;
658 req->rm_len = reqlen;
661 req->rm_infobuflen = dlen;
662 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
663 /* Data immediately follows RNDIS set. */
664 memcpy(req + 1, data, dlen);
666 comp_len = sizeof(*comp);
667 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
668 REMOTE_NDIS_SET_CMPLT);
670 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
675 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
676 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
677 "status 0x%08x\n", oid, comp->rm_status);
683 vmbus_xact_put(xact);
688 hn_rndis_conf_offload(struct hn_softc *sc)
690 struct ndis_offload_params params;
694 /* NOTE: 0 means "no change" */
695 memset(¶ms, 0, sizeof(params));
697 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
698 if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
699 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
700 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
702 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
703 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
705 params.ndis_hdr.ndis_size = paramsz;
707 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
708 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
709 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
710 if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
711 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
712 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
714 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
715 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
717 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
719 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
722 if_printf(sc->hn_ifp, "offload config done\n");
728 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
730 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
731 struct ndis_rss_params *prm = &rss->rss_params;
735 * Only NDIS 6.30+ is supported.
737 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
738 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
740 memset(rss, 0, sizeof(*rss));
741 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
742 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
743 prm->ndis_hdr.ndis_size = sizeof(*rss);
744 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
745 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
746 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
747 /* TODO: Take ndis_rss_caps.ndis_nind into account */
748 prm->ndis_indsize = sizeof(rss->rss_ind);
749 prm->ndis_indoffset =
750 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
751 prm->ndis_keysize = sizeof(rss->rss_key);
752 prm->ndis_keyoffset =
753 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
756 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
758 /* Setup RSS indirect table */
759 /* TODO: Take ndis_rss_caps.ndis_nind into account */
760 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
761 rss->rss_ind[i] = i % nchan;
763 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
766 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
769 if_printf(sc->hn_ifp, "RSS config done\n");
775 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
779 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
780 &filter, sizeof(filter));
782 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
786 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
794 * RNDIS filter init device
797 hv_rf_init_device(struct hn_softc *sc)
799 struct rndis_init_req *req;
800 const struct rndis_init_comp *comp;
801 struct vmbus_xact *xact;
806 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
808 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
811 rid = hn_rndis_rid(sc);
812 req = vmbus_xact_req_data(xact);
813 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
814 req->rm_len = sizeof(*req);
816 req->rm_ver_major = RNDIS_VERSION_MAJOR;
817 req->rm_ver_minor = RNDIS_VERSION_MINOR;
818 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
820 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
821 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
822 REMOTE_NDIS_INITIALIZE_CMPLT);
824 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
829 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
830 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
836 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u, "
837 "align %u\n", comp->rm_ver_major, comp->rm_ver_minor,
838 comp->rm_pktmaxsz, comp->rm_pktmaxcnt,
839 1U << comp->rm_align);
843 vmbus_xact_put(xact);
848 * RNDIS filter halt device
851 hv_rf_halt_device(struct hn_softc *sc)
853 struct vmbus_xact *xact;
854 struct rndis_halt_req *halt;
855 struct hn_send_ctx sndc;
858 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
860 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
863 halt = vmbus_xact_req_data(xact);
864 halt->rm_type = REMOTE_NDIS_HALT_MSG;
865 halt->rm_len = sizeof(*halt);
866 halt->rm_rid = hn_rndis_rid(sc);
868 /* No RNDIS completion; rely on NVS message send completion */
869 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
870 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
872 vmbus_xact_put(xact);
874 if_printf(sc->hn_ifp, "RNDIS halt done\n");
879 * RNDIS filter on device add
882 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
883 int *nchan0, struct hn_rx_ring *rxr)
886 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
887 device_t dev = sc->hn_dev;
888 struct hn_nvs_subch_req *req;
889 const struct hn_nvs_subch_resp *resp;
891 struct vmbus_xact *xact = NULL;
892 uint32_t status, nsubch;
897 * Let the inner driver handle this first to create the netvsc channel
898 * NOTE! Once the channel is created, we may get a receive callback
899 * (hv_rf_on_receive()) before this call is completed.
900 * Note: Earlier code used a function pointer here.
902 ret = hv_nv_on_device_add(sc, rxr);
907 * Initialize the rndis device
910 /* Send the rndis initialization message */
911 ret = hv_rf_init_device(sc);
914 * TODO: If rndis init failed, we will need to shut down
919 /* Get the mac address */
920 ret = hv_rf_query_device_mac(sc, dev_info->mac_addr);
922 /* TODO: shut down rndis device and the channel */
925 /* Configure NDIS offload settings */
926 hn_rndis_conf_offload(sc);
928 hv_rf_query_device_link_status(sc, &dev_info->link_state);
930 if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
932 * Either RSS is not supported, or multiple RX/TX rings
940 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
943 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
945 /* No RSS; this is benign. */
951 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
955 device_printf(dev, "only 1 channel is supported, no vRSS\n");
960 * Ask NVS to allocate sub-channels.
962 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
964 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
968 req = vmbus_xact_req_data(xact);
969 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
970 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
971 req->nvs_nsubch = nchan - 1;
973 resp_len = sizeof(*resp);
974 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len,
975 HN_NVS_TYPE_SUBCH_RESP);
977 if_printf(sc->hn_ifp, "exec subch failed\n");
982 status = resp->nvs_status;
983 nsubch = resp->nvs_nsubch;
984 vmbus_xact_put(xact);
987 if (status != HN_NVS_STATUS_OK) {
988 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
992 if (nsubch > nchan - 1) {
993 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
999 ret = hn_rndis_conf_rss(sc, nchan);
1006 vmbus_xact_put(xact);
1011 * RNDIS filter on device remove
1014 hv_rf_on_device_remove(struct hn_softc *sc)
1018 /* Halt and release the rndis device */
1019 ret = hv_rf_halt_device(sc);
1021 /* Pass control to inner driver to remove the device */
1022 ret |= hv_nv_on_device_remove(sc);
1028 * RNDIS filter on open
1031 hv_rf_on_open(struct hn_softc *sc)
1036 if (hv_promisc_mode != 1) {
1037 filter = NDIS_PACKET_TYPE_BROADCAST |
1038 NDIS_PACKET_TYPE_ALL_MULTICAST |
1039 NDIS_PACKET_TYPE_DIRECTED;
1041 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1043 return (hn_rndis_set_rxfilter(sc, filter));
1047 * RNDIS filter on close
1050 hv_rf_on_close(struct hn_softc *sc)
1053 return (hn_rndis_set_rxfilter(sc, 0));
1057 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1060 netvsc_channel_rollup(rxr, txr);