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 <sys/types.h>
43 #include <machine/atomic.h>
46 #include <vm/vm_param.h>
49 #include <dev/hyperv/include/hyperv.h>
50 #include <dev/hyperv/include/vmbus_xact.h>
51 #include <dev/hyperv/netvsc/hv_net_vsc.h>
52 #include <dev/hyperv/netvsc/hv_rndis.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_response(rndis_device *device,
76 const rndis_msg *response);
77 static void hv_rf_receive_indicate_status(rndis_device *device,
78 const rndis_msg *response);
79 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
80 const void *data, int dlen);
81 static inline int hv_rf_query_device_mac(rndis_device *device);
82 static inline int hv_rf_query_device_link_status(rndis_device *device);
83 static int hv_rf_init_device(rndis_device *device);
85 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
86 const void *idata, size_t idlen, void *odata, size_t *odlen0);
87 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
89 static int hn_rndis_conf_offload(struct hn_softc *sc);
90 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
91 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
93 static __inline uint32_t
94 hn_rndis_rid(struct hn_softc *sc)
99 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
103 /* Use upper 16 bits for non-compat RNDIS messages. */
104 return ((rid & 0xffff) << 16);
108 * Set the Per-Packet-Info with the specified type
111 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
114 rndis_packet *rndis_pkt;
115 rndis_per_packet_info *rppi;
117 rndis_pkt = &rndis_mesg->msg.packet;
118 rndis_pkt->data_offset += rppi_size;
120 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
121 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
123 rppi->size = rppi_size;
124 rppi->type = pkt_type;
125 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
127 rndis_pkt->per_pkt_info_length += rppi_size;
133 * Get the Per-Packet-Info with the specified type
134 * return NULL if not found.
137 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
139 rndis_per_packet_info *ppi;
142 if (rpkt->per_pkt_info_offset == 0)
145 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
146 rpkt->per_pkt_info_offset);
147 len = rpkt->per_pkt_info_length;
150 if (ppi->type == type)
151 return (void *)((unsigned long)ppi +
152 ppi->per_packet_info_offset);
155 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
163 * Allow module_param to work and override to switch to promiscuous mode.
165 static inline rndis_device *
166 hv_get_rndis_device(void)
168 rndis_device *device;
170 device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
172 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
174 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
175 STAILQ_INIT(&device->myrequest_list);
177 device->state = RNDIS_DEV_UNINITIALIZED;
186 hv_put_rndis_device(rndis_device *device)
188 mtx_destroy(&device->req_lock);
189 free(device, M_NETVSC);
193 * RNDIS filter receive response
196 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
198 rndis_request *request = NULL;
199 rndis_request *next_request;
200 boolean_t found = FALSE;
202 mtx_lock(&device->req_lock);
203 request = STAILQ_FIRST(&device->myrequest_list);
204 while (request != NULL) {
206 * All request/response message contains request_id as the
209 if (request->request_msg.msg.init_request.request_id ==
210 response->msg.init_complete.request_id) {
214 next_request = STAILQ_NEXT(request, mylist_entry);
215 request = next_request;
217 mtx_unlock(&device->req_lock);
220 if (response->msg_len <= sizeof(rndis_msg)) {
221 memcpy(&request->response_msg, response,
224 request->response_msg.msg.init_complete.status =
225 RNDIS_STATUS_BUFFER_OVERFLOW;
227 sema_post(&request->wait_sema);
232 * RNDIS filter receive indicate status
235 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
237 const rndis_indicate_status *indicate = &response->msg.indicate_status;
239 switch(indicate->status) {
240 case RNDIS_STATUS_MEDIA_CONNECT:
241 netvsc_linkstatus_callback(device->sc, 1);
243 case RNDIS_STATUS_MEDIA_DISCONNECT:
244 netvsc_linkstatus_callback(device->sc, 0);
248 device_printf(device->sc->hn_dev,
249 "unknown status %d received\n", indicate->status);
255 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
257 const rndis_per_packet_info *ppi;
260 info->vlan_info = NULL;
261 info->csum_info = NULL;
262 info->hash_info = NULL;
263 info->hash_value = NULL;
265 if (rpkt->per_pkt_info_offset == 0)
268 ppi = (const rndis_per_packet_info *)
269 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
270 len = rpkt->per_pkt_info_length;
274 const void *ppi_dptr;
277 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
279 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
280 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
283 case ieee_8021q_info:
284 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
286 info->vlan_info = ppi_dptr;
287 mask |= HV_RF_RECVINFO_VLAN;
290 case tcpip_chksum_info:
291 if (__predict_false(ppi_dlen <
292 sizeof(rndis_tcp_ip_csum_info)))
294 info->csum_info = ppi_dptr;
295 mask |= HV_RF_RECVINFO_CSUM;
299 if (__predict_false(ppi_dlen <
300 sizeof(struct rndis_hash_value)))
302 info->hash_value = ppi_dptr;
303 mask |= HV_RF_RECVINFO_HASHVAL;
307 if (__predict_false(ppi_dlen <
308 sizeof(struct rndis_hash_info)))
310 info->hash_info = ppi_dptr;
311 mask |= HV_RF_RECVINFO_HASHINF;
318 if (mask == HV_RF_RECVINFO_ALL) {
319 /* All found; done */
323 if (__predict_false(len < ppi->size))
326 ppi = (const rndis_per_packet_info *)
327 ((const uint8_t *)ppi + ppi->size);
333 * RNDIS filter receive data
336 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
338 const rndis_msg *message = data;
339 const rndis_packet *rndis_pkt;
340 uint32_t data_offset;
341 struct hn_recvinfo info;
343 rndis_pkt = &message->msg.packet;
346 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
347 * netvsc packet (ie tot_data_buf_len != message_length)
350 /* Remove rndis header, then pass data packet up the stack */
351 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
354 if (dlen < rndis_pkt->data_length) {
355 if_printf(rxr->hn_ifp,
356 "total length %u is less than data length %u\n",
357 dlen, rndis_pkt->data_length);
361 dlen = rndis_pkt->data_length;
362 data = (const uint8_t *)data + data_offset;
364 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
365 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
368 netvsc_recv(rxr, data, dlen, &info);
372 * RNDIS filter on receive
375 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
376 const void *data, int dlen)
378 rndis_device *rndis_dev;
379 const rndis_msg *rndis_hdr;
380 const struct rndis_comp_hdr *comp;
382 rndis_dev = sc->rndis_dev;
383 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
387 switch (rndis_hdr->ndis_msg_type) {
389 case REMOTE_NDIS_PACKET_MSG:
390 hv_rf_receive_data(rxr, data, dlen);
393 /* completion messages */
394 case REMOTE_NDIS_INITIALIZE_CMPLT:
395 case REMOTE_NDIS_QUERY_CMPLT:
396 case REMOTE_NDIS_SET_CMPLT:
397 case REMOTE_NDIS_KEEPALIVE_CMPLT:
399 if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
400 /* Transition time compat code */
401 hv_rf_receive_response(rndis_dev, rndis_hdr);
403 vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
407 /* notification message */
408 case REMOTE_NDIS_INDICATE_STATUS_MSG:
409 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
412 case REMOTE_NDIS_RESET_CMPLT:
414 * Reset completed, no rid.
417 * RESET is not issued by hn(4), so this message should
420 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
424 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
425 rndis_hdr->ndis_msg_type);
432 * RNDIS filter query device MAC address
435 hv_rf_query_device_mac(rndis_device *device)
437 struct hn_softc *sc = device->sc;
441 hwaddr_len = ETHER_ADDR_LEN;
442 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
443 device->hw_mac_addr, &hwaddr_len);
446 if (hwaddr_len != ETHER_ADDR_LEN) {
447 if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
454 * RNDIS filter query device link status
457 hv_rf_query_device_link_status(rndis_device *device)
459 struct hn_softc *sc = device->sc;
463 size = sizeof(uint32_t);
464 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
465 &device->link_status, &size);
468 if (size != sizeof(uint32_t)) {
469 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
475 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
476 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
477 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
478 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
479 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
480 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
484 hn_rndis_xact_exec1(struct hn_softc *sc, struct vmbus_xact *xact, size_t reqlen,
485 struct hn_send_ctx *sndc, size_t *comp_len)
487 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
491 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
492 ("invalid request length %zu", reqlen));
497 paddr = vmbus_xact_req_paddr(xact);
498 KASSERT((paddr & PAGE_MASK) == 0,
499 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
500 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
508 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
509 gpa[gpa_cnt].gpa_len = len;
510 gpa[gpa_cnt].gpa_ofs = 0;
514 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
517 * Send this RNDIS control message and wait for its completion
520 vmbus_xact_activate(xact);
521 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL, sndc,
524 vmbus_xact_deactivate(xact);
525 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
528 return (vmbus_xact_wait(xact, comp_len));
532 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
533 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
535 const struct rndis_comp_hdr *comp;
536 size_t comp_len, min_complen = *comp_len0;
538 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
539 KASSERT(min_complen >= sizeof(*comp),
540 ("invalid minimum complete len %zu", min_complen));
543 * Execute the xact setup by the caller.
545 comp = hn_rndis_xact_exec1(sc, xact, reqlen, &hn_send_ctx_none,
551 * Check this RNDIS complete message.
553 if (comp_len < min_complen) {
554 if (comp_len >= sizeof(*comp)) {
555 /* rm_status field is valid */
556 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
557 "status 0x%08x\n", comp_len, comp->rm_status);
559 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
564 if (comp->rm_len < min_complen) {
565 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
569 if (comp->rm_type != comp_type) {
570 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
571 "expect 0x%08x\n", comp->rm_type, comp_type);
574 if (comp->rm_rid != rid) {
575 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
576 "expect %u\n", comp->rm_rid, rid);
580 *comp_len0 = comp_len;
585 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
586 const void *idata, size_t idlen, void *odata, size_t *odlen0)
588 struct rndis_query_req *req;
589 const struct rndis_query_comp *comp;
590 struct vmbus_xact *xact;
591 size_t reqlen, odlen = *odlen0, comp_len;
595 reqlen = sizeof(*req) + idlen;
596 xact = vmbus_xact_get(sc->hn_xact, reqlen);
598 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
601 rid = hn_rndis_rid(sc);
602 req = vmbus_xact_req_data(xact);
603 req->rm_type = REMOTE_NDIS_QUERY_MSG;
604 req->rm_len = reqlen;
609 * This is _not_ RNDIS Spec conforming:
610 * "This MUST be set to 0 when there is no input data
611 * associated with the OID."
613 * If this field was set to 0 according to the RNDIS Spec,
614 * Hyper-V would set non-SUCCESS status in the query
617 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
620 req->rm_infobuflen = idlen;
621 /* Input data immediately follows RNDIS query. */
622 memcpy(req + 1, idata, idlen);
625 comp_len = sizeof(*comp) + odlen;
626 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
627 REMOTE_NDIS_QUERY_CMPLT);
629 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
634 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
635 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
636 "status 0x%08x\n", oid, comp->rm_status);
640 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
641 /* No output data! */
642 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
649 * Check output data length and offset.
651 /* ofs is the offset from the beginning of comp. */
652 ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
653 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
654 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
655 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
663 if (comp->rm_infobuflen < odlen)
664 odlen = comp->rm_infobuflen;
665 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
670 vmbus_xact_put(xact);
675 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
677 struct ndis_rss_caps in, caps;
682 * Only NDIS 6.30+ is supported.
684 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
685 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
688 memset(&in, 0, sizeof(in));
689 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
690 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
691 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
693 caps_len = NDIS_RSS_CAPS_SIZE;
694 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
695 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
698 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
699 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
704 if (caps.ndis_nrxr == 0) {
705 if_printf(sc->hn_ifp, "0 RX rings!?\n");
708 *rxr_cnt = caps.ndis_nrxr;
710 if (caps_len == NDIS_RSS_CAPS_SIZE) {
712 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
720 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
722 struct rndis_set_req *req;
723 const struct rndis_set_comp *comp;
724 struct vmbus_xact *xact;
725 size_t reqlen, comp_len;
729 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
731 reqlen = sizeof(*req) + dlen;
732 xact = vmbus_xact_get(sc->hn_xact, reqlen);
734 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
737 rid = hn_rndis_rid(sc);
738 req = vmbus_xact_req_data(xact);
739 req->rm_type = REMOTE_NDIS_SET_MSG;
740 req->rm_len = reqlen;
743 req->rm_infobuflen = dlen;
744 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
745 /* Data immediately follows RNDIS set. */
746 memcpy(req + 1, data, dlen);
748 comp_len = sizeof(*comp);
749 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
750 REMOTE_NDIS_SET_CMPLT);
752 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
757 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
758 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
759 "status 0x%08x\n", oid, comp->rm_status);
765 vmbus_xact_put(xact);
770 hn_rndis_conf_offload(struct hn_softc *sc)
772 struct ndis_offload_params params;
776 /* NOTE: 0 means "no change" */
777 memset(¶ms, 0, sizeof(params));
779 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
780 if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
781 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
782 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
784 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
785 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
787 params.ndis_hdr.ndis_size = paramsz;
789 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
790 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
791 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
792 if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
793 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
794 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
796 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
797 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
799 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
801 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
804 if_printf(sc->hn_ifp, "offload config done\n");
810 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
812 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
813 struct ndis_rss_params *prm = &rss->rss_params;
817 * Only NDIS 6.30+ is supported.
819 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
820 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
822 memset(rss, 0, sizeof(*rss));
823 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
824 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
825 prm->ndis_hdr.ndis_size = sizeof(*rss);
826 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
827 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
828 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
829 /* TODO: Take ndis_rss_caps.ndis_nind into account */
830 prm->ndis_indsize = sizeof(rss->rss_ind);
831 prm->ndis_indoffset =
832 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
833 prm->ndis_keysize = sizeof(rss->rss_key);
834 prm->ndis_keyoffset =
835 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
838 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
840 /* Setup RSS indirect table */
841 /* TODO: Take ndis_rss_caps.ndis_nind into account */
842 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
843 rss->rss_ind[i] = i % nchan;
845 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
848 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
851 if_printf(sc->hn_ifp, "RSS config done\n");
857 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
861 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
862 &filter, sizeof(filter));
864 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
868 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
876 * RNDIS filter init device
879 hv_rf_init_device(rndis_device *device)
881 struct hn_softc *sc = device->sc;
882 struct rndis_init_req *req;
883 const struct rndis_init_comp *comp;
884 struct vmbus_xact *xact;
890 device->state = RNDIS_DEV_INITIALIZED;
892 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
894 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
897 rid = hn_rndis_rid(sc);
898 req = vmbus_xact_req_data(xact);
899 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
900 req->rm_len = sizeof(*req);
902 req->rm_ver_major = RNDIS_VERSION_MAJOR;
903 req->rm_ver_minor = RNDIS_VERSION_MINOR;
904 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
906 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
907 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
908 REMOTE_NDIS_INITIALIZE_CMPLT);
910 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
915 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
916 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
922 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
923 comp->rm_ver_major, comp->rm_ver_minor,
924 comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
930 vmbus_xact_put(xact);
935 * RNDIS filter halt device
938 hv_rf_halt_device(struct hn_softc *sc)
940 struct vmbus_xact *xact;
941 struct rndis_halt_req *halt;
942 struct hn_send_ctx sndc;
945 xact = vmbus_xact_get(sc->hn_xact, sizeof(*halt));
947 if_printf(sc->hn_ifp, "no xact for RNDIS halt\n");
950 halt = vmbus_xact_req_data(xact);
951 halt->rm_type = REMOTE_NDIS_HALT_MSG;
952 halt->rm_len = sizeof(*halt);
953 halt->rm_rid = hn_rndis_rid(sc);
955 /* No RNDIS completion; rely on NVS message send completion */
956 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
957 hn_rndis_xact_exec1(sc, xact, sizeof(*halt), &sndc, &comp_len);
959 vmbus_xact_put(xact);
961 if_printf(sc->hn_ifp, "RNDIS halt done\n");
966 * RNDIS filter on device add
969 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
970 int *nchan0, struct hn_rx_ring *rxr)
973 rndis_device *rndis_dev;
974 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
975 device_t dev = sc->hn_dev;
976 struct hn_nvs_subch_req *req;
977 const struct hn_nvs_subch_resp *resp;
979 struct vmbus_xact *xact = NULL;
980 uint32_t status, nsubch;
984 rndis_dev = hv_get_rndis_device();
985 if (rndis_dev == NULL) {
988 sc->rndis_dev = rndis_dev;
992 * Let the inner driver handle this first to create the netvsc channel
993 * NOTE! Once the channel is created, we may get a receive callback
994 * (hv_rf_on_receive()) before this call is completed.
995 * Note: Earlier code used a function pointer here.
997 ret = hv_nv_on_device_add(sc, rxr);
999 hv_put_rndis_device(rndis_dev);
1004 * Initialize the rndis device
1007 /* Send the rndis initialization message */
1008 ret = hv_rf_init_device(rndis_dev);
1011 * TODO: If rndis init failed, we will need to shut down
1016 /* Get the mac address */
1017 ret = hv_rf_query_device_mac(rndis_dev);
1019 /* TODO: shut down rndis device and the channel */
1022 /* Configure NDIS offload settings */
1023 hn_rndis_conf_offload(sc);
1025 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1027 hv_rf_query_device_link_status(rndis_dev);
1029 dev_info->link_state = rndis_dev->link_status;
1031 if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
1033 * Either RSS is not supported, or multiple RX/TX rings
1034 * are not requested.
1041 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1044 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1046 /* No RSS; this is benign. */
1050 if (nchan > rxr_cnt)
1052 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1056 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1061 * Ask NVS to allocate sub-channels.
1063 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1065 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1069 req = vmbus_xact_req_data(xact);
1070 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1071 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1072 req->nvs_nsubch = nchan - 1;
1074 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len);
1076 if_printf(sc->hn_ifp, "exec subch failed\n");
1080 if (resp_len < sizeof(*resp)) {
1081 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1086 if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1087 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1093 status = resp->nvs_status;
1094 nsubch = resp->nvs_nsubch;
1095 vmbus_xact_put(xact);
1098 if (status != HN_NVS_STATUS_OK) {
1099 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1103 if (nsubch > nchan - 1) {
1104 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1110 ret = hn_rndis_conf_rss(sc, nchan);
1117 vmbus_xact_put(xact);
1122 * RNDIS filter on device remove
1125 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1127 rndis_device *rndis_dev = sc->rndis_dev;
1130 /* Halt and release the rndis device */
1131 ret = hv_rf_halt_device(sc);
1133 sc->rndis_dev = NULL;
1134 hv_put_rndis_device(rndis_dev);
1136 /* Pass control to inner driver to remove the device */
1137 ret |= hv_nv_on_device_remove(sc, destroy_channel);
1143 * RNDIS filter on open
1146 hv_rf_on_open(struct hn_softc *sc)
1151 if (hv_promisc_mode != 1) {
1152 filter = NDIS_PACKET_TYPE_BROADCAST |
1153 NDIS_PACKET_TYPE_ALL_MULTICAST |
1154 NDIS_PACKET_TYPE_DIRECTED;
1156 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1158 return (hn_rndis_set_rxfilter(sc, filter));
1162 * RNDIS filter on close
1165 hv_rf_on_close(struct hn_softc *sc)
1168 return (hn_rndis_set_rxfilter(sc, 0));
1172 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1175 netvsc_channel_rollup(rxr, txr);