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>
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)
67 * Forward declarations
69 static int hv_rf_send_request(rndis_device *device, rndis_request *request,
70 uint32_t message_type);
71 static void hv_rf_receive_response(rndis_device *device,
72 const rndis_msg *response);
73 static void hv_rf_receive_indicate_status(rndis_device *device,
74 const rndis_msg *response);
75 static void hv_rf_receive_data(struct hn_rx_ring *rxr,
76 const void *data, int dlen);
77 static int hv_rf_query_device(rndis_device *device, uint32_t oid,
78 void *result, uint32_t *result_size);
79 static inline int hv_rf_query_device_mac(rndis_device *device);
80 static inline int hv_rf_query_device_link_status(rndis_device *device);
81 static int hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
82 static int hv_rf_init_device(rndis_device *device);
83 static int hv_rf_open_device(rndis_device *device);
84 static int hv_rf_close_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 netvsc_dev_ *net_dev, struct vmbus_channel *chan,
91 const void *data, int dlen);
92 static void hn_rndis_sent_cb(struct hn_send_ctx *sndc,
93 struct netvsc_dev_ *net_dev, struct vmbus_channel *chan,
94 const void *data, int dlen);
97 * Set the Per-Packet-Info with the specified type
100 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
103 rndis_packet *rndis_pkt;
104 rndis_per_packet_info *rppi;
106 rndis_pkt = &rndis_mesg->msg.packet;
107 rndis_pkt->data_offset += rppi_size;
109 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
110 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
112 rppi->size = rppi_size;
113 rppi->type = pkt_type;
114 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
116 rndis_pkt->per_pkt_info_length += rppi_size;
122 * Get the Per-Packet-Info with the specified type
123 * return NULL if not found.
126 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
128 rndis_per_packet_info *ppi;
131 if (rpkt->per_pkt_info_offset == 0)
134 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
135 rpkt->per_pkt_info_offset);
136 len = rpkt->per_pkt_info_length;
139 if (ppi->type == type)
140 return (void *)((unsigned long)ppi +
141 ppi->per_packet_info_offset);
144 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
152 * Allow module_param to work and override to switch to promiscuous mode.
154 static inline rndis_device *
155 hv_get_rndis_device(void)
157 rndis_device *device;
159 device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
161 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
163 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
164 STAILQ_INIT(&device->myrequest_list);
166 device->state = RNDIS_DEV_UNINITIALIZED;
175 hv_put_rndis_device(rndis_device *device)
177 mtx_destroy(&device->req_lock);
178 free(device, M_NETVSC);
184 static inline rndis_request *
185 hv_rndis_request(rndis_device *device, uint32_t message_type,
186 uint32_t message_length)
188 rndis_request *request;
189 rndis_msg *rndis_mesg;
190 rndis_set_request *set;
192 request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
194 sema_init(&request->wait_sema, 0, "rndis sema");
196 rndis_mesg = &request->request_msg;
197 rndis_mesg->ndis_msg_type = message_type;
198 rndis_mesg->msg_len = message_length;
201 * Set the request id. This field is always after the rndis header
202 * for request/response packet types so we just use the set_request
205 set = &rndis_mesg->msg.set_request;
206 set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
207 /* Increment to get the new value (call above returns old value) */
208 set->request_id += 1;
210 /* Add to the request list */
211 mtx_lock(&device->req_lock);
212 STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
213 mtx_unlock(&device->req_lock);
222 hv_put_rndis_request(rndis_device *device, rndis_request *request)
224 mtx_lock(&device->req_lock);
225 /* Fixme: Has O(n) performance */
227 * XXXKYS: Use Doubly linked lists.
229 STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
231 mtx_unlock(&device->req_lock);
233 sema_destroy(&request->wait_sema);
234 free(request, M_NETVSC);
241 hv_rf_send_request(rndis_device *device, rndis_request *request,
242 uint32_t message_type)
244 netvsc_dev *net_dev = device->net_dev;
245 uint32_t send_buf_section_idx, tot_data_buf_len;
246 struct vmbus_gpa gpa[2];
247 int gpa_cnt, send_buf_section_size;
248 hn_sent_callback_t cb;
250 /* Set up the packet to send it */
251 tot_data_buf_len = request->request_msg.msg_len;
254 gpa[0].gpa_page = hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
255 gpa[0].gpa_len = request->request_msg.msg_len;
256 gpa[0].gpa_ofs = (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
258 if (gpa[0].gpa_ofs + gpa[0].gpa_len > PAGE_SIZE) {
260 gpa[0].gpa_len = PAGE_SIZE - gpa[0].gpa_ofs;
262 hv_get_phys_addr((char*)&request->request_msg +
263 gpa[0].gpa_len) >> PAGE_SHIFT;
265 gpa[1].gpa_len = request->request_msg.msg_len - gpa[0].gpa_len;
268 if (message_type != REMOTE_NDIS_HALT_MSG)
269 cb = hn_rndis_sent_cb;
271 cb = hn_rndis_sent_halt;
273 if (tot_data_buf_len < net_dev->send_section_size) {
274 send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
275 if (send_buf_section_idx != HN_NVS_CHIM_IDX_INVALID) {
276 char *dest = ((char *)net_dev->send_buf +
277 send_buf_section_idx * net_dev->send_section_size);
279 memcpy(dest, &request->request_msg, request->request_msg.msg_len);
280 send_buf_section_size = tot_data_buf_len;
284 /* Failed to allocate chimney send buffer; move on */
286 send_buf_section_idx = HN_NVS_CHIM_IDX_INVALID;
287 send_buf_section_size = 0;
290 hn_send_ctx_init(&request->send_ctx, cb, request,
291 send_buf_section_idx, send_buf_section_size);
292 return hv_nv_on_send(device->net_dev->sc->hn_prichan,
293 HN_NVS_RNDIS_MTYPE_CTRL, &request->send_ctx, gpa, gpa_cnt);
297 * RNDIS filter receive response
300 hv_rf_receive_response(rndis_device *device, const rndis_msg *response)
302 rndis_request *request = NULL;
303 rndis_request *next_request;
304 boolean_t found = FALSE;
306 mtx_lock(&device->req_lock);
307 request = STAILQ_FIRST(&device->myrequest_list);
308 while (request != NULL) {
310 * All request/response message contains request_id as the
313 if (request->request_msg.msg.init_request.request_id ==
314 response->msg.init_complete.request_id) {
318 next_request = STAILQ_NEXT(request, mylist_entry);
319 request = next_request;
321 mtx_unlock(&device->req_lock);
324 if (response->msg_len <= sizeof(rndis_msg)) {
325 memcpy(&request->response_msg, response,
328 if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
329 /* Does not have a request id field */
330 request->response_msg.msg.reset_complete.status =
331 STATUS_BUFFER_OVERFLOW;
333 request->response_msg.msg.init_complete.status =
334 STATUS_BUFFER_OVERFLOW;
338 sema_post(&request->wait_sema);
343 hv_rf_send_offload_request(struct hn_softc *sc,
344 rndis_offload_params *offloads)
346 rndis_request *request;
347 rndis_set_request *set;
348 rndis_offload_params *offload_req;
349 rndis_set_complete *set_complete;
350 rndis_device *rndis_dev;
351 device_t dev = sc->hn_dev;
352 netvsc_dev *net_dev = sc->net_dev;
353 uint32_t vsp_version = net_dev->nvsp_version;
354 uint32_t extlen = sizeof(rndis_offload_params);
357 if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
358 extlen = VERSION_4_OFFLOAD_SIZE;
359 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
360 * UDP checksum offload.
362 offloads->udp_ipv4_csum = 0;
363 offloads->udp_ipv6_csum = 0;
366 rndis_dev = net_dev->extension;
368 request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
369 RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
373 set = &request->request_msg.msg.set_request;
374 set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
375 set->info_buffer_length = extlen;
376 set->info_buffer_offset = sizeof(rndis_set_request);
377 set->device_vc_handle = 0;
379 offload_req = (rndis_offload_params *)((unsigned long)set +
380 set->info_buffer_offset);
381 *offload_req = *offloads;
382 offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
383 offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
384 offload_req->header.size = extlen;
386 ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
388 device_printf(dev, "hv send offload request failed, ret=%d!\n",
393 ret = sema_timedwait(&request->wait_sema, 5 * hz);
395 device_printf(dev, "hv send offload request timeout\n");
399 set_complete = &request->response_msg.msg.set_complete;
400 if (set_complete->status == RNDIS_STATUS_SUCCESS) {
401 device_printf(dev, "hv send offload request succeeded\n");
404 if (set_complete->status == STATUS_NOT_SUPPORTED) {
405 device_printf(dev, "HV Not support offload\n");
408 ret = set_complete->status;
413 hv_put_rndis_request(rndis_dev, request);
419 * RNDIS filter receive indicate status
422 hv_rf_receive_indicate_status(rndis_device *device, const rndis_msg *response)
424 const rndis_indicate_status *indicate = &response->msg.indicate_status;
426 switch(indicate->status) {
427 case RNDIS_STATUS_MEDIA_CONNECT:
428 netvsc_linkstatus_callback(device->net_dev->sc, 1);
430 case RNDIS_STATUS_MEDIA_DISCONNECT:
431 netvsc_linkstatus_callback(device->net_dev->sc, 0);
435 device_printf(device->net_dev->sc->hn_dev,
436 "unknown status %d received\n", indicate->status);
442 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hn_recvinfo *info)
444 const rndis_per_packet_info *ppi;
447 info->vlan_info = NULL;
448 info->csum_info = NULL;
449 info->hash_info = NULL;
450 info->hash_value = NULL;
452 if (rpkt->per_pkt_info_offset == 0)
455 ppi = (const rndis_per_packet_info *)
456 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
457 len = rpkt->per_pkt_info_length;
461 const void *ppi_dptr;
464 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
466 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
467 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
470 case ieee_8021q_info:
471 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
473 info->vlan_info = ppi_dptr;
474 mask |= HV_RF_RECVINFO_VLAN;
477 case tcpip_chksum_info:
478 if (__predict_false(ppi_dlen <
479 sizeof(rndis_tcp_ip_csum_info)))
481 info->csum_info = ppi_dptr;
482 mask |= HV_RF_RECVINFO_CSUM;
486 if (__predict_false(ppi_dlen <
487 sizeof(struct rndis_hash_value)))
489 info->hash_value = ppi_dptr;
490 mask |= HV_RF_RECVINFO_HASHVAL;
494 if (__predict_false(ppi_dlen <
495 sizeof(struct rndis_hash_info)))
497 info->hash_info = ppi_dptr;
498 mask |= HV_RF_RECVINFO_HASHINF;
505 if (mask == HV_RF_RECVINFO_ALL) {
506 /* All found; done */
510 if (__predict_false(len < ppi->size))
513 ppi = (const rndis_per_packet_info *)
514 ((const uint8_t *)ppi + ppi->size);
520 * RNDIS filter receive data
523 hv_rf_receive_data(struct hn_rx_ring *rxr, const void *data, int dlen)
525 const rndis_msg *message = data;
526 const rndis_packet *rndis_pkt;
527 uint32_t data_offset;
528 struct hn_recvinfo info;
530 rndis_pkt = &message->msg.packet;
533 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
534 * netvsc packet (ie tot_data_buf_len != message_length)
537 /* Remove rndis header, then pass data packet up the stack */
538 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
541 if (dlen < rndis_pkt->data_length) {
542 if_printf(rxr->hn_ifp,
543 "total length %u is less than data length %u\n",
544 dlen, rndis_pkt->data_length);
548 dlen = rndis_pkt->data_length;
549 data = (const uint8_t *)data + data_offset;
551 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
552 if_printf(rxr->hn_ifp, "recvinfo parsing failed\n");
555 netvsc_recv(rxr, data, dlen, &info);
559 * RNDIS filter on receive
562 hv_rf_on_receive(netvsc_dev *net_dev,
563 struct hn_rx_ring *rxr, const void *data, int dlen)
565 rndis_device *rndis_dev;
566 const rndis_msg *rndis_hdr;
568 /* Make sure the rndis device state is initialized */
569 if (net_dev->extension == NULL)
572 rndis_dev = (rndis_device *)net_dev->extension;
573 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
577 switch (rndis_hdr->ndis_msg_type) {
580 case REMOTE_NDIS_PACKET_MSG:
581 hv_rf_receive_data(rxr, data, dlen);
583 /* completion messages */
584 case REMOTE_NDIS_INITIALIZE_CMPLT:
585 case REMOTE_NDIS_QUERY_CMPLT:
586 case REMOTE_NDIS_SET_CMPLT:
587 case REMOTE_NDIS_RESET_CMPLT:
588 case REMOTE_NDIS_KEEPALIVE_CMPLT:
589 hv_rf_receive_response(rndis_dev, rndis_hdr);
591 /* notification message */
592 case REMOTE_NDIS_INDICATE_STATUS_MSG:
593 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
596 printf("hv_rf_on_receive(): Unknown msg_type 0x%x\n",
597 rndis_hdr->ndis_msg_type);
605 * RNDIS filter query device
608 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
609 uint32_t *result_size)
611 rndis_request *request;
612 uint32_t in_result_size = *result_size;
613 rndis_query_request *query;
614 rndis_query_complete *query_complete;
618 request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
619 RNDIS_MESSAGE_SIZE(rndis_query_request));
620 if (request == NULL) {
625 /* Set up the rndis query */
626 query = &request->request_msg.msg.query_request;
628 query->info_buffer_offset = sizeof(rndis_query_request);
629 query->info_buffer_length = 0;
630 query->device_vc_handle = 0;
632 if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
633 struct rndis_recv_scale_cap *cap;
635 request->request_msg.msg_len +=
636 sizeof(struct rndis_recv_scale_cap);
637 query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
638 cap = (struct rndis_recv_scale_cap *)((unsigned long)query +
639 query->info_buffer_offset);
640 cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
641 cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
642 cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
645 ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
647 /* Fixme: printf added */
648 printf("RNDISFILTER request failed to Send!\n");
652 sema_wait(&request->wait_sema);
654 /* Copy the response back */
655 query_complete = &request->response_msg.msg.query_complete;
657 if (query_complete->info_buffer_length > in_result_size) {
662 memcpy(result, (void *)((unsigned long)query_complete +
663 query_complete->info_buffer_offset),
664 query_complete->info_buffer_length);
666 *result_size = query_complete->info_buffer_length;
670 hv_put_rndis_request(device, request);
676 * RNDIS filter query device MAC address
679 hv_rf_query_device_mac(rndis_device *device)
681 uint32_t size = ETHER_ADDR_LEN;
683 return (hv_rf_query_device(device,
684 RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
688 * RNDIS filter query device link status
691 hv_rf_query_device_link_status(rndis_device *device)
693 uint32_t size = sizeof(uint32_t);
695 return (hv_rf_query_device(device,
696 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
699 static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
700 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
701 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
702 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
703 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
704 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
708 * RNDIS set vRSS parameters
711 hv_rf_set_rss_param(rndis_device *device, int num_queue)
713 rndis_request *request;
714 rndis_set_request *set;
715 rndis_set_complete *set_complete;
716 rndis_recv_scale_param *rssp;
717 uint32_t extlen = sizeof(rndis_recv_scale_param) +
718 (4 * ITAB_NUM) + HASH_KEYLEN;
719 uint32_t *itab, status;
724 request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
725 RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
726 if (request == NULL) {
728 printf("Netvsc: No memory to set vRSS parameters.\n");
733 set = &request->request_msg.msg.set_request;
734 set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
735 set->info_buffer_length = extlen;
736 set->info_buffer_offset = sizeof(rndis_set_request);
737 set->device_vc_handle = 0;
739 /* Fill out the rssp parameter structure */
740 rssp = (rndis_recv_scale_param *)(set + 1);
741 rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
742 rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
743 rssp->hdr.size = sizeof(rndis_recv_scale_param);
745 rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
746 RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
747 rssp->indirect_tabsize = 4 * ITAB_NUM;
748 rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
749 rssp->hashkey_size = HASH_KEYLEN;
750 rssp->hashkey_offset = rssp->indirect_taboffset +
751 rssp->indirect_tabsize;
753 /* Set indirection table entries */
754 itab = (uint32_t *)(rssp + 1);
755 for (i = 0; i < ITAB_NUM; i++)
756 itab[i] = i % num_queue;
758 /* Set hash key values */
759 keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
760 for (i = 0; i < HASH_KEYLEN; i++)
761 keyp[i] = netvsc_hash_key[i];
763 ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
769 * Wait for the response from the host. Another thread will signal
770 * us when the response has arrived. In the failure case,
771 * sema_timedwait() returns a non-zero status after waiting 5 seconds.
773 ret = sema_timedwait(&request->wait_sema, 5 * hz);
775 /* Response received, check status */
776 set_complete = &request->response_msg.msg.set_complete;
777 status = set_complete->status;
778 if (status != RNDIS_STATUS_SUCCESS) {
779 /* Bad response status, return error */
781 printf("Netvsc: Failed to set vRSS "
786 printf("Netvsc: Successfully set vRSS "
791 * We cannot deallocate the request since we may still
792 * receive a send completion for it.
794 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
795 request->request_msg.msg.init_request.request_id, ret);
800 if (request != NULL) {
801 hv_put_rndis_request(device, request);
808 * RNDIS filter set packet filter
809 * Sends an rndis request with the new filter, then waits for a response
811 * Returns zero on success, non-zero on failure.
814 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
816 rndis_request *request;
817 rndis_set_request *set;
818 rndis_set_complete *set_complete;
822 request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
823 RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
824 if (request == NULL) {
829 /* Set up the rndis set */
830 set = &request->request_msg.msg.set_request;
831 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
832 set->info_buffer_length = sizeof(uint32_t);
833 set->info_buffer_offset = sizeof(rndis_set_request);
835 memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
836 &new_filter, sizeof(uint32_t));
838 ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
844 * Wait for the response from the host. Another thread will signal
845 * us when the response has arrived. In the failure case,
846 * sema_timedwait() returns a non-zero status after waiting 5 seconds.
848 ret = sema_timedwait(&request->wait_sema, 5 * hz);
850 /* Response received, check status */
851 set_complete = &request->response_msg.msg.set_complete;
852 status = set_complete->status;
853 if (status != RNDIS_STATUS_SUCCESS) {
854 /* Bad response status, return error */
859 * We cannot deallocate the request since we may still
860 * receive a send completion for it.
866 if (request != NULL) {
867 hv_put_rndis_request(device, request);
874 * RNDIS filter init device
877 hv_rf_init_device(rndis_device *device)
879 rndis_request *request;
880 rndis_initialize_request *init;
881 rndis_initialize_complete *init_complete;
885 request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
886 RNDIS_MESSAGE_SIZE(rndis_initialize_request));
892 /* Set up the rndis set */
893 init = &request->request_msg.msg.init_request;
894 init->major_version = RNDIS_MAJOR_VERSION;
895 init->minor_version = RNDIS_MINOR_VERSION;
897 * Per the RNDIS document, this should be set to the max MTU
898 * plus the header size. However, 2048 works fine, so leaving
901 init->max_xfer_size = 2048;
903 device->state = RNDIS_DEV_INITIALIZING;
905 ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
907 device->state = RNDIS_DEV_UNINITIALIZED;
911 sema_wait(&request->wait_sema);
913 init_complete = &request->response_msg.msg.init_complete;
914 status = init_complete->status;
915 if (status == RNDIS_STATUS_SUCCESS) {
916 device->state = RNDIS_DEV_INITIALIZED;
919 device->state = RNDIS_DEV_UNINITIALIZED;
925 hv_put_rndis_request(device, request);
931 #define HALT_COMPLETION_WAIT_COUNT 25
934 * RNDIS filter halt device
937 hv_rf_halt_device(rndis_device *device)
939 rndis_request *request;
940 rndis_halt_request *halt;
943 /* Attempt to do a rndis device halt */
944 request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
945 RNDIS_MESSAGE_SIZE(rndis_halt_request));
946 if (request == NULL) {
950 /* initialize "poor man's semaphore" */
951 request->halt_complete_flag = 0;
953 /* Set up the rndis set */
954 halt = &request->request_msg.msg.halt_request;
955 halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
956 /* Increment to get the new value (call above returns old value) */
957 halt->request_id += 1;
959 ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
965 * Wait for halt response from halt callback. We must wait for
966 * the transaction response before freeing the request and other
969 for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
970 if (request->halt_complete_flag != 0) {
979 device->state = RNDIS_DEV_UNINITIALIZED;
981 hv_put_rndis_request(device, request);
987 * RNDIS filter open device
990 hv_rf_open_device(rndis_device *device)
994 if (device->state != RNDIS_DEV_INITIALIZED) {
998 if (hv_promisc_mode != 1) {
999 ret = hv_rf_set_packet_filter(device,
1000 NDIS_PACKET_TYPE_BROADCAST |
1001 NDIS_PACKET_TYPE_ALL_MULTICAST |
1002 NDIS_PACKET_TYPE_DIRECTED);
1004 ret = hv_rf_set_packet_filter(device,
1005 NDIS_PACKET_TYPE_PROMISCUOUS);
1009 device->state = RNDIS_DEV_DATAINITIALIZED;
1016 * RNDIS filter close device
1019 hv_rf_close_device(rndis_device *device)
1023 if (device->state != RNDIS_DEV_DATAINITIALIZED) {
1027 ret = hv_rf_set_packet_filter(device, 0);
1029 device->state = RNDIS_DEV_INITIALIZED;
1036 * RNDIS filter on device add
1039 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1040 int nchan, struct hn_rx_ring *rxr)
1042 struct hn_send_ctx sndc;
1044 netvsc_dev *net_dev;
1045 rndis_device *rndis_dev;
1046 rndis_offload_params offloads;
1047 struct rndis_recv_scale_cap rsscaps;
1048 uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
1049 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1050 device_t dev = sc->hn_dev;
1051 struct hn_nvs_subch_req *req;
1052 const struct hn_nvs_subch_resp *resp;
1054 struct vmbus_xact *xact;
1055 uint32_t status, nsubch;
1057 rndis_dev = hv_get_rndis_device();
1058 if (rndis_dev == NULL) {
1063 * Let the inner driver handle this first to create the netvsc channel
1064 * NOTE! Once the channel is created, we may get a receive callback
1065 * (hv_rf_on_receive()) before this call is completed.
1066 * Note: Earlier code used a function pointer here.
1068 net_dev = hv_nv_on_device_add(sc, additl_info, rxr);
1070 hv_put_rndis_device(rndis_dev);
1076 * Initialize the rndis device
1079 net_dev->extension = rndis_dev;
1080 rndis_dev->net_dev = net_dev;
1082 /* Send the rndis initialization message */
1083 ret = hv_rf_init_device(rndis_dev);
1086 * TODO: If rndis init failed, we will need to shut down
1091 /* Get the mac address */
1092 ret = hv_rf_query_device_mac(rndis_dev);
1094 /* TODO: shut down rndis device and the channel */
1097 /* config csum offload and send request to host */
1098 memset(&offloads, 0, sizeof(offloads));
1099 offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1100 offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1101 offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1102 offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1103 offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1104 offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1106 ret = hv_rf_send_offload_request(sc, &offloads);
1108 /* TODO: shut down rndis device and the channel */
1110 "hv_rf_send_offload_request failed, ret=%d\n", ret);
1113 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, ETHER_ADDR_LEN);
1115 hv_rf_query_device_link_status(rndis_dev);
1117 dev_info->link_state = rndis_dev->link_status;
1119 net_dev->num_channel = 1;
1120 if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1123 memset(&rsscaps, 0, rsscaps_size);
1124 ret = hv_rf_query_device(rndis_dev,
1125 RNDIS_OID_GEN_RSS_CAPABILITIES,
1126 &rsscaps, &rsscaps_size);
1127 if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
1128 device_printf(dev, "hv_rf_query_device failed or "
1129 "rsscaps.num_recv_que < 2 \n");
1132 device_printf(dev, "channel, offered %u, requested %d\n",
1133 rsscaps.num_recv_que, nchan);
1134 if (nchan > rsscaps.num_recv_que)
1135 nchan = rsscaps.num_recv_que;
1136 net_dev->num_channel = nchan;
1138 if (net_dev->num_channel == 1) {
1139 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1144 * Ask NVS to allocate sub-channels.
1146 xact = vmbus_xact_get(sc->hn_xact, sizeof(*req));
1148 if_printf(sc->hn_ifp, "no xact for nvs subch req\n");
1153 req = vmbus_xact_req_data(xact);
1154 req->nvs_type = HN_NVS_TYPE_SUBCH_REQ;
1155 req->nvs_op = HN_NVS_SUBCH_OP_ALLOC;
1156 req->nvs_nsubch = net_dev->num_channel - 1;
1158 hn_send_ctx_init_simple(&sndc, hn_nvs_sent_xact, xact);
1159 vmbus_xact_activate(xact);
1161 ret = hn_nvs_send(sc->hn_prichan, VMBUS_CHANPKT_FLAG_RC,
1162 req, sizeof(*req), &sndc);
1164 if_printf(sc->hn_ifp, "send nvs subch req failed: %d\n", ret);
1165 vmbus_xact_deactivate(xact);
1166 vmbus_xact_put(xact);
1170 resp = vmbus_xact_wait(xact, &resp_len);
1171 if (resp_len < sizeof(*resp)) {
1172 if_printf(sc->hn_ifp, "invalid subch resp length %zu\n",
1174 vmbus_xact_put(xact);
1178 if (resp->nvs_type != HN_NVS_TYPE_SUBCH_RESP) {
1179 if_printf(sc->hn_ifp, "not subch resp, type %u\n",
1181 vmbus_xact_put(xact);
1186 status = resp->nvs_status;
1187 nsubch = resp->nvs_nsubch;
1188 vmbus_xact_put(xact);
1190 if (status != HN_NVS_STATUS_OK) {
1191 if_printf(sc->hn_ifp, "subch req failed: %x\n", status);
1195 if (nsubch > net_dev->num_channel - 1) {
1196 if_printf(sc->hn_ifp, "%u subchans are allocated, requested %u\n",
1197 nsubch, net_dev->num_channel - 1);
1198 nsubch = net_dev->num_channel - 1;
1200 net_dev->num_channel = nsubch + 1;
1202 ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1206 net_dev->num_channel = 1;
1212 * RNDIS filter on device remove
1215 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1217 netvsc_dev *net_dev = sc->net_dev;
1218 rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1221 /* Halt and release the rndis device */
1222 ret = hv_rf_halt_device(rndis_dev);
1224 hv_put_rndis_device(rndis_dev);
1225 net_dev->extension = NULL;
1227 /* Pass control to inner driver to remove the device */
1228 ret |= hv_nv_on_device_remove(sc, destroy_channel);
1234 * RNDIS filter on open
1237 hv_rf_on_open(struct hn_softc *sc)
1239 netvsc_dev *net_dev = sc->net_dev;
1241 return (hv_rf_open_device((rndis_device *)net_dev->extension));
1245 * RNDIS filter on close
1248 hv_rf_on_close(struct hn_softc *sc)
1250 netvsc_dev *net_dev = sc->net_dev;
1252 return (hv_rf_close_device((rndis_device *)net_dev->extension));
1256 hn_rndis_sent_cb(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
1257 struct vmbus_channel *chan __unused, const void *data __unused,
1260 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1261 hn_chim_free(net_dev, sndc->hn_chim_idx);
1265 hn_rndis_sent_halt(struct hn_send_ctx *sndc, struct netvsc_dev_ *net_dev,
1266 struct vmbus_channel *chan __unused, const void *data __unused,
1269 rndis_request *request = sndc->hn_cbarg;
1271 if (sndc->hn_chim_idx != HN_NVS_CHIM_IDX_INVALID)
1272 hn_chim_free(net_dev, sndc->hn_chim_idx);
1275 * Notify hv_rf_halt_device() about halt completion.
1276 * The halt code must wait for completion before freeing
1277 * the transaction resources.
1279 request->halt_complete_flag = 1;
1283 hv_rf_channel_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr)
1286 netvsc_channel_rollup(rxr, txr);