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>
38 #include <net/if_arp.h>
39 #include <net/ethernet.h>
40 #include <sys/types.h>
41 #include <machine/atomic.h>
44 #include <vm/vm_param.h>
47 #include <dev/hyperv/include/hyperv.h>
48 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
49 #include "hv_net_vsc.h"
51 #include "hv_rndis_filter.h"
53 struct hv_rf_recvinfo {
54 const ndis_8021q_info *vlan_info;
55 const rndis_tcp_ip_csum_info *csum_info;
56 const struct rndis_hash_info *hash_info;
57 const struct rndis_hash_value *hash_value;
60 #define HV_RF_RECVINFO_VLAN 0x1
61 #define HV_RF_RECVINFO_CSUM 0x2
62 #define HV_RF_RECVINFO_HASHINF 0x4
63 #define HV_RF_RECVINFO_HASHVAL 0x8
64 #define HV_RF_RECVINFO_ALL \
65 (HV_RF_RECVINFO_VLAN | \
66 HV_RF_RECVINFO_CSUM | \
67 HV_RF_RECVINFO_HASHINF | \
68 HV_RF_RECVINFO_HASHVAL)
71 * Forward declarations
73 static int hv_rf_send_request(rndis_device *device, rndis_request *request,
74 uint32_t message_type);
75 static void hv_rf_receive_response(rndis_device *device, rndis_msg *response);
76 static void hv_rf_receive_indicate_status(rndis_device *device,
78 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
79 struct hv_vmbus_channel *chan,
81 static int hv_rf_query_device(rndis_device *device, uint32_t oid,
82 void *result, uint32_t *result_size);
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_set_packet_filter(rndis_device *device, uint32_t new_filter);
86 static int hv_rf_init_device(rndis_device *device);
87 static int hv_rf_open_device(rndis_device *device);
88 static int hv_rf_close_device(rndis_device *device);
89 static void hv_rf_on_send_request_completion(struct hv_vmbus_channel *, void *context);
90 static void hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *, void *context);
92 hv_rf_send_offload_request(struct hn_softc *sc,
93 rndis_offload_params *offloads);
95 * Set the Per-Packet-Info with the specified type
98 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
101 rndis_packet *rndis_pkt;
102 rndis_per_packet_info *rppi;
104 rndis_pkt = &rndis_mesg->msg.packet;
105 rndis_pkt->data_offset += rppi_size;
107 rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
108 rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
110 rppi->size = rppi_size;
111 rppi->type = pkt_type;
112 rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
114 rndis_pkt->per_pkt_info_length += rppi_size;
120 * Get the Per-Packet-Info with the specified type
121 * return NULL if not found.
124 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
126 rndis_per_packet_info *ppi;
129 if (rpkt->per_pkt_info_offset == 0)
132 ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
133 rpkt->per_pkt_info_offset);
134 len = rpkt->per_pkt_info_length;
137 if (ppi->type == type)
138 return (void *)((unsigned long)ppi +
139 ppi->per_packet_info_offset);
142 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
150 * Allow module_param to work and override to switch to promiscuous mode.
152 static inline rndis_device *
153 hv_get_rndis_device(void)
155 rndis_device *device;
157 device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
159 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
161 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
162 STAILQ_INIT(&device->myrequest_list);
164 device->state = RNDIS_DEV_UNINITIALIZED;
173 hv_put_rndis_device(rndis_device *device)
175 mtx_destroy(&device->req_lock);
176 free(device, M_NETVSC);
182 static inline rndis_request *
183 hv_rndis_request(rndis_device *device, uint32_t message_type,
184 uint32_t message_length)
186 rndis_request *request;
187 rndis_msg *rndis_mesg;
188 rndis_set_request *set;
190 request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
192 sema_init(&request->wait_sema, 0, "rndis sema");
194 rndis_mesg = &request->request_msg;
195 rndis_mesg->ndis_msg_type = message_type;
196 rndis_mesg->msg_len = message_length;
199 * Set the request id. This field is always after the rndis header
200 * for request/response packet types so we just use the set_request
203 set = &rndis_mesg->msg.set_request;
204 set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
205 /* Increment to get the new value (call above returns old value) */
206 set->request_id += 1;
208 /* Add to the request list */
209 mtx_lock(&device->req_lock);
210 STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
211 mtx_unlock(&device->req_lock);
220 hv_put_rndis_request(rndis_device *device, rndis_request *request)
222 mtx_lock(&device->req_lock);
223 /* Fixme: Has O(n) performance */
225 * XXXKYS: Use Doubly linked lists.
227 STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
229 mtx_unlock(&device->req_lock);
231 sema_destroy(&request->wait_sema);
232 free(request, M_NETVSC);
239 hv_rf_send_request(rndis_device *device, rndis_request *request,
240 uint32_t message_type)
243 netvsc_packet *packet;
244 netvsc_dev *net_dev = device->net_dev;
245 int send_buf_section_idx;
247 /* Set up the packet to send it */
248 packet = &request->pkt;
250 packet->is_data_pkt = FALSE;
251 packet->tot_data_buf_len = request->request_msg.msg_len;
252 packet->page_buf_count = 1;
254 packet->page_buffers[0].pfn =
255 hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
256 packet->page_buffers[0].length = request->request_msg.msg_len;
257 packet->page_buffers[0].offset =
258 (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
260 if (packet->page_buffers[0].offset +
261 packet->page_buffers[0].length > PAGE_SIZE) {
262 packet->page_buf_count = 2;
263 packet->page_buffers[0].length =
264 PAGE_SIZE - packet->page_buffers[0].offset;
265 packet->page_buffers[1].pfn =
266 hv_get_phys_addr((char*)&request->request_msg +
267 packet->page_buffers[0].length) >> PAGE_SHIFT;
268 packet->page_buffers[1].offset = 0;
269 packet->page_buffers[1].length =
270 request->request_msg.msg_len -
271 packet->page_buffers[0].length;
274 packet->compl.send.send_completion_context = request; /* packet */
275 if (message_type != REMOTE_NDIS_HALT_MSG) {
276 packet->compl.send.on_send_completion =
277 hv_rf_on_send_request_completion;
279 packet->compl.send.on_send_completion =
280 hv_rf_on_send_request_halt_completion;
282 packet->compl.send.send_completion_tid = (unsigned long)device;
283 if (packet->tot_data_buf_len < net_dev->send_section_size) {
284 send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
285 if (send_buf_section_idx !=
286 NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
287 char *dest = ((char *)net_dev->send_buf +
288 send_buf_section_idx * net_dev->send_section_size);
290 memcpy(dest, &request->request_msg, request->request_msg.msg_len);
291 packet->send_buf_section_idx = send_buf_section_idx;
292 packet->send_buf_section_size = packet->tot_data_buf_len;
293 packet->page_buf_count = 0;
296 /* Failed to allocate chimney send buffer; move on */
298 packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
299 packet->send_buf_section_size = 0;
302 ret = hv_nv_on_send(device->net_dev->sc->hn_prichan, packet);
308 * RNDIS filter receive response
311 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
313 rndis_request *request = NULL;
314 rndis_request *next_request;
315 boolean_t found = FALSE;
317 mtx_lock(&device->req_lock);
318 request = STAILQ_FIRST(&device->myrequest_list);
319 while (request != NULL) {
321 * All request/response message contains request_id as the
324 if (request->request_msg.msg.init_request.request_id ==
325 response->msg.init_complete.request_id) {
329 next_request = STAILQ_NEXT(request, mylist_entry);
330 request = next_request;
332 mtx_unlock(&device->req_lock);
335 if (response->msg_len <= sizeof(rndis_msg)) {
336 memcpy(&request->response_msg, response,
339 if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
340 /* Does not have a request id field */
341 request->response_msg.msg.reset_complete.status =
342 STATUS_BUFFER_OVERFLOW;
344 request->response_msg.msg.init_complete.status =
345 STATUS_BUFFER_OVERFLOW;
349 sema_post(&request->wait_sema);
354 hv_rf_send_offload_request(struct hn_softc *sc,
355 rndis_offload_params *offloads)
357 rndis_request *request;
358 rndis_set_request *set;
359 rndis_offload_params *offload_req;
360 rndis_set_complete *set_complete;
361 rndis_device *rndis_dev;
362 device_t dev = sc->hn_dev;
363 netvsc_dev *net_dev = sc->net_dev;
364 uint32_t vsp_version = net_dev->nvsp_version;
365 uint32_t extlen = sizeof(rndis_offload_params);
368 if (vsp_version <= 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 rndis_dev = net_dev->extension;
379 request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
380 RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
384 set = &request->request_msg.msg.set_request;
385 set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
386 set->info_buffer_length = extlen;
387 set->info_buffer_offset = sizeof(rndis_set_request);
388 set->device_vc_handle = 0;
390 offload_req = (rndis_offload_params *)((unsigned long)set +
391 set->info_buffer_offset);
392 *offload_req = *offloads;
393 offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
394 offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
395 offload_req->header.size = extlen;
397 ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
399 device_printf(dev, "hv send offload request failed, ret=%d!\n",
404 ret = sema_timedwait(&request->wait_sema, 5 * hz);
406 device_printf(dev, "hv send offload request timeout\n");
410 set_complete = &request->response_msg.msg.set_complete;
411 if (set_complete->status == RNDIS_STATUS_SUCCESS) {
412 device_printf(dev, "hv send offload request succeeded\n");
415 if (set_complete->status == STATUS_NOT_SUPPORTED) {
416 device_printf(dev, "HV Not support offload\n");
419 ret = set_complete->status;
424 hv_put_rndis_request(rndis_dev, request);
430 * RNDIS filter receive indicate status
433 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
435 rndis_indicate_status *indicate = &response->msg.indicate_status;
437 switch(indicate->status) {
438 case RNDIS_STATUS_MEDIA_CONNECT:
439 netvsc_linkstatus_callback(device->net_dev->sc, 1);
441 case RNDIS_STATUS_MEDIA_DISCONNECT:
442 netvsc_linkstatus_callback(device->net_dev->sc, 0);
446 device_printf(device->net_dev->sc->hn_dev,
447 "unknown status %d received\n", indicate->status);
453 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hv_rf_recvinfo *info)
455 const rndis_per_packet_info *ppi;
458 info->vlan_info = NULL;
459 info->csum_info = NULL;
460 info->hash_info = NULL;
461 info->hash_value = NULL;
463 if (rpkt->per_pkt_info_offset == 0)
466 ppi = (const rndis_per_packet_info *)
467 ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
468 len = rpkt->per_pkt_info_length;
472 const void *ppi_dptr;
475 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
477 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
478 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
481 case ieee_8021q_info:
482 if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
484 info->vlan_info = ppi_dptr;
485 mask |= HV_RF_RECVINFO_VLAN;
488 case tcpip_chksum_info:
489 if (__predict_false(ppi_dlen <
490 sizeof(rndis_tcp_ip_csum_info)))
492 info->csum_info = ppi_dptr;
493 mask |= HV_RF_RECVINFO_CSUM;
497 if (__predict_false(ppi_dlen <
498 sizeof(struct rndis_hash_value)))
500 info->hash_value = ppi_dptr;
501 mask |= HV_RF_RECVINFO_HASHVAL;
505 if (__predict_false(ppi_dlen <
506 sizeof(struct rndis_hash_info)))
508 info->hash_info = ppi_dptr;
509 mask |= HV_RF_RECVINFO_HASHINF;
516 if (mask == HV_RF_RECVINFO_ALL) {
517 /* All found; done */
521 if (__predict_false(len < ppi->size))
524 ppi = (const rndis_per_packet_info *)
525 ((const uint8_t *)ppi + ppi->size);
531 * RNDIS filter receive data
534 hv_rf_receive_data(rndis_device *device, rndis_msg *message,
535 struct hv_vmbus_channel *chan, netvsc_packet *pkt)
537 rndis_packet *rndis_pkt;
538 uint32_t data_offset;
539 device_t dev = device->net_dev->sc->hn_dev;
540 struct hv_rf_recvinfo info;
542 rndis_pkt = &message->msg.packet;
545 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
546 * netvsc packet (ie tot_data_buf_len != message_length)
549 /* Remove rndis header, then pass data packet up the stack */
550 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
552 pkt->tot_data_buf_len -= data_offset;
553 if (pkt->tot_data_buf_len < rndis_pkt->data_length) {
554 pkt->status = nvsp_status_failure;
556 "total length %u is less than data length %u\n",
557 pkt->tot_data_buf_len, rndis_pkt->data_length);
561 pkt->tot_data_buf_len = rndis_pkt->data_length;
562 pkt->data = (void *)((unsigned long)pkt->data + data_offset);
564 if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
565 pkt->status = nvsp_status_failure;
566 device_printf(dev, "recvinfo parsing failed\n");
570 if (info.vlan_info != NULL)
571 pkt->vlan_tci = info.vlan_info->u1.s1.vlan_id;
575 netvsc_recv(chan, pkt, info.csum_info, info.hash_info, info.hash_value);
579 * RNDIS filter on receive
582 hv_rf_on_receive(netvsc_dev *net_dev,
583 struct hv_vmbus_channel *chan, netvsc_packet *pkt)
585 rndis_device *rndis_dev;
586 rndis_msg *rndis_hdr;
588 /* Make sure the rndis device state is initialized */
589 if (net_dev->extension == NULL) {
590 pkt->status = nvsp_status_failure;
594 rndis_dev = (rndis_device *)net_dev->extension;
595 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
596 pkt->status = nvsp_status_failure;
600 rndis_hdr = pkt->data;
602 switch (rndis_hdr->ndis_msg_type) {
605 case REMOTE_NDIS_PACKET_MSG:
606 hv_rf_receive_data(rndis_dev, rndis_hdr, chan, pkt);
608 /* completion messages */
609 case REMOTE_NDIS_INITIALIZE_CMPLT:
610 case REMOTE_NDIS_QUERY_CMPLT:
611 case REMOTE_NDIS_SET_CMPLT:
612 case REMOTE_NDIS_RESET_CMPLT:
613 case REMOTE_NDIS_KEEPALIVE_CMPLT:
614 hv_rf_receive_response(rndis_dev, rndis_hdr);
616 /* notification message */
617 case REMOTE_NDIS_INDICATE_STATUS_MSG:
618 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
621 printf("hv_rf_on_receive(): Unknown msg_type 0x%x\n",
622 rndis_hdr->ndis_msg_type);
630 * RNDIS filter query device
633 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
634 uint32_t *result_size)
636 rndis_request *request;
637 uint32_t in_result_size = *result_size;
638 rndis_query_request *query;
639 rndis_query_complete *query_complete;
643 request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
644 RNDIS_MESSAGE_SIZE(rndis_query_request));
645 if (request == NULL) {
650 /* Set up the rndis query */
651 query = &request->request_msg.msg.query_request;
653 query->info_buffer_offset = sizeof(rndis_query_request);
654 query->info_buffer_length = 0;
655 query->device_vc_handle = 0;
657 if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
658 struct rndis_recv_scale_cap *cap;
660 request->request_msg.msg_len +=
661 sizeof(struct rndis_recv_scale_cap);
662 query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
663 cap = (struct rndis_recv_scale_cap *)((unsigned long)query +
664 query->info_buffer_offset);
665 cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
666 cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
667 cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
670 ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
672 /* Fixme: printf added */
673 printf("RNDISFILTER request failed to Send!\n");
677 sema_wait(&request->wait_sema);
679 /* Copy the response back */
680 query_complete = &request->response_msg.msg.query_complete;
682 if (query_complete->info_buffer_length > in_result_size) {
687 memcpy(result, (void *)((unsigned long)query_complete +
688 query_complete->info_buffer_offset),
689 query_complete->info_buffer_length);
691 *result_size = query_complete->info_buffer_length;
695 hv_put_rndis_request(device, request);
701 * RNDIS filter query device MAC address
704 hv_rf_query_device_mac(rndis_device *device)
706 uint32_t size = HW_MACADDR_LEN;
708 return (hv_rf_query_device(device,
709 RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
713 * RNDIS filter query device link status
716 hv_rf_query_device_link_status(rndis_device *device)
718 uint32_t size = sizeof(uint32_t);
720 return (hv_rf_query_device(device,
721 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
724 static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
725 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
726 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
727 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
728 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
729 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
733 * RNDIS set vRSS parameters
736 hv_rf_set_rss_param(rndis_device *device, int num_queue)
738 rndis_request *request;
739 rndis_set_request *set;
740 rndis_set_complete *set_complete;
741 rndis_recv_scale_param *rssp;
742 uint32_t extlen = sizeof(rndis_recv_scale_param) +
743 (4 * ITAB_NUM) + HASH_KEYLEN;
744 uint32_t *itab, status;
749 request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
750 RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
751 if (request == NULL) {
753 printf("Netvsc: No memory to set vRSS parameters.\n");
758 set = &request->request_msg.msg.set_request;
759 set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
760 set->info_buffer_length = extlen;
761 set->info_buffer_offset = sizeof(rndis_set_request);
762 set->device_vc_handle = 0;
764 /* Fill out the rssp parameter structure */
765 rssp = (rndis_recv_scale_param *)(set + 1);
766 rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
767 rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
768 rssp->hdr.size = sizeof(rndis_recv_scale_param);
770 rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
771 RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
772 rssp->indirect_tabsize = 4 * ITAB_NUM;
773 rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
774 rssp->hashkey_size = HASH_KEYLEN;
775 rssp->hashkey_offset = rssp->indirect_taboffset +
776 rssp->indirect_tabsize;
778 /* Set indirection table entries */
779 itab = (uint32_t *)(rssp + 1);
780 for (i = 0; i < ITAB_NUM; i++)
781 itab[i] = i % num_queue;
783 /* Set hash key values */
784 keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
785 for (i = 0; i < HASH_KEYLEN; i++)
786 keyp[i] = netvsc_hash_key[i];
788 ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
794 * Wait for the response from the host. Another thread will signal
795 * us when the response has arrived. In the failure case,
796 * sema_timedwait() returns a non-zero status after waiting 5 seconds.
798 ret = sema_timedwait(&request->wait_sema, 5 * hz);
800 /* Response received, check status */
801 set_complete = &request->response_msg.msg.set_complete;
802 status = set_complete->status;
803 if (status != RNDIS_STATUS_SUCCESS) {
804 /* Bad response status, return error */
806 printf("Netvsc: Failed to set vRSS "
811 printf("Netvsc: Successfully set vRSS "
816 * We cannot deallocate the request since we may still
817 * receive a send completion for it.
819 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
820 request->request_msg.msg.init_request.request_id, ret);
825 if (request != NULL) {
826 hv_put_rndis_request(device, request);
833 * RNDIS filter set packet filter
834 * Sends an rndis request with the new filter, then waits for a response
836 * Returns zero on success, non-zero on failure.
839 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
841 rndis_request *request;
842 rndis_set_request *set;
843 rndis_set_complete *set_complete;
847 request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
848 RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
849 if (request == NULL) {
854 /* Set up the rndis set */
855 set = &request->request_msg.msg.set_request;
856 set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
857 set->info_buffer_length = sizeof(uint32_t);
858 set->info_buffer_offset = sizeof(rndis_set_request);
860 memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
861 &new_filter, sizeof(uint32_t));
863 ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
869 * Wait for the response from the host. Another thread will signal
870 * us when the response has arrived. In the failure case,
871 * sema_timedwait() returns a non-zero status after waiting 5 seconds.
873 ret = sema_timedwait(&request->wait_sema, 5 * hz);
875 /* Response received, check status */
876 set_complete = &request->response_msg.msg.set_complete;
877 status = set_complete->status;
878 if (status != RNDIS_STATUS_SUCCESS) {
879 /* Bad response status, return error */
884 * We cannot deallocate the request since we may still
885 * receive a send completion for it.
891 if (request != NULL) {
892 hv_put_rndis_request(device, request);
899 * RNDIS filter init device
902 hv_rf_init_device(rndis_device *device)
904 rndis_request *request;
905 rndis_initialize_request *init;
906 rndis_initialize_complete *init_complete;
910 request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
911 RNDIS_MESSAGE_SIZE(rndis_initialize_request));
917 /* Set up the rndis set */
918 init = &request->request_msg.msg.init_request;
919 init->major_version = RNDIS_MAJOR_VERSION;
920 init->minor_version = RNDIS_MINOR_VERSION;
922 * Per the RNDIS document, this should be set to the max MTU
923 * plus the header size. However, 2048 works fine, so leaving
926 init->max_xfer_size = 2048;
928 device->state = RNDIS_DEV_INITIALIZING;
930 ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
932 device->state = RNDIS_DEV_UNINITIALIZED;
936 sema_wait(&request->wait_sema);
938 init_complete = &request->response_msg.msg.init_complete;
939 status = init_complete->status;
940 if (status == RNDIS_STATUS_SUCCESS) {
941 device->state = RNDIS_DEV_INITIALIZED;
944 device->state = RNDIS_DEV_UNINITIALIZED;
950 hv_put_rndis_request(device, request);
956 #define HALT_COMPLETION_WAIT_COUNT 25
959 * RNDIS filter halt device
962 hv_rf_halt_device(rndis_device *device)
964 rndis_request *request;
965 rndis_halt_request *halt;
968 /* Attempt to do a rndis device halt */
969 request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
970 RNDIS_MESSAGE_SIZE(rndis_halt_request));
971 if (request == NULL) {
975 /* initialize "poor man's semaphore" */
976 request->halt_complete_flag = 0;
978 /* Set up the rndis set */
979 halt = &request->request_msg.msg.halt_request;
980 halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
981 /* Increment to get the new value (call above returns old value) */
982 halt->request_id += 1;
984 ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
990 * Wait for halt response from halt callback. We must wait for
991 * the transaction response before freeing the request and other
994 for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
995 if (request->halt_complete_flag != 0) {
1004 device->state = RNDIS_DEV_UNINITIALIZED;
1006 hv_put_rndis_request(device, request);
1012 * RNDIS filter open device
1015 hv_rf_open_device(rndis_device *device)
1019 if (device->state != RNDIS_DEV_INITIALIZED) {
1023 if (hv_promisc_mode != 1) {
1024 ret = hv_rf_set_packet_filter(device,
1025 NDIS_PACKET_TYPE_BROADCAST |
1026 NDIS_PACKET_TYPE_ALL_MULTICAST |
1027 NDIS_PACKET_TYPE_DIRECTED);
1029 ret = hv_rf_set_packet_filter(device,
1030 NDIS_PACKET_TYPE_PROMISCUOUS);
1034 device->state = RNDIS_DEV_DATAINITIALIZED;
1041 * RNDIS filter close device
1044 hv_rf_close_device(rndis_device *device)
1048 if (device->state != RNDIS_DEV_DATAINITIALIZED) {
1052 ret = hv_rf_set_packet_filter(device, 0);
1054 device->state = RNDIS_DEV_INITIALIZED;
1061 * RNDIS filter on device add
1064 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1068 netvsc_dev *net_dev;
1069 rndis_device *rndis_dev;
1071 rndis_offload_params offloads;
1072 struct rndis_recv_scale_cap rsscaps;
1073 uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
1074 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
1075 device_t dev = sc->hn_dev;
1077 rndis_dev = hv_get_rndis_device();
1078 if (rndis_dev == NULL) {
1083 * Let the inner driver handle this first to create the netvsc channel
1084 * NOTE! Once the channel is created, we may get a receive callback
1085 * (hv_rf_on_receive()) before this call is completed.
1086 * Note: Earlier code used a function pointer here.
1088 net_dev = hv_nv_on_device_add(sc, additl_info);
1090 hv_put_rndis_device(rndis_dev);
1096 * Initialize the rndis device
1099 net_dev->extension = rndis_dev;
1100 rndis_dev->net_dev = net_dev;
1102 /* Send the rndis initialization message */
1103 ret = hv_rf_init_device(rndis_dev);
1106 * TODO: If rndis init failed, we will need to shut down
1111 /* Get the mac address */
1112 ret = hv_rf_query_device_mac(rndis_dev);
1114 /* TODO: shut down rndis device and the channel */
1117 /* config csum offload and send request to host */
1118 memset(&offloads, 0, sizeof(offloads));
1119 offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1120 offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1121 offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1122 offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1123 offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1124 offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1126 ret = hv_rf_send_offload_request(sc, &offloads);
1128 /* TODO: shut down rndis device and the channel */
1130 "hv_rf_send_offload_request failed, ret=%d\n", ret);
1133 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
1135 hv_rf_query_device_link_status(rndis_dev);
1137 dev_info->link_state = rndis_dev->link_status;
1139 net_dev->num_channel = 1;
1140 if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1143 memset(&rsscaps, 0, rsscaps_size);
1144 ret = hv_rf_query_device(rndis_dev,
1145 RNDIS_OID_GEN_RSS_CAPABILITIES,
1146 &rsscaps, &rsscaps_size);
1147 if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
1148 device_printf(dev, "hv_rf_query_device failed or "
1149 "rsscaps.num_recv_que < 2 \n");
1152 device_printf(dev, "channel, offered %u, requested %d\n",
1153 rsscaps.num_recv_que, nchan);
1154 if (nchan > rsscaps.num_recv_que)
1155 nchan = rsscaps.num_recv_que;
1156 net_dev->num_channel = nchan;
1158 if (net_dev->num_channel == 1) {
1159 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1163 /* request host to create sub channels */
1164 init_pkt = &net_dev->channel_init_packet;
1165 memset(init_pkt, 0, sizeof(nvsp_msg));
1167 init_pkt->hdr.msg_type = nvsp_msg5_type_subchannel;
1168 init_pkt->msgs.vers_5_msgs.subchannel_request.op =
1169 NVSP_SUBCHANNE_ALLOCATE;
1170 init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
1171 net_dev->num_channel - 1;
1173 ret = hv_vmbus_channel_send_packet(sc->hn_prichan, init_pkt,
1174 sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
1175 HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
1176 HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1178 device_printf(dev, "Fail to allocate subchannel\n");
1182 sema_wait(&net_dev->channel_init_sema);
1184 if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
1185 nvsp_status_success) {
1187 device_printf(dev, "sub channel complete error\n");
1191 net_dev->num_channel = 1 +
1192 init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
1194 ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1198 net_dev->num_channel = 1;
1204 * RNDIS filter on device remove
1207 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1209 netvsc_dev *net_dev = sc->net_dev;
1210 rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1213 /* Halt and release the rndis device */
1214 ret = hv_rf_halt_device(rndis_dev);
1216 hv_put_rndis_device(rndis_dev);
1217 net_dev->extension = NULL;
1219 /* Pass control to inner driver to remove the device */
1220 ret |= hv_nv_on_device_remove(sc, destroy_channel);
1226 * RNDIS filter on open
1229 hv_rf_on_open(struct hn_softc *sc)
1231 netvsc_dev *net_dev = sc->net_dev;
1233 return (hv_rf_open_device((rndis_device *)net_dev->extension));
1237 * RNDIS filter on close
1240 hv_rf_on_close(struct hn_softc *sc)
1242 netvsc_dev *net_dev = sc->net_dev;
1244 return (hv_rf_close_device((rndis_device *)net_dev->extension));
1248 * RNDIS filter on send request completion callback
1251 hv_rf_on_send_request_completion(struct hv_vmbus_channel *chan __unused,
1252 void *context __unused)
1257 * RNDIS filter on send request (halt only) completion callback
1260 hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *chan __unused,
1263 rndis_request *request = context;
1266 * Notify hv_rf_halt_device() about halt completion.
1267 * The halt code must wait for completion before freeing
1268 * the transaction resources.
1270 request->halt_complete_flag = 1;
1274 hv_rf_channel_rollup(struct hv_vmbus_channel *chan)
1277 netvsc_channel_rollup(chan);