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 int hv_rf_send_request(rndis_device *device, rndis_request *request,
76 uint32_t message_type);
77 static void hv_rf_receive_response(rndis_device *device,
78 const rndis_msg *response);
79 static void hv_rf_receive_indicate_status(rndis_device *device,
80 const rndis_msg *response);
81 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
82 const void *data, int dlen);
83 static inline int hv_rf_query_device_mac(rndis_device *device);
84 static inline int hv_rf_query_device_link_status(rndis_device *device);
85 static int hv_rf_init_device(rndis_device *device);
87 static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
88 struct hn_softc *sc, struct vmbus_channel *chan,
89 const void *data, int dlen);
90 static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
91 struct hn_softc *sc, struct vmbus_channel *chan,
92 const void *data, int dlen);
93 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
94 const void *idata, size_t idlen, void *odata, size_t *odlen0);
95 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
97 static int hn_rndis_conf_offload(struct hn_softc *sc);
98 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
99 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
101 static __inline uint32_t
102 hn_rndis_rid(struct hn_softc *sc)
107 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
111 /* Use upper 16 bits for non-compat RNDIS messages. */
112 return ((rid & 0xffff) << 16);
116 * Set the Per-Packet-Info with the specified type
119 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
122 rndis_packet *rndis_pkt;
123 rndis_per_packet_info *rppi;
125 rndis_pkt = &rndis_mesg->msg.packet;
126 rndis_pkt->data_offset += rppi_size;
128 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
129 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
131 rppi->size = rppi_size;
132 rppi->type = pkt_type;
133 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
135 rndis_pkt->per_pkt_info_length += rppi_size;
141 * Get the Per-Packet-Info with the specified type
142 * return NULL if not found.
145 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
147 rndis_per_packet_info *ppi;
150 if (rpkt->per_pkt_info_offset == 0)
153 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
154 rpkt->per_pkt_info_offset);
155 len = rpkt->per_pkt_info_length;
158 if (ppi->type == type)
159 return (void *)((unsigned long)ppi +
160 ppi->per_packet_info_offset);
163 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
171 * Allow module_param to work and override to switch to promiscuous mode.
173 static inline rndis_device *
174 hv_get_rndis_device(void)
176 rndis_device *device;
178 device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
180 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
182 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
183 STAILQ_INIT(&device->myrequest_list);
185 device->state = RNDIS_DEV_UNINITIALIZED;
194 hv_put_rndis_device(rndis_device *device)
196 mtx_destroy(&device->req_lock);
197 free(device, M_NETVSC);
203 static inline rndis_request *
204 hv_rndis_request(rndis_device *device, uint32_t message_type,
205 uint32_t message_length)
207 rndis_request *request;
208 rndis_msg *rndis_mesg;
209 rndis_set_request *set;
211 request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
213 sema_init(&request->wait_sema, 0, "rndis sema");
215 rndis_mesg = &request->request_msg;
216 rndis_mesg->ndis_msg_type = message_type;
217 rndis_mesg->msg_len = message_length;
220 * Set the request id. This field is always after the rndis header
221 * for request/response packet types so we just use the set_request
224 set = &rndis_mesg->msg.set_request;
225 set->request_id = atomic_fetchadd_int(&device->new_request_id, 1) &
226 HN_RNDIS_RID_COMPAT_MASK;
228 /* Add to the request list */
229 mtx_lock(&device->req_lock);
230 STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
231 mtx_unlock(&device->req_lock);
240 hv_put_rndis_request(rndis_device *device, rndis_request *request)
242 mtx_lock(&device->req_lock);
243 /* Fixme: Has O(n) performance */
245 * XXXKYS: Use Doubly linked lists.
247 STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
249 mtx_unlock(&device->req_lock);
251 sema_destroy(&request->wait_sema);
252 free(request, M_NETVSC);
259 hv_rf_send_request(rndis_device *device, rndis_request *request,
260 uint32_t message_type)
262 struct hn_softc *sc = device->sc;
263 uint32_t send_buf_section_idx, tot_data_buf_len;
264 struct vmbus_gpa gpa[2];
265 int gpa_cnt, send_buf_section_size;
266 hn_sent_callback_t cb;
268 /* Set up the packet to send it */
269 tot_data_buf_len = request->request_msg.msg_len;
272 gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
273 gpa[0].gpa_len = request->request_msg.msg_len;
274 gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
276 if (gpa[0].gpa_ofs + gpa[0].gpa_len > PAGE_SIZE) {
278 gpa[0].gpa_len = PAGE_SIZE - gpa[0].gpa_ofs;
280 hv_get_phys_addr((char*)&request->request_msg +
281 gpa[0].gpa_len) >> PAGE_SHIFT;
283 gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
286 if (message_type != REMOTE_NDIS_HALT_MSG)
287 cb = hn_rndis_sent_cb;
289 cb = hn_rndis_sent_halt;
291 if (tot_data_buf_len < sc->hn_chim_szmax) {
292 send_buf_section_idx = hn_chim_alloc(sc);
293 if (send_buf_section_idx != HN_NVS_CHIM_IDX_INVALID) {
294 uint8_t *dest = sc->hn_chim +
295 (send_buf_section_idx * sc->hn_chim_szmax);
297 memcpy(dest, &request->request_msg, request->request_msg.msg_len);
298 send_buf_section_size = tot_data_buf_len;
302 /* Failed to allocate chimney send buffer; move on */
304 send_buf_section_idx = HN_NVS_CHIM_IDX_INVALID;
305 send_buf_section_size = 0;
308 hn_send_ctx_init(&request->send_ctx, cb, request,
309 send_buf_section_idx, send_buf_section_size);
310 return hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
311 &request->send_ctx, gpa, gpa_cnt);
315 * RNDIS filter receive response
318 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
320 rndis_request *request = NULL;
321 rndis_request *next_request;
322 boolean_t found = FALSE;
324 mtx_lock(&device->req_lock);
325 request = STAILQ_FIRST(&device->myrequest_list);
326 while (request != NULL) {
328 * All request/response message contains request_id as the
331 if (request->request_msg.msg.init_request.request_id ==
332 response->msg.init_complete.request_id) {
336 next_request = STAILQ_NEXT(request, mylist_entry);
337 request = next_request;
339 mtx_unlock(&device->req_lock);
342 if (response->msg_len <= sizeof(rndis_msg)) {
343 memcpy(&request->response_msg, response,
346 request->response_msg.msg.init_complete.status =
347 RNDIS_STATUS_BUFFER_OVERFLOW;
349 sema_post(&request->wait_sema);
354 * RNDIS filter receive indicate status
357 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
359 const rndis_indicate_status *indicate = &response->msg.indicate_status;
361 switch(indicate->status) {
362 case RNDIS_STATUS_MEDIA_CONNECT:
363 netvsc_linkstatus_callback(device->sc, 1);
365 case RNDIS_STATUS_MEDIA_DISCONNECT:
366 netvsc_linkstatus_callback(device->sc, 0);
370 device_printf(device->sc->hn_dev,
371 "unknown status %d received\n", indicate->status);
377 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
379 const rndis_per_packet_info *ppi;
382 info->vlan_info = NULL;
383 info->csum_info = NULL;
384 info->hash_info = NULL;
385 info->hash_value = NULL;
387 if (rpkt->per_pkt_info_offset == 0)
390 ppi = (const rndis_per_packet_info *)
391 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
392 len = rpkt->per_pkt_info_length;
396 const void *ppi_dptr;
399 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
401 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
402 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
405 case ieee_8021q_info:
406 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
408 info->vlan_info = ppi_dptr;
409 mask |= HV_RF_RECVINFO_VLAN;
412 case tcpip_chksum_info:
413 if (__predict_false(ppi_dlen <
414 sizeof(rndis_tcp_ip_csum_info)))
416 info->csum_info = ppi_dptr;
417 mask |= HV_RF_RECVINFO_CSUM;
421 if (__predict_false(ppi_dlen <
422 sizeof(struct rndis_hash_value)))
424 info->hash_value = ppi_dptr;
425 mask |= HV_RF_RECVINFO_HASHVAL;
429 if (__predict_false(ppi_dlen <
430 sizeof(struct rndis_hash_info)))
432 info->hash_info = ppi_dptr;
433 mask |= HV_RF_RECVINFO_HASHINF;
440 if (mask == HV_RF_RECVINFO_ALL) {
441 /* All found; done */
445 if (__predict_false(len < ppi->size))
448 ppi = (const rndis_per_packet_info *)
449 ((const uint8_t *)ppi + ppi->size);
455 * RNDIS filter receive data
458 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
460 const rndis_msg *message = data;
461 const rndis_packet *rndis_pkt;
462 uint32_t data_offset;
463 struct hn_recvinfo info;
465 rndis_pkt = &message->msg.packet;
468 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
469 * netvsc packet (ie tot_data_buf_len != message_length)
472 /* Remove rndis header, then pass data packet up the stack */
473 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
476 if (dlen < rndis_pkt->data_length) {
477 if_printf(rxr->hn_ifp,
478 "total length %u is less than data length %u\n",
479 dlen, rndis_pkt->data_length);
483 dlen = rndis_pkt->data_length;
484 data = (const uint8_t *)data + data_offset;
486 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
487 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
490 netvsc_recv(rxr, data, dlen, &info);
494 * RNDIS filter on receive
497 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
498 const void *data, int dlen)
500 rndis_device *rndis_dev;
501 const rndis_msg *rndis_hdr;
502 const struct rndis_comp_hdr *comp;
504 rndis_dev = sc->rndis_dev;
505 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
509 switch (rndis_hdr->ndis_msg_type) {
511 case REMOTE_NDIS_PACKET_MSG:
512 hv_rf_receive_data(rxr, data, dlen);
515 /* completion messages */
516 case REMOTE_NDIS_INITIALIZE_CMPLT:
517 case REMOTE_NDIS_QUERY_CMPLT:
518 case REMOTE_NDIS_SET_CMPLT:
519 case REMOTE_NDIS_KEEPALIVE_CMPLT:
521 if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
522 /* Transition time compat code */
523 hv_rf_receive_response(rndis_dev, rndis_hdr);
525 vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
529 /* notification message */
530 case REMOTE_NDIS_INDICATE_STATUS_MSG:
531 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
534 case REMOTE_NDIS_RESET_CMPLT:
536 * Reset completed, no rid.
539 * RESET is not issued by hn(4), so this message should
542 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
546 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
547 rndis_hdr->ndis_msg_type);
554 * RNDIS filter query device MAC address
557 hv_rf_query_device_mac(rndis_device *device)
559 struct hn_softc *sc = device->sc;
563 hwaddr_len = ETHER_ADDR_LEN;
564 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
565 device->hw_mac_addr, &hwaddr_len);
568 if (hwaddr_len != ETHER_ADDR_LEN) {
569 if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
576 * RNDIS filter query device link status
579 hv_rf_query_device_link_status(rndis_device *device)
581 struct hn_softc *sc = device->sc;
585 size = sizeof(uint32_t);
586 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
587 &device->link_status, &size);
590 if (size != sizeof(uint32_t)) {
591 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
597 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
598 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
599 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
600 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
601 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
602 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
606 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
607 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
609 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
610 const struct rndis_comp_hdr *comp;
612 size_t comp_len, min_complen = *comp_len0;
615 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
616 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
617 ("invalid request length %zu", reqlen));
618 KASSERT(min_complen >= sizeof(*comp),
619 ("invalid minimum complete len %zu", min_complen));
624 paddr = vmbus_xact_req_paddr(xact);
625 KASSERT((paddr & PAGE_MASK) == 0,
626 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
627 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
635 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
636 gpa[gpa_cnt].gpa_len = len;
637 gpa[gpa_cnt].gpa_ofs = 0;
641 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
644 * Send this RNDIS control message and wait for its completion
647 vmbus_xact_activate(xact);
648 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
649 &hn_send_ctx_none, gpa, gpa_cnt);
651 vmbus_xact_deactivate(xact);
652 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
655 comp = vmbus_xact_wait(xact, &comp_len);
658 * Check this RNDIS complete message.
660 if (comp_len < min_complen) {
661 if (comp_len >= sizeof(*comp)) {
662 /* rm_status field is valid */
663 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
664 "status 0x%08x\n", comp_len, comp->rm_status);
666 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
671 if (comp->rm_len < min_complen) {
672 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
676 if (comp->rm_type != comp_type) {
677 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
678 "expect 0x%08x\n", comp->rm_type, comp_type);
681 if (comp->rm_rid != rid) {
682 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
683 "expect %u\n", comp->rm_rid, rid);
687 *comp_len0 = comp_len;
692 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
693 const void *idata, size_t idlen, void *odata, size_t *odlen0)
695 struct rndis_query_req *req;
696 const struct rndis_query_comp *comp;
697 struct vmbus_xact *xact;
698 size_t reqlen, odlen = *odlen0, comp_len;
702 reqlen = sizeof(*req) + idlen;
703 xact = vmbus_xact_get(sc->hn_xact, reqlen);
705 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
708 rid = hn_rndis_rid(sc);
709 req = vmbus_xact_req_data(xact);
710 req->rm_type = REMOTE_NDIS_QUERY_MSG;
711 req->rm_len = reqlen;
716 * This is _not_ RNDIS Spec conforming:
717 * "This MUST be set to 0 when there is no input data
718 * associated with the OID."
720 * If this field was set to 0 according to the RNDIS Spec,
721 * Hyper-V would set non-SUCCESS status in the query
724 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
727 req->rm_infobuflen = idlen;
728 /* Input data immediately follows RNDIS query. */
729 memcpy(req + 1, idata, idlen);
732 comp_len = sizeof(*comp) + odlen;
733 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
734 REMOTE_NDIS_QUERY_CMPLT);
736 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
741 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
742 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
743 "status 0x%08x\n", oid, comp->rm_status);
747 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
748 /* No output data! */
749 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
756 * Check output data length and offset.
758 /* ofs is the offset from the beginning of comp. */
759 ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
760 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
761 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
762 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
770 if (comp->rm_infobuflen < odlen)
771 odlen = comp->rm_infobuflen;
772 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
777 vmbus_xact_put(xact);
782 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
784 struct ndis_rss_caps in, caps;
789 * Only NDIS 6.30+ is supported.
791 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
792 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
795 memset(&in, 0, sizeof(in));
796 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
797 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
798 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
800 caps_len = NDIS_RSS_CAPS_SIZE;
801 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
802 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
805 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
806 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
811 if (caps.ndis_nrxr == 0) {
812 if_printf(sc->hn_ifp, "0 RX rings!?\n");
815 *rxr_cnt = caps.ndis_nrxr;
817 if (caps_len == NDIS_RSS_CAPS_SIZE) {
819 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
827 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
829 struct rndis_set_req *req;
830 const struct rndis_set_comp *comp;
831 struct vmbus_xact *xact;
832 size_t reqlen, comp_len;
836 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
838 reqlen = sizeof(*req) + dlen;
839 xact = vmbus_xact_get(sc->hn_xact, reqlen);
841 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
844 rid = hn_rndis_rid(sc);
845 req = vmbus_xact_req_data(xact);
846 req->rm_type = REMOTE_NDIS_SET_MSG;
847 req->rm_len = reqlen;
850 req->rm_infobuflen = dlen;
851 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
852 /* Data immediately follows RNDIS set. */
853 memcpy(req + 1, data, dlen);
855 comp_len = sizeof(*comp);
856 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
857 REMOTE_NDIS_SET_CMPLT);
859 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
864 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
865 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
866 "status 0x%08x\n", oid, comp->rm_status);
872 vmbus_xact_put(xact);
877 hn_rndis_conf_offload(struct hn_softc *sc)
879 struct ndis_offload_params params;
883 /* NOTE: 0 means "no change" */
884 memset(¶ms, 0, sizeof(params));
886 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
887 if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
888 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
889 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
891 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
892 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
894 params.ndis_hdr.ndis_size = paramsz;
896 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
897 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
898 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
899 if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
900 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
901 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
903 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
904 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
906 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
908 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
911 if_printf(sc->hn_ifp, "offload config done\n");
917 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
919 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
920 struct ndis_rss_params *prm = &rss->rss_params;
924 * Only NDIS 6.30+ is supported.
926 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
927 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
929 memset(rss, 0, sizeof(*rss));
930 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
931 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
932 prm->ndis_hdr.ndis_size = sizeof(*rss);
933 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
934 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
935 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
936 /* TODO: Take ndis_rss_caps.ndis_nind into account */
937 prm->ndis_indsize = sizeof(rss->rss_ind);
938 prm->ndis_indoffset =
939 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
940 prm->ndis_keysize = sizeof(rss->rss_key);
941 prm->ndis_keyoffset =
942 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
945 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
947 /* Setup RSS indirect table */
948 /* TODO: Take ndis_rss_caps.ndis_nind into account */
949 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
950 rss->rss_ind[i] = i % nchan;
952 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
955 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
958 if_printf(sc->hn_ifp, "RSS config done\n");
964 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
968 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
969 &filter, sizeof(filter));
971 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
975 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
983 * RNDIS filter init device
986 hv_rf_init_device(rndis_device *device)
988 struct hn_softc *sc = device->sc;
989 struct rndis_init_req *req;
990 const struct rndis_init_comp *comp;
991 struct vmbus_xact *xact;
997 device->state = RNDIS_DEV_INITIALIZED;
999 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1001 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
1004 rid = hn_rndis_rid(sc);
1005 req = vmbus_xact_req_data(xact);
1006 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1007 req->rm_len = sizeof(*req);
1009 req->rm_ver_major = RNDIS_VERSION_MAJOR;
1010 req->rm_ver_minor = RNDIS_VERSION_MINOR;
1011 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
1013 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
1014 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
1015 REMOTE_NDIS_INITIALIZE_CMPLT);
1017 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
1022 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
1023 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
1029 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
1030 comp->rm_ver_major, comp->rm_ver_minor,
1031 comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
1037 vmbus_xact_put(xact);
1041 #define HALT_COMPLETION_WAIT_COUNT 25
1044 * RNDIS filter halt device
1047 hv_rf_halt_device(rndis_device *device)
1049 rndis_request *request;
1052 /* Attempt to do a rndis device halt */
1053 request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
1054 RNDIS_MESSAGE_SIZE(rndis_halt_request));
1055 if (request == NULL) {
1059 /* initialize "poor man's semaphore" */
1060 request->halt_complete_flag = 0;
1062 ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
1068 * Wait for halt response from halt callback. We must wait for
1069 * the transaction response before freeing the request and other
1072 for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
1073 if (request->halt_complete_flag != 0) {
1082 device->state = RNDIS_DEV_UNINITIALIZED;
1084 hv_put_rndis_request(device, request);
1090 * RNDIS filter on device add
1093 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1094 int *nchan0, struct hn_rx_ring *rxr)
1097 rndis_device *rndis_dev;
1098 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1099 device_t dev = sc->hn_dev;
1100 struct hn_nvs_subch_req *req;
1101 const struct hn_nvs_subch_resp *resp;
1103 struct vmbus_xact *xact = NULL;
1104 uint32_t status, nsubch;
1105 int nchan = *nchan0;
1108 rndis_dev = hv_get_rndis_device();
1109 if (rndis_dev == NULL) {
1112 sc->rndis_dev = rndis_dev;
1116 * Let the inner driver handle this first to create the netvsc channel
1117 * NOTE! Once the channel is created, we may get a receive callback
1118 * (hv_rf_on_receive()) before this call is completed.
1119 * Note: Earlier code used a function pointer here.
1121 ret = hv_nv_on_device_add(sc, rxr);
1123 hv_put_rndis_device(rndis_dev);
1128 * Initialize the rndis device
1131 /* Send the rndis initialization message */
1132 ret = hv_rf_init_device(rndis_dev);
1135 * TODO: If rndis init failed, we will need to shut down
1140 /* Get the mac address */
1141 ret = hv_rf_query_device_mac(rndis_dev);
1143 /* TODO: shut down rndis device and the channel */
1146 /* Configure NDIS offload settings */
1147 hn_rndis_conf_offload(sc);
1149 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1151 hv_rf_query_device_link_status(rndis_dev);
1153 dev_info->link_state = rndis_dev->link_status;
1155 if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
1157 * Either RSS is not supported, or multiple RX/TX rings
1158 * are not requested.
1165 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1168 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1170 /* No RSS; this is benign. */
1174 if (nchan > rxr_cnt)
1176 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1180 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1185 * Ask NVS to allocate sub-channels.
1187 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1189 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1193 req = vmbus_xact_req_data(xact);
1194 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1195 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1196 req->nvs_nsubch = nchan - 1;
1198 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len);
1200 if_printf(sc->hn_ifp, "exec subch failed\n");
1204 if (resp_len < sizeof(*resp)) {
1205 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1210 if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1211 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1217 status = resp->nvs_status;
1218 nsubch = resp->nvs_nsubch;
1219 vmbus_xact_put(xact);
1222 if (status != HN_NVS_STATUS_OK) {
1223 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1227 if (nsubch > nchan - 1) {
1228 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1234 ret = hn_rndis_conf_rss(sc, nchan);
1241 vmbus_xact_put(xact);
1246 * RNDIS filter on device remove
1249 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1251 rndis_device *rndis_dev = sc->rndis_dev;
1254 /* Halt and release the rndis device */
1255 ret = hv_rf_halt_device(rndis_dev);
1257 sc->rndis_dev = NULL;
1258 hv_put_rndis_device(rndis_dev);
1260 /* Pass control to inner driver to remove the device */
1261 ret |= hv_nv_on_device_remove(sc, destroy_channel);
1267 * RNDIS filter on open
1270 hv_rf_on_open(struct hn_softc *sc)
1275 if (hv_promisc_mode != 1) {
1276 filter = NDIS_PACKET_TYPE_BROADCAST |
1277 NDIS_PACKET_TYPE_ALL_MULTICAST |
1278 NDIS_PACKET_TYPE_DIRECTED;
1280 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1282 return (hn_rndis_set_rxfilter(sc, filter));
1286 * RNDIS filter on close
1289 hv_rf_on_close(struct hn_softc *sc)
1292 return (hn_rndis_set_rxfilter(sc, 0));
1296 hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct hn_softc *sc,
1297 struct vmbus_channel *chan __unused, const void *data __unused,
1300 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1301 hn_chim_free(sc, sndc->hn_chim_idx);
1305 hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct hn_softc *sc,
1306 struct vmbus_channel *chan __unused, const void *data __unused,
1309 rndis_request *request = sndc->hn_cbarg;
1311 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1312 hn_chim_free(sc, sndc->hn_chim_idx);
1315 * Notify hv_rf_halt_device() about halt completion.
1316 * The halt code must wait for completion before freeing
1317 * the transaction resources.
1319 request->halt_complete_flag = 1;
1323 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1326 netvsc_channel_rollup(rxr, txr);