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 int hv_rf_send_request(rndis_device *device, rndis_request *request,
75 uint32_t message_type);
76 static void hv_rf_receive_response(rndis_device *device,
77 const rndis_msg *response);
78 static void hv_rf_receive_indicate_status(rndis_device *device,
79 const rndis_msg *response);
80 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
81 const void *data, int dlen);
82 static inline int hv_rf_query_device_mac(rndis_device *device);
83 static inline int hv_rf_query_device_link_status(rndis_device *device);
84 static int hv_rf_init_device(rndis_device *device);
86 hv_rf_send_offload_request(struct hn_softc *sc,
87 rndis_offload_params *offloads);
89 static void hn_rndis_sent_halt(struct hn_send_ctx *sndc,
90 struct hn_softc *sc, struct vmbus_channel *chan,
91 const void *data, int dlen);
92 static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
93 struct hn_softc *sc, struct vmbus_channel *chan,
94 const void *data, int dlen);
95 static int hn_rndis_query(struct hn_softc *sc, uint32_t oid,
96 const void *idata, size_t idlen, void *odata, size_t *odlen0);
97 static int hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data,
99 static int hn_rndis_conf_offload(struct hn_softc *sc);
100 static int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt);
101 static int hn_rndis_conf_rss(struct hn_softc *sc, int nchan);
103 static __inline uint32_t
104 hn_rndis_rid(struct hn_softc *sc)
109 rid = atomic_fetchadd_int(&sc->hn_rndis_rid, 1);
113 /* Use upper 16 bits for non-compat RNDIS messages. */
114 return ((rid & 0xffff) << 16);
118 * Set the Per-Packet-Info with the specified type
121 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
124 rndis_packet *rndis_pkt;
125 rndis_per_packet_info *rppi;
127 rndis_pkt = &rndis_mesg->msg.packet;
128 rndis_pkt->data_offset += rppi_size;
130 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
131 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
133 rppi->size = rppi_size;
134 rppi->type = pkt_type;
135 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
137 rndis_pkt->per_pkt_info_length += rppi_size;
143 * Get the Per-Packet-Info with the specified type
144 * return NULL if not found.
147 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
149 rndis_per_packet_info *ppi;
152 if (rpkt->per_pkt_info_offset == 0)
155 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
156 rpkt->per_pkt_info_offset);
157 len = rpkt->per_pkt_info_length;
160 if (ppi->type == type)
161 return (void *)((unsigned long)ppi +
162 ppi->per_packet_info_offset);
165 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
173 * Allow module_param to work and override to switch to promiscuous mode.
175 static inline rndis_device *
176 hv_get_rndis_device(void)
178 rndis_device *device;
180 device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
182 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
184 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
185 STAILQ_INIT(&device->myrequest_list);
187 device->state = RNDIS_DEV_UNINITIALIZED;
196 hv_put_rndis_device(rndis_device *device)
198 mtx_destroy(&device->req_lock);
199 free(device, M_NETVSC);
205 static inline rndis_request *
206 hv_rndis_request(rndis_device *device, uint32_t message_type,
207 uint32_t message_length)
209 rndis_request *request;
210 rndis_msg *rndis_mesg;
211 rndis_set_request *set;
213 request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
215 sema_init(&request->wait_sema, 0, "rndis sema");
217 rndis_mesg = &request->request_msg;
218 rndis_mesg->ndis_msg_type = message_type;
219 rndis_mesg->msg_len = message_length;
222 * Set the request id. This field is always after the rndis header
223 * for request/response packet types so we just use the set_request
226 set = &rndis_mesg->msg.set_request;
227 set->request_id = atomic_fetchadd_int(&device->new_request_id, 1) &
228 HN_RNDIS_RID_COMPAT_MASK;
230 /* Add to the request list */
231 mtx_lock(&device->req_lock);
232 STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
233 mtx_unlock(&device->req_lock);
242 hv_put_rndis_request(rndis_device *device, rndis_request *request)
244 mtx_lock(&device->req_lock);
245 /* Fixme: Has O(n) performance */
247 * XXXKYS: Use Doubly linked lists.
249 STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
251 mtx_unlock(&device->req_lock);
253 sema_destroy(&request->wait_sema);
254 free(request, M_NETVSC);
261 hv_rf_send_request(rndis_device *device, rndis_request *request,
262 uint32_t message_type)
264 struct hn_softc *sc = device->sc;
265 uint32_t send_buf_section_idx, tot_data_buf_len;
266 struct vmbus_gpa gpa[2];
267 int gpa_cnt, send_buf_section_size;
268 hn_sent_callback_t cb;
270 /* Set up the packet to send it */
271 tot_data_buf_len = request->request_msg.msg_len;
274 gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
275 gpa[0].gpa_len = request->request_msg.msg_len;
276 gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
278 if (gpa[0].gpa_ofs + gpa[0].gpa_len > PAGE_SIZE) {
280 gpa[0].gpa_len = PAGE_SIZE - gpa[0].gpa_ofs;
282 hv_get_phys_addr((char*)&request->request_msg +
283 gpa[0].gpa_len) >> PAGE_SHIFT;
285 gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
288 if (message_type != REMOTE_NDIS_HALT_MSG)
289 cb = hn_rndis_sent_cb;
291 cb = hn_rndis_sent_halt;
293 if (tot_data_buf_len < sc->hn_chim_szmax) {
294 send_buf_section_idx = hn_chim_alloc(sc);
295 if (send_buf_section_idx != HN_NVS_CHIM_IDX_INVALID) {
296 uint8_t *dest = sc->hn_chim +
297 (send_buf_section_idx * sc->hn_chim_szmax);
299 memcpy(dest, &request->request_msg, request->request_msg.msg_len);
300 send_buf_section_size = tot_data_buf_len;
304 /* Failed to allocate chimney send buffer; move on */
306 send_buf_section_idx = HN_NVS_CHIM_IDX_INVALID;
307 send_buf_section_size = 0;
310 hn_send_ctx_init(&request->send_ctx, cb, request,
311 send_buf_section_idx, send_buf_section_size);
312 return hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
313 &request->send_ctx, gpa, gpa_cnt);
317 * RNDIS filter receive response
320 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
322 rndis_request *request = NULL;
323 rndis_request *next_request;
324 boolean_t found = FALSE;
326 mtx_lock(&device->req_lock);
327 request = STAILQ_FIRST(&device->myrequest_list);
328 while (request != NULL) {
330 * All request/response message contains request_id as the
333 if (request->request_msg.msg.init_request.request_id ==
334 response->msg.init_complete.request_id) {
338 next_request = STAILQ_NEXT(request, mylist_entry);
339 request = next_request;
341 mtx_unlock(&device->req_lock);
344 if (response->msg_len <= sizeof(rndis_msg)) {
345 memcpy(&request->response_msg, response,
348 request->response_msg.msg.init_complete.status =
349 RNDIS_STATUS_BUFFER_OVERFLOW;
351 sema_post(&request->wait_sema);
356 hv_rf_send_offload_request(struct hn_softc *sc,
357 rndis_offload_params *offloads)
359 rndis_request *request;
360 rndis_set_request *set;
361 rndis_offload_params *offload_req;
362 rndis_set_complete *set_complete;
363 rndis_device *rndis_dev = sc->rndis_dev;
364 device_t dev = sc->hn_dev;
365 uint32_t extlen = sizeof(rndis_offload_params);
368 if (sc->hn_nvs_ver <= NVSP_PROTOCOL_VERSION_4) {
369 extlen = VERSION_4_OFFLOAD_SIZE;
370 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
371 * UDP checksum offload.
373 offloads->udp_ipv4_csum = 0;
374 offloads->udp_ipv6_csum = 0;
377 request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
378 RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
382 set = &request->request_msg.msg.set_request;
383 set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
384 set->info_buffer_length = extlen;
385 set->info_buffer_offset = sizeof(rndis_set_request);
386 set->device_vc_handle = 0;
388 offload_req = (rndis_offload_params *)((unsigned long)set +
389 set->info_buffer_offset);
390 *offload_req = *offloads;
391 offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
392 offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
393 offload_req->header.size = extlen;
395 ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
397 device_printf(dev, "hv send offload request failed, ret=%d!\n",
402 ret = sema_timedwait(&request->wait_sema, 5 * hz);
404 device_printf(dev, "hv send offload request timeout\n");
408 set_complete = &request->response_msg.msg.set_complete;
409 if (set_complete->status == RNDIS_STATUS_SUCCESS) {
410 device_printf(dev, "hv send offload request succeeded\n");
413 if (set_complete->status == RNDIS_STATUS_NOT_SUPPORTED) {
414 device_printf(dev, "HV Not support offload\n");
417 ret = set_complete->status;
422 hv_put_rndis_request(rndis_dev, request);
428 * RNDIS filter receive indicate status
431 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
433 const rndis_indicate_status *indicate = &response->msg.indicate_status;
435 switch(indicate->status) {
436 case RNDIS_STATUS_MEDIA_CONNECT:
437 netvsc_linkstatus_callback(device->sc, 1);
439 case RNDIS_STATUS_MEDIA_DISCONNECT:
440 netvsc_linkstatus_callback(device->sc, 0);
444 device_printf(device->sc->hn_dev,
445 "unknown status %d received\n", indicate->status);
451 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
453 const rndis_per_packet_info *ppi;
456 info->vlan_info = NULL;
457 info->csum_info = NULL;
458 info->hash_info = NULL;
459 info->hash_value = NULL;
461 if (rpkt->per_pkt_info_offset == 0)
464 ppi = (const rndis_per_packet_info *)
465 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
466 len = rpkt->per_pkt_info_length;
470 const void *ppi_dptr;
473 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
475 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
476 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
479 case ieee_8021q_info:
480 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
482 info->vlan_info = ppi_dptr;
483 mask |= HV_RF_RECVINFO_VLAN;
486 case tcpip_chksum_info:
487 if (__predict_false(ppi_dlen <
488 sizeof(rndis_tcp_ip_csum_info)))
490 info->csum_info = ppi_dptr;
491 mask |= HV_RF_RECVINFO_CSUM;
495 if (__predict_false(ppi_dlen <
496 sizeof(struct rndis_hash_value)))
498 info->hash_value = ppi_dptr;
499 mask |= HV_RF_RECVINFO_HASHVAL;
503 if (__predict_false(ppi_dlen <
504 sizeof(struct rndis_hash_info)))
506 info->hash_info = ppi_dptr;
507 mask |= HV_RF_RECVINFO_HASHINF;
514 if (mask == HV_RF_RECVINFO_ALL) {
515 /* All found; done */
519 if (__predict_false(len < ppi->size))
522 ppi = (const rndis_per_packet_info *)
523 ((const uint8_t *)ppi + ppi->size);
529 * RNDIS filter receive data
532 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
534 const rndis_msg *message = data;
535 const rndis_packet *rndis_pkt;
536 uint32_t data_offset;
537 struct hn_recvinfo info;
539 rndis_pkt = &message->msg.packet;
542 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
543 * netvsc packet (ie tot_data_buf_len != message_length)
546 /* Remove rndis header, then pass data packet up the stack */
547 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
550 if (dlen < rndis_pkt->data_length) {
551 if_printf(rxr->hn_ifp,
552 "total length %u is less than data length %u\n",
553 dlen, rndis_pkt->data_length);
557 dlen = rndis_pkt->data_length;
558 data = (const uint8_t *)data + data_offset;
560 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
561 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
564 netvsc_recv(rxr, data, dlen, &info);
568 * RNDIS filter on receive
571 hv_rf_on_receive(struct hn_softc *sc, struct hn_rx_ring *rxr,
572 const void *data, int dlen)
574 rndis_device *rndis_dev;
575 const rndis_msg *rndis_hdr;
576 const struct rndis_comp_hdr *comp;
578 rndis_dev = sc->rndis_dev;
579 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
583 switch (rndis_hdr->ndis_msg_type) {
585 case REMOTE_NDIS_PACKET_MSG:
586 hv_rf_receive_data(rxr, data, dlen);
589 /* completion messages */
590 case REMOTE_NDIS_INITIALIZE_CMPLT:
591 case REMOTE_NDIS_QUERY_CMPLT:
592 case REMOTE_NDIS_SET_CMPLT:
593 case REMOTE_NDIS_KEEPALIVE_CMPLT:
595 if (comp->rm_rid <= HN_RNDIS_RID_COMPAT_MAX) {
596 /* Transition time compat code */
597 hv_rf_receive_response(rndis_dev, rndis_hdr);
599 vmbus_xact_ctx_wakeup(sc->hn_xact, data, dlen);
603 /* notification message */
604 case REMOTE_NDIS_INDICATE_STATUS_MSG:
605 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
608 case REMOTE_NDIS_RESET_CMPLT:
610 * Reset completed, no rid.
613 * RESET is not issued by hn(4), so this message should
616 if_printf(sc->hn_ifp, "RESET CMPLT received\n");
620 if_printf(sc->hn_ifp, "unknown RNDIS message 0x%x\n",
621 rndis_hdr->ndis_msg_type);
628 * RNDIS filter query device MAC address
631 hv_rf_query_device_mac(rndis_device *device)
633 struct hn_softc *sc = device->sc;
637 hwaddr_len = ETHER_ADDR_LEN;
638 error = hn_rndis_query(sc, OID_802_3_PERMANENT_ADDRESS, NULL, 0,
639 device->hw_mac_addr, &hwaddr_len);
642 if (hwaddr_len != ETHER_ADDR_LEN) {
643 if_printf(sc->hn_ifp, "invalid hwaddr len %zu\n", hwaddr_len);
650 * RNDIS filter query device link status
653 hv_rf_query_device_link_status(rndis_device *device)
655 struct hn_softc *sc = device->sc;
659 size = sizeof(uint32_t);
660 error = hn_rndis_query(sc, OID_GEN_MEDIA_CONNECT_STATUS, NULL, 0,
661 &device->link_status, &size);
664 if (size != sizeof(uint32_t)) {
665 if_printf(sc->hn_ifp, "invalid link status len %zu\n", size);
671 static uint8_t netvsc_hash_key[NDIS_HASH_KEYSIZE_TOEPLITZ] = {
672 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
673 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
674 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
675 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
676 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
680 hn_rndis_xact_execute(struct hn_softc *sc, struct vmbus_xact *xact, uint32_t rid,
681 size_t reqlen, size_t *comp_len0, uint32_t comp_type)
683 struct vmbus_gpa gpa[HN_XACT_REQ_PGCNT];
684 const struct rndis_comp_hdr *comp;
686 size_t comp_len, min_complen = *comp_len0;
689 KASSERT(rid > HN_RNDIS_RID_COMPAT_MAX, ("invalid rid %u\n", rid));
690 KASSERT(reqlen <= HN_XACT_REQ_SIZE && reqlen > 0,
691 ("invalid request length %zu", reqlen));
692 KASSERT(min_complen >= sizeof(*comp),
693 ("invalid minimum complete len %zu", min_complen));
698 paddr = vmbus_xact_req_paddr(xact);
699 KASSERT((paddr & PAGE_MASK) == 0,
700 ("vmbus xact request is not page aligned 0x%jx", (uintmax_t)paddr));
701 for (gpa_cnt = 0; gpa_cnt < HN_XACT_REQ_PGCNT; ++gpa_cnt) {
709 gpa[gpa_cnt].gpa_page = atop(paddr) + gpa_cnt;
710 gpa[gpa_cnt].gpa_len = len;
711 gpa[gpa_cnt].gpa_ofs = 0;
715 KASSERT(reqlen == 0, ("still have %zu request data left", reqlen));
718 * Send this RNDIS control message and wait for its completion
721 vmbus_xact_activate(xact);
722 error = hv_nv_on_send(sc->hn_prichan, HN_NVS_RNDIS_MTYPE_CTRL,
723 &hn_send_ctx_none, gpa, gpa_cnt);
725 vmbus_xact_deactivate(xact);
726 if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error);
729 comp = vmbus_xact_wait(xact, &comp_len);
732 * Check this RNDIS complete message.
734 if (comp_len < min_complen) {
735 if (comp_len >= sizeof(*comp)) {
736 /* rm_status field is valid */
737 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu, "
738 "status 0x%08x\n", comp_len, comp->rm_status);
740 if_printf(sc->hn_ifp, "invalid RNDIS comp len %zu\n",
745 if (comp->rm_len < min_complen) {
746 if_printf(sc->hn_ifp, "invalid RNDIS comp msglen %u\n",
750 if (comp->rm_type != comp_type) {
751 if_printf(sc->hn_ifp, "unexpected RNDIS comp 0x%08x, "
752 "expect 0x%08x\n", comp->rm_type, comp_type);
755 if (comp->rm_rid != rid) {
756 if_printf(sc->hn_ifp, "RNDIS comp rid mismatch %u, "
757 "expect %u\n", comp->rm_rid, rid);
761 *comp_len0 = comp_len;
766 hn_rndis_query(struct hn_softc *sc, uint32_t oid,
767 const void *idata, size_t idlen, void *odata, size_t *odlen0)
769 struct rndis_query_req *req;
770 const struct rndis_query_comp *comp;
771 struct vmbus_xact *xact;
772 size_t reqlen, odlen = *odlen0, comp_len;
776 reqlen = sizeof(*req) + idlen;
777 xact = vmbus_xact_get(sc->hn_xact, reqlen);
779 if_printf(sc->hn_ifp, "no xact for RNDIS query 0x%08x\n", oid);
782 rid = hn_rndis_rid(sc);
783 req = vmbus_xact_req_data(xact);
784 req->rm_type = REMOTE_NDIS_QUERY_MSG;
785 req->rm_len = reqlen;
790 * This is _not_ RNDIS Spec conforming:
791 * "This MUST be set to 0 when there is no input data
792 * associated with the OID."
794 * If this field was set to 0 according to the RNDIS Spec,
795 * Hyper-V would set non-SUCCESS status in the query
798 req->rm_infobufoffset = RNDIS_QUERY_REQ_INFOBUFOFFSET;
801 req->rm_infobuflen = idlen;
802 /* Input data immediately follows RNDIS query. */
803 memcpy(req + 1, idata, idlen);
806 comp_len = sizeof(*comp) + odlen;
807 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
808 REMOTE_NDIS_QUERY_CMPLT);
810 if_printf(sc->hn_ifp, "exec RNDIS query 0x%08x failed\n", oid);
815 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
816 if_printf(sc->hn_ifp, "RNDIS query 0x%08x failed: "
817 "status 0x%08x\n", oid, comp->rm_status);
821 if (comp->rm_infobuflen == 0 || comp->rm_infobufoffset == 0) {
822 /* No output data! */
823 if_printf(sc->hn_ifp, "RNDIS query 0x%08x, no data\n", oid);
830 * Check output data length and offset.
832 /* ofs is the offset from the beginning of comp. */
833 ofs = RNDIS_QUERY_COMP_INFOBUFABS(comp->rm_infobufoffset);
834 if (ofs < sizeof(*comp) || ofs + comp->rm_infobuflen > comp_len) {
835 if_printf(sc->hn_ifp, "RNDIS query invalid comp ib off/len, "
836 "%u/%u\n", comp->rm_infobufoffset, comp->rm_infobuflen);
844 if (comp->rm_infobuflen < odlen)
845 odlen = comp->rm_infobuflen;
846 memcpy(odata, ((const uint8_t *)comp) + ofs, odlen);
851 vmbus_xact_put(xact);
856 hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt)
858 struct ndis_rss_caps in, caps;
863 * Only NDIS 6.30+ is supported.
865 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
866 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
869 memset(&in, 0, sizeof(in));
870 in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS;
871 in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2;
872 in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE;
874 caps_len = NDIS_RSS_CAPS_SIZE;
875 error = hn_rndis_query(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES,
876 &in, NDIS_RSS_CAPS_SIZE, &caps, &caps_len);
879 if (caps_len < NDIS_RSS_CAPS_SIZE_6_0) {
880 if_printf(sc->hn_ifp, "invalid NDIS RSS caps len %zu",
885 if (caps.ndis_nrxr == 0) {
886 if_printf(sc->hn_ifp, "0 RX rings!?\n");
889 *rxr_cnt = caps.ndis_nrxr;
891 if (caps_len == NDIS_RSS_CAPS_SIZE) {
893 if_printf(sc->hn_ifp, "RSS indirect table size %u\n",
901 hn_rndis_set(struct hn_softc *sc, uint32_t oid, const void *data, size_t dlen)
903 struct rndis_set_req *req;
904 const struct rndis_set_comp *comp;
905 struct vmbus_xact *xact;
906 size_t reqlen, comp_len;
910 KASSERT(dlen > 0, ("invalid dlen %zu", dlen));
912 reqlen = sizeof(*req) + dlen;
913 xact = vmbus_xact_get(sc->hn_xact, reqlen);
915 if_printf(sc->hn_ifp, "no xact for RNDIS set 0x%08x\n", oid);
918 rid = hn_rndis_rid(sc);
919 req = vmbus_xact_req_data(xact);
920 req->rm_type = REMOTE_NDIS_SET_MSG;
921 req->rm_len = reqlen;
924 req->rm_infobuflen = dlen;
925 req->rm_infobufoffset = RNDIS_SET_REQ_INFOBUFOFFSET;
926 /* Data immediately follows RNDIS set. */
927 memcpy(req + 1, data, dlen);
929 comp_len = sizeof(*comp);
930 comp = hn_rndis_xact_execute(sc, xact, rid, reqlen, &comp_len,
931 REMOTE_NDIS_SET_CMPLT);
933 if_printf(sc->hn_ifp, "exec RNDIS set 0x%08x failed\n", oid);
938 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
939 if_printf(sc->hn_ifp, "RNDIS set 0x%08x failed: "
940 "status 0x%08x\n", oid, comp->rm_status);
946 vmbus_xact_put(xact);
951 hn_rndis_conf_offload(struct hn_softc *sc)
953 struct ndis_offload_params params;
957 /* NOTE: 0 means "no change" */
958 memset(¶ms, 0, sizeof(params));
960 params.ndis_hdr.ndis_type = NDIS_OBJTYPE_DEFAULT;
961 if (sc->hn_ndis_ver < NDIS_VERSION_6_30) {
962 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_2;
963 paramsz = NDIS_OFFLOAD_PARAMS_SIZE_6_1;
965 params.ndis_hdr.ndis_rev = NDIS_OFFLOAD_PARAMS_REV_3;
966 paramsz = NDIS_OFFLOAD_PARAMS_SIZE;
968 params.ndis_hdr.ndis_size = paramsz;
970 params.ndis_ip4csum = NDIS_OFFLOAD_PARAM_TXRX;
971 params.ndis_tcp4csum = NDIS_OFFLOAD_PARAM_TXRX;
972 params.ndis_tcp6csum = NDIS_OFFLOAD_PARAM_TXRX;
973 if (sc->hn_ndis_ver >= NDIS_VERSION_6_30) {
974 params.ndis_udp4csum = NDIS_OFFLOAD_PARAM_TXRX;
975 params.ndis_udp6csum = NDIS_OFFLOAD_PARAM_TXRX;
977 params.ndis_lsov2_ip4 = NDIS_OFFLOAD_LSOV2_ON;
978 /* XXX ndis_lsov2_ip6 = NDIS_OFFLOAD_LSOV2_ON */
980 error = hn_rndis_set(sc, OID_TCP_OFFLOAD_PARAMETERS, ¶ms, paramsz);
982 if_printf(sc->hn_ifp, "offload config failed: %d\n", error);
985 if_printf(sc->hn_ifp, "offload config done\n");
991 hn_rndis_conf_rss(struct hn_softc *sc, int nchan)
993 struct ndis_rssprm_toeplitz *rss = &sc->hn_rss;
994 struct ndis_rss_params *prm = &rss->rss_params;
998 * Only NDIS 6.30+ is supported.
1000 KASSERT(sc->hn_ndis_ver >= NDIS_VERSION_6_30,
1001 ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver));
1003 memset(rss, 0, sizeof(*rss));
1004 prm->ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_PARAMS;
1005 prm->ndis_hdr.ndis_rev = NDIS_RSS_PARAMS_REV_2;
1006 prm->ndis_hdr.ndis_size = sizeof(*rss);
1007 prm->ndis_hash = NDIS_HASH_FUNCTION_TOEPLITZ |
1008 NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 |
1009 NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6;
1010 /* TODO: Take ndis_rss_caps.ndis_nind into account */
1011 prm->ndis_indsize = sizeof(rss->rss_ind);
1012 prm->ndis_indoffset =
1013 __offsetof(struct ndis_rssprm_toeplitz, rss_ind[0]);
1014 prm->ndis_keysize = sizeof(rss->rss_key);
1015 prm->ndis_keyoffset =
1016 __offsetof(struct ndis_rssprm_toeplitz, rss_key[0]);
1019 memcpy(rss->rss_key, netvsc_hash_key, sizeof(rss->rss_key));
1021 /* Setup RSS indirect table */
1022 /* TODO: Take ndis_rss_caps.ndis_nind into account */
1023 for (i = 0; i < NDIS_HASH_INDCNT; ++i)
1024 rss->rss_ind[i] = i % nchan;
1026 error = hn_rndis_set(sc, OID_GEN_RECEIVE_SCALE_PARAMETERS,
1029 if_printf(sc->hn_ifp, "RSS config failed: %d\n", error);
1032 if_printf(sc->hn_ifp, "RSS config done\n");
1038 hn_rndis_set_rxfilter(struct hn_softc *sc, uint32_t filter)
1042 error = hn_rndis_set(sc, OID_GEN_CURRENT_PACKET_FILTER,
1043 &filter, sizeof(filter));
1045 if_printf(sc->hn_ifp, "set RX filter 0x%08x failed: %d\n",
1049 if_printf(sc->hn_ifp, "set RX filter 0x%08x done\n",
1057 * RNDIS filter init device
1060 hv_rf_init_device(rndis_device *device)
1062 struct hn_softc *sc = device->sc;
1063 struct rndis_init_req *req;
1064 const struct rndis_init_comp *comp;
1065 struct vmbus_xact *xact;
1071 device->state = RNDIS_DEV_INITIALIZED;
1073 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1075 if_printf(sc->hn_ifp, "no xact for RNDIS init\n");
1078 rid = hn_rndis_rid(sc);
1079 req = vmbus_xact_req_data(xact);
1080 req->rm_type = REMOTE_NDIS_INITIALIZE_MSG;
1081 req->rm_len = sizeof(*req);
1083 req->rm_ver_major = RNDIS_VERSION_MAJOR;
1084 req->rm_ver_minor = RNDIS_VERSION_MINOR;
1085 req->rm_max_xfersz = HN_RNDIS_XFER_SIZE;
1087 comp_len = RNDIS_INIT_COMP_SIZE_MIN;
1088 comp = hn_rndis_xact_execute(sc, xact, rid, sizeof(*req), &comp_len,
1089 REMOTE_NDIS_INITIALIZE_CMPLT);
1091 if_printf(sc->hn_ifp, "exec RNDIS init failed\n");
1096 if (comp->rm_status != RNDIS_STATUS_SUCCESS) {
1097 if_printf(sc->hn_ifp, "RNDIS init failed: status 0x%08x\n",
1103 if_printf(sc->hn_ifp, "RNDIS ver %u.%u, pktsz %u, pktcnt %u\n",
1104 comp->rm_ver_major, comp->rm_ver_minor,
1105 comp->rm_pktmaxsz, comp->rm_pktmaxcnt);
1111 vmbus_xact_put(xact);
1115 #define HALT_COMPLETION_WAIT_COUNT 25
1118 * RNDIS filter halt device
1121 hv_rf_halt_device(rndis_device *device)
1123 rndis_request *request;
1126 /* Attempt to do a rndis device halt */
1127 request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
1128 RNDIS_MESSAGE_SIZE(rndis_halt_request));
1129 if (request == NULL) {
1133 /* initialize "poor man's semaphore" */
1134 request->halt_complete_flag = 0;
1136 ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
1142 * Wait for halt response from halt callback. We must wait for
1143 * the transaction response before freeing the request and other
1146 for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
1147 if (request->halt_complete_flag != 0) {
1156 device->state = RNDIS_DEV_UNINITIALIZED;
1158 hv_put_rndis_request(device, request);
1164 * RNDIS filter on device add
1167 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1168 int *nchan0, struct hn_rx_ring *rxr)
1171 rndis_device *rndis_dev;
1172 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1173 device_t dev = sc->hn_dev;
1174 struct hn_nvs_subch_req *req;
1175 const struct hn_nvs_subch_resp *resp;
1177 struct vmbus_xact *xact = NULL;
1178 uint32_t status, nsubch;
1179 int nchan = *nchan0;
1182 rndis_dev = hv_get_rndis_device();
1183 if (rndis_dev == NULL) {
1186 sc->rndis_dev = rndis_dev;
1190 * Let the inner driver handle this first to create the netvsc channel
1191 * NOTE! Once the channel is created, we may get a receive callback
1192 * (hv_rf_on_receive()) before this call is completed.
1193 * Note: Earlier code used a function pointer here.
1195 ret = hv_nv_on_device_add(sc, rxr);
1197 hv_put_rndis_device(rndis_dev);
1202 * Initialize the rndis device
1205 /* Send the rndis initialization message */
1206 ret = hv_rf_init_device(rndis_dev);
1209 * TODO: If rndis init failed, we will need to shut down
1214 /* Get the mac address */
1215 ret = hv_rf_query_device_mac(rndis_dev);
1217 /* TODO: shut down rndis device and the channel */
1220 /* Configure NDIS offload settings */
1221 hn_rndis_conf_offload(sc);
1223 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1225 hv_rf_query_device_link_status(rndis_dev);
1227 dev_info->link_state = rndis_dev->link_status;
1229 if (sc->hn_ndis_ver < NDIS_VERSION_6_30 || nchan == 1) {
1231 * Either RSS is not supported, or multiple RX/TX rings
1232 * are not requested.
1239 * Get RSS capabilities, e.g. # of RX rings, and # of indirect
1242 ret = hn_rndis_get_rsscaps(sc, &rxr_cnt);
1244 /* No RSS; this is benign. */
1248 if (nchan > rxr_cnt)
1250 if_printf(sc->hn_ifp, "RX rings offered %u, requested %d\n",
1254 device_printf(dev, "only 1 channel is supported, no vRSS\n");
1259 * Ask NVS to allocate sub-channels.
1261 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1263 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1267 req = vmbus_xact_req_data(xact);
1268 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1269 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1270 req->nvs_nsubch = nchan - 1;
1272 resp = hn_nvs_xact_execute(sc, xact, req, sizeof(*req), &resp_len);
1274 if_printf(sc->hn_ifp, "exec subch failed\n");
1278 if (resp_len < sizeof(*resp)) {
1279 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1284 if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1285 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1291 status = resp->nvs_status;
1292 nsubch = resp->nvs_nsubch;
1293 vmbus_xact_put(xact);
1296 if (status != HN_NVS_STATUS_OK) {
1297 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1301 if (nsubch > nchan - 1) {
1302 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1308 ret = hn_rndis_conf_rss(sc, nchan);
1315 vmbus_xact_put(xact);
1320 * RNDIS filter on device remove
1323 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1325 rndis_device *rndis_dev = sc->rndis_dev;
1328 /* Halt and release the rndis device */
1329 ret = hv_rf_halt_device(rndis_dev);
1331 sc->rndis_dev = NULL;
1332 hv_put_rndis_device(rndis_dev);
1334 /* Pass control to inner driver to remove the device */
1335 ret |= hv_nv_on_device_remove(sc, destroy_channel);
1341 * RNDIS filter on open
1344 hv_rf_on_open(struct hn_softc *sc)
1349 if (hv_promisc_mode != 1) {
1350 filter = NDIS_PACKET_TYPE_BROADCAST |
1351 NDIS_PACKET_TYPE_ALL_MULTICAST |
1352 NDIS_PACKET_TYPE_DIRECTED;
1354 filter = NDIS_PACKET_TYPE_PROMISCUOUS;
1356 return (hn_rndis_set_rxfilter(sc, filter));
1360 * RNDIS filter on close
1363 hv_rf_on_close(struct hn_softc *sc)
1366 return (hn_rndis_set_rxfilter(sc, 0));
1370 hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct hn_softc *sc,
1371 struct vmbus_channel *chan __unused, const void *data __unused,
1374 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1375 hn_chim_free(sc, sndc->hn_chim_idx);
1379 hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct hn_softc *sc,
1380 struct vmbus_channel *chan __unused, const void *data __unused,
1383 rndis_request *request = sndc->hn_cbarg;
1385 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1386 hn_chim_free(sc, sndc->hn_chim_idx);
1389 * Notify hv_rf_halt_device() about halt completion.
1390 * The halt code must wait for completion before freeing
1391 * the transaction resources.
1393 request->halt_complete_flag = 1;
1397 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1400 netvsc_channel_rollup(rxr, txr);