]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
MFV r297505:
[FreeBSD/FreeBSD.git] / sys / dev / hyperv / netvsc / hv_rndis_filter.c
1 /*-
2  * Copyright (c) 2009-2012 Microsoft Corp.
3  * Copyright (c) 2010-2012 Citrix Inc.
4  * Copyright (c) 2012 NetApp Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
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.
16  *
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.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/mbuf.h>
34 #include <sys/socket.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <net/if_arp.h>
38 #include <net/ethernet.h>
39 #include <sys/types.h>
40 #include <machine/atomic.h>
41 #include <sys/sema.h>
42 #include <vm/vm.h>
43 #include <vm/vm_param.h>
44 #include <vm/pmap.h>
45
46 #include <dev/hyperv/include/hyperv.h>
47 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
48 #include "hv_net_vsc.h"
49 #include "hv_rndis.h"
50 #include "hv_rndis_filter.h"
51
52
53 /*
54  * Forward declarations
55  */
56 static int  hv_rf_send_request(rndis_device *device, rndis_request *request,
57                                uint32_t message_type);
58 static void hv_rf_receive_response(rndis_device *device, rndis_msg *response);
59 static void hv_rf_receive_indicate_status(rndis_device *device,
60                                           rndis_msg *response);
61 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
62                                struct hv_vmbus_channel *chan,
63                                netvsc_packet *pkt);
64 static int  hv_rf_query_device(rndis_device *device, uint32_t oid,
65                                void *result, uint32_t *result_size);
66 static inline int hv_rf_query_device_mac(rndis_device *device);
67 static inline int hv_rf_query_device_link_status(rndis_device *device);
68 static int  hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
69 static int  hv_rf_init_device(rndis_device *device);
70 static int  hv_rf_open_device(rndis_device *device);
71 static int  hv_rf_close_device(rndis_device *device);
72 static void hv_rf_on_send_request_completion(struct hv_vmbus_channel *, void *context);
73 static void hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *, void *context);
74 int
75 hv_rf_send_offload_request(struct hv_device *device,
76     rndis_offload_params *offloads);
77 /*
78  * Set the Per-Packet-Info with the specified type
79  */
80 void *
81 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
82         int pkt_type)
83 {
84         rndis_packet *rndis_pkt;
85         rndis_per_packet_info *rppi;
86
87         rndis_pkt = &rndis_mesg->msg.packet;
88         rndis_pkt->data_offset += rppi_size;
89
90         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
91             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
92
93         rppi->size = rppi_size;
94         rppi->type = pkt_type;
95         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
96
97         rndis_pkt->per_pkt_info_length += rppi_size;
98
99         return (rppi);
100 }
101
102 /*
103  * Get the Per-Packet-Info with the specified type
104  * return NULL if not found.
105  */
106 void *
107 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
108 {
109         rndis_per_packet_info *ppi;
110         int len;
111
112         if (rpkt->per_pkt_info_offset == 0)
113                 return (NULL);
114
115         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
116             rpkt->per_pkt_info_offset);
117         len = rpkt->per_pkt_info_length;
118
119         while (len > 0) {
120                 if (ppi->type == type)
121                         return (void *)((unsigned long)ppi +
122                             ppi->per_packet_info_offset);
123
124                 len -= ppi->size;
125                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
126         }
127
128         return (NULL);
129 }
130
131
132 /*
133  * Allow module_param to work and override to switch to promiscuous mode.
134  */
135 static inline rndis_device *
136 hv_get_rndis_device(void)
137 {
138         rndis_device *device;
139
140         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
141
142         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
143
144         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
145         STAILQ_INIT(&device->myrequest_list);
146
147         device->state = RNDIS_DEV_UNINITIALIZED;
148
149         return (device);
150 }
151
152 /*
153  *
154  */
155 static inline void
156 hv_put_rndis_device(rndis_device *device)
157 {
158         mtx_destroy(&device->req_lock);
159         free(device, M_NETVSC);
160 }
161
162 /*
163  *
164  */
165 static inline rndis_request *
166 hv_rndis_request(rndis_device *device, uint32_t message_type,
167                  uint32_t message_length)
168 {
169         rndis_request *request;
170         rndis_msg *rndis_mesg;
171         rndis_set_request *set;
172
173         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
174
175         sema_init(&request->wait_sema, 0, "rndis sema");
176         
177         rndis_mesg = &request->request_msg;
178         rndis_mesg->ndis_msg_type = message_type;
179         rndis_mesg->msg_len = message_length;
180
181         /*
182          * Set the request id. This field is always after the rndis header
183          * for request/response packet types so we just use the set_request
184          * as a template.
185          */
186         set = &rndis_mesg->msg.set_request;
187         set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
188         /* Increment to get the new value (call above returns old value) */
189         set->request_id += 1;
190
191         /* Add to the request list */
192         mtx_lock(&device->req_lock);
193         STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
194         mtx_unlock(&device->req_lock);
195
196         return (request);
197 }
198
199 /*
200  *
201  */
202 static inline void
203 hv_put_rndis_request(rndis_device *device, rndis_request *request)
204 {
205         mtx_lock(&device->req_lock);
206         /* Fixme:  Has O(n) performance */
207         /*
208          * XXXKYS: Use Doubly linked lists.
209          */
210         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
211             mylist_entry);
212         mtx_unlock(&device->req_lock);
213
214         sema_destroy(&request->wait_sema);
215         free(request, M_NETVSC);
216 }
217
218 /*
219  *
220  */
221 static int
222 hv_rf_send_request(rndis_device *device, rndis_request *request,
223     uint32_t message_type)
224 {
225         int ret;
226         netvsc_packet *packet;
227         netvsc_dev      *net_dev = device->net_dev;
228         int send_buf_section_idx;
229
230         /* Set up the packet to send it */
231         packet = &request->pkt;
232         
233         packet->is_data_pkt = FALSE;
234         packet->tot_data_buf_len = request->request_msg.msg_len;
235         packet->page_buf_count = 1;
236
237         packet->page_buffers[0].pfn =
238             hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
239         packet->page_buffers[0].length = request->request_msg.msg_len;
240         packet->page_buffers[0].offset =
241             (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
242
243         if (packet->page_buffers[0].offset +
244                 packet->page_buffers[0].length > PAGE_SIZE) {
245                 packet->page_buf_count = 2;
246                 packet->page_buffers[0].length =
247                         PAGE_SIZE - packet->page_buffers[0].offset;
248                 packet->page_buffers[1].pfn =
249                         hv_get_phys_addr((char*)&request->request_msg +
250                                 packet->page_buffers[0].length) >> PAGE_SHIFT;
251                 packet->page_buffers[1].offset = 0;
252                 packet->page_buffers[1].length =
253                         request->request_msg.msg_len -
254                                 packet->page_buffers[0].length;
255         }
256
257         packet->compl.send.send_completion_context = request; /* packet */
258         if (message_type != REMOTE_NDIS_HALT_MSG) {
259                 packet->compl.send.on_send_completion =
260                     hv_rf_on_send_request_completion;
261         } else {
262                 packet->compl.send.on_send_completion =
263                     hv_rf_on_send_request_halt_completion;
264         }
265         packet->compl.send.send_completion_tid = (unsigned long)device;
266         if (packet->tot_data_buf_len < net_dev->send_section_size) {
267                 send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
268                 if (send_buf_section_idx !=
269                         NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
270                         char *dest = ((char *)net_dev->send_buf +
271                                 send_buf_section_idx * net_dev->send_section_size);
272
273                         memcpy(dest, &request->request_msg, request->request_msg.msg_len);
274                         packet->send_buf_section_idx = send_buf_section_idx;
275                         packet->send_buf_section_size = packet->tot_data_buf_len;
276                         packet->page_buf_count = 0;
277                         goto sendit;
278                 }
279                 /* Failed to allocate chimney send buffer; move on */
280         }
281         packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
282         packet->send_buf_section_size = 0;
283
284 sendit:
285         ret = hv_nv_on_send(device->net_dev->dev->channel, packet);
286
287         return (ret);
288 }
289
290 /*
291  * RNDIS filter receive response
292  */
293 static void 
294 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
295 {
296         rndis_request *request = NULL;
297         rndis_request *next_request;
298         boolean_t found = FALSE;
299
300         mtx_lock(&device->req_lock);
301         request = STAILQ_FIRST(&device->myrequest_list);
302         while (request != NULL) {
303                 /*
304                  * All request/response message contains request_id as the
305                  * first field
306                  */
307                 if (request->request_msg.msg.init_request.request_id ==
308                                       response->msg.init_complete.request_id) {
309                         found = TRUE;
310                         break;
311                 }
312                 next_request = STAILQ_NEXT(request, mylist_entry);
313                 request = next_request;
314         }
315         mtx_unlock(&device->req_lock);
316
317         if (found) {
318                 if (response->msg_len <= sizeof(rndis_msg)) {
319                         memcpy(&request->response_msg, response,
320                             response->msg_len);
321                 } else {
322                         if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
323                                 /* Does not have a request id field */
324                                 request->response_msg.msg.reset_complete.status =
325                                     STATUS_BUFFER_OVERFLOW;
326                         } else {
327                                 request->response_msg.msg.init_complete.status =
328                                     STATUS_BUFFER_OVERFLOW;
329                         }
330                 }
331
332                 sema_post(&request->wait_sema);
333         }
334 }
335
336 int
337 hv_rf_send_offload_request(struct hv_device *device,
338     rndis_offload_params *offloads)
339 {
340         rndis_request *request;
341         rndis_set_request *set;
342         rndis_offload_params *offload_req;
343         rndis_set_complete *set_complete;       
344         rndis_device *rndis_dev;
345         hn_softc_t *sc = device_get_softc(device->device);
346         device_t dev = device->device;
347         netvsc_dev *net_dev = sc->net_dev;
348         uint32_t vsp_version = net_dev->nvsp_version;
349         uint32_t extlen = sizeof(rndis_offload_params);
350         int ret;
351
352         if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
353                 extlen = VERSION_4_OFFLOAD_SIZE;
354                 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
355                  * UDP checksum offload.
356                  */
357                 offloads->udp_ipv4_csum = 0;
358                 offloads->udp_ipv6_csum = 0;
359         }
360
361         rndis_dev = net_dev->extension;
362
363         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
364             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
365         if (!request)
366                 return (ENOMEM);
367
368         set = &request->request_msg.msg.set_request;
369         set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
370         set->info_buffer_length = extlen;
371         set->info_buffer_offset = sizeof(rndis_set_request);
372         set->device_vc_handle = 0;
373
374         offload_req = (rndis_offload_params *)((unsigned long)set +
375             set->info_buffer_offset);
376         *offload_req = *offloads;
377         offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
378         offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
379         offload_req->header.size = extlen;
380
381         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
382         if (ret != 0) {
383                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
384                     ret);
385                 goto cleanup;
386         }
387
388         ret = sema_timedwait(&request->wait_sema, 5 * hz);
389         if (ret != 0) {
390                 device_printf(dev, "hv send offload request timeout\n");
391                 goto cleanup;
392         }
393
394         set_complete = &request->response_msg.msg.set_complete;
395         if (set_complete->status == RNDIS_STATUS_SUCCESS) {
396                 device_printf(dev, "hv send offload request succeeded\n");
397                 ret = 0;
398         } else {
399                 if (set_complete->status == STATUS_NOT_SUPPORTED) {
400                         device_printf(dev, "HV Not support offload\n");
401                         ret = 0;
402                 } else {
403                         ret = set_complete->status;
404                 }
405         }
406
407 cleanup:
408         if (request)
409                 hv_put_rndis_request(rndis_dev, request);
410
411         return (ret);
412 }
413
414 /*
415  * RNDIS filter receive indicate status
416  */
417 static void 
418 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
419 {
420         rndis_indicate_status *indicate = &response->msg.indicate_status;
421                 
422         switch(indicate->status) {
423         case RNDIS_STATUS_MEDIA_CONNECT:
424                 netvsc_linkstatus_callback(device->net_dev->dev, 1);
425                 break;
426         case RNDIS_STATUS_MEDIA_DISCONNECT:
427                 netvsc_linkstatus_callback(device->net_dev->dev, 0);
428                 break;
429         default:
430                 /* TODO: */
431                 device_printf(device->net_dev->dev->device,
432                     "unknown status %d received\n", indicate->status);
433                 break;
434         }
435 }
436
437 /*
438  * RNDIS filter receive data
439  */
440 static void
441 hv_rf_receive_data(rndis_device *device, rndis_msg *message,
442     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
443 {
444         rndis_packet *rndis_pkt;
445         ndis_8021q_info *rppi_vlan_info;
446         uint32_t data_offset;
447         rndis_tcp_ip_csum_info *csum_info = NULL;
448         device_t dev = device->net_dev->dev->device;
449
450         rndis_pkt = &message->msg.packet;
451
452         /*
453          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
454          * netvsc packet (ie tot_data_buf_len != message_length)
455          */
456
457         /* Remove rndis header, then pass data packet up the stack */
458         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
459
460         pkt->tot_data_buf_len -= data_offset;
461         if (pkt->tot_data_buf_len < rndis_pkt->data_length) {
462                 pkt->status = nvsp_status_failure;
463                 device_printf(dev,
464                     "total length %u is less than data length %u\n",
465                     pkt->tot_data_buf_len, rndis_pkt->data_length);
466                 return;
467         }
468
469         pkt->tot_data_buf_len = rndis_pkt->data_length;
470         pkt->data = (void *)((unsigned long)pkt->data + data_offset);
471
472         rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info);
473         if (rppi_vlan_info) {
474                 pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id;
475         } else {
476                 pkt->vlan_tci = 0;
477         }
478
479         csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info);
480         netvsc_recv(chan, pkt, csum_info);
481 }
482
483 /*
484  * RNDIS filter on receive
485  */
486 int
487 hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device,
488     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
489 {
490         rndis_device *rndis_dev;
491         rndis_msg *rndis_hdr;
492
493         /* Make sure the rndis device state is initialized */
494         if (net_dev->extension == NULL) {
495                 pkt->status = nvsp_status_failure;
496                 return (ENODEV);
497         }
498
499         rndis_dev = (rndis_device *)net_dev->extension;
500         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
501                 pkt->status = nvsp_status_failure;
502                 return (EINVAL);
503         }
504
505         rndis_hdr = pkt->data;
506
507         switch (rndis_hdr->ndis_msg_type) {
508
509         /* data message */
510         case REMOTE_NDIS_PACKET_MSG:
511                 hv_rf_receive_data(rndis_dev, rndis_hdr, chan, pkt);
512                 break;
513         /* completion messages */
514         case REMOTE_NDIS_INITIALIZE_CMPLT:
515         case REMOTE_NDIS_QUERY_CMPLT:
516         case REMOTE_NDIS_SET_CMPLT:
517         case REMOTE_NDIS_RESET_CMPLT:
518         case REMOTE_NDIS_KEEPALIVE_CMPLT:
519                 hv_rf_receive_response(rndis_dev, rndis_hdr);
520                 break;
521         /* notification message */
522         case REMOTE_NDIS_INDICATE_STATUS_MSG:
523                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
524                 break;
525         default:
526                 printf("hv_rf_on_receive():  Unknown msg_type 0x%x\n",
527                         rndis_hdr->ndis_msg_type);
528                 break;
529         }
530
531         return (0);
532 }
533
534 /*
535  * RNDIS filter query device
536  */
537 static int
538 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
539                    uint32_t *result_size)
540 {
541         rndis_request *request;
542         uint32_t in_result_size = *result_size;
543         rndis_query_request *query;
544         rndis_query_complete *query_complete;
545         int ret = 0;
546
547         *result_size = 0;
548         request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
549             RNDIS_MESSAGE_SIZE(rndis_query_request));
550         if (request == NULL) {
551                 ret = -1;
552                 goto cleanup;
553         }
554
555         /* Set up the rndis query */
556         query = &request->request_msg.msg.query_request;
557         query->oid = oid;
558         query->info_buffer_offset = sizeof(rndis_query_request); 
559         query->info_buffer_length = 0;
560         query->device_vc_handle = 0;
561
562         if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
563                 struct rndis_recv_scale_cap *cap;
564
565                 request->request_msg.msg_len += 
566                         sizeof(struct rndis_recv_scale_cap);
567                 query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
568                 cap = (struct rndis_recv_scale_cap *)((unsigned long)query + 
569                                                 query->info_buffer_offset);
570                 cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
571                 cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
572                 cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
573         }
574
575         ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
576         if (ret != 0) {
577                 /* Fixme:  printf added */
578                 printf("RNDISFILTER request failed to Send!\n");
579                 goto cleanup;
580         }
581
582         sema_wait(&request->wait_sema);
583
584         /* Copy the response back */
585         query_complete = &request->response_msg.msg.query_complete;
586         
587         if (query_complete->info_buffer_length > in_result_size) {
588                 ret = EINVAL;
589                 goto cleanup;
590         }
591
592         memcpy(result, (void *)((unsigned long)query_complete +
593             query_complete->info_buffer_offset),
594             query_complete->info_buffer_length);
595
596         *result_size = query_complete->info_buffer_length;
597
598 cleanup:
599         if (request != NULL)
600                 hv_put_rndis_request(device, request);
601
602         return (ret);
603 }
604
605 /*
606  * RNDIS filter query device MAC address
607  */
608 static inline int
609 hv_rf_query_device_mac(rndis_device *device)
610 {
611         uint32_t size = HW_MACADDR_LEN;
612
613         return (hv_rf_query_device(device,
614             RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
615 }
616
617 /*
618  * RNDIS filter query device link status
619  */
620 static inline int
621 hv_rf_query_device_link_status(rndis_device *device)
622 {
623         uint32_t size = sizeof(uint32_t);
624
625         return (hv_rf_query_device(device,
626             RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
627 }
628
629 static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
630         0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
631         0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
632         0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
633         0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
634         0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
635 };
636
637 /*
638  * RNDIS set vRSS parameters
639  */
640 static int
641 hv_rf_set_rss_param(rndis_device *device, int num_queue)
642 {
643         rndis_request *request;
644         rndis_set_request *set;
645         rndis_set_complete *set_complete;
646         rndis_recv_scale_param *rssp;
647         uint32_t extlen = sizeof(rndis_recv_scale_param) +
648             (4 * ITAB_NUM) + HASH_KEYLEN;
649         uint32_t *itab, status;
650         uint8_t *keyp;
651         int i, ret;
652
653
654         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
655             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
656         if (request == NULL) {
657                 if (bootverbose)
658                         printf("Netvsc: No memory to set vRSS parameters.\n");
659                 ret = -1;
660                 goto cleanup;
661         }
662
663         set = &request->request_msg.msg.set_request;
664         set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
665         set->info_buffer_length = extlen;
666         set->info_buffer_offset = sizeof(rndis_set_request);
667         set->device_vc_handle = 0;
668
669         /* Fill out the rssp parameter structure */
670         rssp = (rndis_recv_scale_param *)(set + 1);
671         rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
672         rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
673         rssp->hdr.size = sizeof(rndis_recv_scale_param);
674         rssp->flag = 0;
675         rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
676             RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
677         rssp->indirect_tabsize = 4 * ITAB_NUM;
678         rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
679         rssp->hashkey_size = HASH_KEYLEN;
680         rssp->hashkey_offset = rssp->indirect_taboffset +
681             rssp->indirect_tabsize;
682
683         /* Set indirection table entries */
684         itab = (uint32_t *)(rssp + 1);
685         for (i = 0; i < ITAB_NUM; i++)
686                 itab[i] = i % num_queue;
687
688         /* Set hash key values */
689         keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
690         for (i = 0; i < HASH_KEYLEN; i++)
691                 keyp[i] = netvsc_hash_key[i];
692
693         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
694         if (ret != 0) {
695                 goto cleanup;
696         }
697
698         /*
699          * Wait for the response from the host.  Another thread will signal
700          * us when the response has arrived.  In the failure case,
701          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
702          */
703         ret = sema_timedwait(&request->wait_sema, 5 * hz);
704         if (ret == 0) {
705                 /* Response received, check status */
706                 set_complete = &request->response_msg.msg.set_complete;
707                 status = set_complete->status;
708                 if (status != RNDIS_STATUS_SUCCESS) {
709                         /* Bad response status, return error */
710                         if (bootverbose)
711                                 printf("Netvsc: Failed to set vRSS "
712                                     "parameters.\n");
713                         ret = -2;
714                 } else {
715                         if (bootverbose)
716                                 printf("Netvsc: Successfully set vRSS "
717                                     "parameters.\n");
718                 }
719         } else {
720                 /*
721                  * We cannot deallocate the request since we may still
722                  * receive a send completion for it.
723                  */
724                 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
725                     request->request_msg.msg.init_request.request_id, ret);
726                 goto exit;
727         }
728
729 cleanup:
730         if (request != NULL) {
731                 hv_put_rndis_request(device, request);
732         }
733 exit:
734         return (ret);
735 }
736
737 /*
738  * RNDIS filter set packet filter
739  * Sends an rndis request with the new filter, then waits for a response
740  * from the host.
741  * Returns zero on success, non-zero on failure.
742  */
743 static int
744 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
745 {
746         rndis_request *request;
747         rndis_set_request *set;
748         rndis_set_complete *set_complete;
749         uint32_t status;
750         int ret;
751
752         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
753             RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
754         if (request == NULL) {
755                 ret = -1;
756                 goto cleanup;
757         }
758
759         /* Set up the rndis set */
760         set = &request->request_msg.msg.set_request;
761         set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
762         set->info_buffer_length = sizeof(uint32_t);
763         set->info_buffer_offset = sizeof(rndis_set_request); 
764
765         memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
766             &new_filter, sizeof(uint32_t));
767
768         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
769         if (ret != 0) {
770                 goto cleanup;
771         }
772
773         /*
774          * Wait for the response from the host.  Another thread will signal
775          * us when the response has arrived.  In the failure case,
776          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
777          */
778         ret = sema_timedwait(&request->wait_sema, 5 * hz);
779         if (ret == 0) {
780                 /* Response received, check status */
781                 set_complete = &request->response_msg.msg.set_complete;
782                 status = set_complete->status;
783                 if (status != RNDIS_STATUS_SUCCESS) {
784                         /* Bad response status, return error */
785                         ret = -2;
786                 }
787         } else {
788                 /*
789                  * We cannot deallocate the request since we may still
790                  * receive a send completion for it.
791                  */
792                 goto exit;
793         }
794
795 cleanup:
796         if (request != NULL) {
797                 hv_put_rndis_request(device, request);
798         }
799 exit:
800         return (ret);
801 }
802
803 /*
804  * RNDIS filter init device
805  */
806 static int
807 hv_rf_init_device(rndis_device *device)
808 {
809         rndis_request *request;
810         rndis_initialize_request *init;
811         rndis_initialize_complete *init_complete;
812         uint32_t status;
813         int ret;
814
815         request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
816             RNDIS_MESSAGE_SIZE(rndis_initialize_request));
817         if (!request) {
818                 ret = -1;
819                 goto cleanup;
820         }
821
822         /* Set up the rndis set */
823         init = &request->request_msg.msg.init_request;
824         init->major_version = RNDIS_MAJOR_VERSION;
825         init->minor_version = RNDIS_MINOR_VERSION;
826         /*
827          * Per the RNDIS document, this should be set to the max MTU
828          * plus the header size.  However, 2048 works fine, so leaving
829          * it as is.
830          */
831         init->max_xfer_size = 2048;
832         
833         device->state = RNDIS_DEV_INITIALIZING;
834
835         ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
836         if (ret != 0) {
837                 device->state = RNDIS_DEV_UNINITIALIZED;
838                 goto cleanup;
839         }
840
841         sema_wait(&request->wait_sema);
842
843         init_complete = &request->response_msg.msg.init_complete;
844         status = init_complete->status;
845         if (status == RNDIS_STATUS_SUCCESS) {
846                 device->state = RNDIS_DEV_INITIALIZED;
847                 ret = 0;
848         } else {
849                 device->state = RNDIS_DEV_UNINITIALIZED; 
850                 ret = -1;
851         }
852
853 cleanup:
854         if (request) {
855                 hv_put_rndis_request(device, request);
856         }
857
858         return (ret);
859 }
860
861 #define HALT_COMPLETION_WAIT_COUNT      25
862
863 /*
864  * RNDIS filter halt device
865  */
866 static int
867 hv_rf_halt_device(rndis_device *device)
868 {
869         rndis_request *request;
870         rndis_halt_request *halt;
871         int i, ret;
872
873         /* Attempt to do a rndis device halt */
874         request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
875             RNDIS_MESSAGE_SIZE(rndis_halt_request));
876         if (request == NULL) {
877                 return (-1);
878         }
879
880         /* initialize "poor man's semaphore" */
881         request->halt_complete_flag = 0;
882
883         /* Set up the rndis set */
884         halt = &request->request_msg.msg.halt_request;
885         halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
886         /* Increment to get the new value (call above returns old value) */
887         halt->request_id += 1;
888         
889         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
890         if (ret != 0) {
891                 return (-1);
892         }
893
894         /*
895          * Wait for halt response from halt callback.  We must wait for
896          * the transaction response before freeing the request and other
897          * resources.
898          */
899         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
900                 if (request->halt_complete_flag != 0) {
901                         break;
902                 }
903                 DELAY(400);
904         }
905         if (i == 0) {
906                 return (-1);
907         }
908
909         device->state = RNDIS_DEV_UNINITIALIZED;
910         
911         if (request != NULL) {
912                 hv_put_rndis_request(device, request);
913         }
914
915         return (0);
916 }
917
918 /*
919  * RNDIS filter open device
920  */
921 static int
922 hv_rf_open_device(rndis_device *device)
923 {
924         int ret;
925
926         if (device->state != RNDIS_DEV_INITIALIZED) {
927                 return (0);
928         }
929
930         if (hv_promisc_mode != 1) {
931                 ret = hv_rf_set_packet_filter(device, 
932                     NDIS_PACKET_TYPE_BROADCAST     |
933                     NDIS_PACKET_TYPE_ALL_MULTICAST |
934                     NDIS_PACKET_TYPE_DIRECTED);
935         } else {
936                 ret = hv_rf_set_packet_filter(device, 
937                     NDIS_PACKET_TYPE_PROMISCUOUS);
938         }
939
940         if (ret == 0) {
941                 device->state = RNDIS_DEV_DATAINITIALIZED;
942         }
943
944         return (ret);
945 }
946
947 /*
948  * RNDIS filter close device
949  */
950 static int
951 hv_rf_close_device(rndis_device *device)
952 {
953         int ret;
954
955         if (device->state != RNDIS_DEV_DATAINITIALIZED) {
956                 return (0);
957         }
958
959         ret = hv_rf_set_packet_filter(device, 0);
960         if (ret == 0) {
961                 device->state = RNDIS_DEV_INITIALIZED;
962         }
963
964         return (ret);
965 }
966
967 /*
968  * RNDIS filter on device add
969  */
970 int
971 hv_rf_on_device_add(struct hv_device *device, void *additl_info,
972     int nchan)
973 {
974         int ret;
975         netvsc_dev *net_dev;
976         rndis_device *rndis_dev;
977         nvsp_msg *init_pkt;
978         rndis_offload_params offloads;
979         struct rndis_recv_scale_cap rsscaps;
980         uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
981         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
982         device_t dev = device->device;
983
984         rndis_dev = hv_get_rndis_device();
985         if (rndis_dev == NULL) {
986                 return (ENOMEM);
987         }
988
989         /*
990          * Let the inner driver handle this first to create the netvsc channel
991          * NOTE! Once the channel is created, we may get a receive callback 
992          * (hv_rf_on_receive()) before this call is completed.
993          * Note:  Earlier code used a function pointer here.
994          */
995         net_dev = hv_nv_on_device_add(device, additl_info);
996         if (!net_dev) {
997                 hv_put_rndis_device(rndis_dev);
998
999                 return (ENOMEM);
1000         }
1001
1002         /*
1003          * Initialize the rndis device
1004          */
1005
1006         net_dev->extension = rndis_dev;
1007         rndis_dev->net_dev = net_dev;
1008
1009         /* Send the rndis initialization message */
1010         ret = hv_rf_init_device(rndis_dev);
1011         if (ret != 0) {
1012                 /*
1013                  * TODO: If rndis init failed, we will need to shut down
1014                  * the channel
1015                  */
1016         }
1017
1018         /* Get the mac address */
1019         ret = hv_rf_query_device_mac(rndis_dev);
1020         if (ret != 0) {
1021                 /* TODO: shut down rndis device and the channel */
1022         }
1023
1024         /* config csum offload and send request to host */
1025         memset(&offloads, 0, sizeof(offloads));
1026         offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1027         offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1028         offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1029         offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1030         offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1031         offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1032
1033         ret = hv_rf_send_offload_request(device, &offloads);
1034         if (ret != 0) {
1035                 /* TODO: shut down rndis device and the channel */
1036                 device_printf(dev,
1037                     "hv_rf_send_offload_request failed, ret=%d\n", ret);
1038         }
1039         
1040         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
1041
1042         hv_rf_query_device_link_status(rndis_dev);
1043         
1044         dev_info->link_state = rndis_dev->link_status;
1045
1046         net_dev->num_channel = 1;
1047         if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1048                 return (0);
1049
1050         memset(&rsscaps, 0, rsscaps_size);
1051         ret = hv_rf_query_device(rndis_dev,
1052                         RNDIS_OID_GEN_RSS_CAPABILITIES,
1053                         &rsscaps, &rsscaps_size);
1054         if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
1055                 device_printf(dev, "hv_rf_query_device failed or "
1056                         "rsscaps.num_recv_que < 2 \n");
1057                 goto out;
1058         }
1059         device_printf(dev, "channel, offered %u, requested %d\n",
1060             rsscaps.num_recv_que, nchan);
1061         if (nchan > rsscaps.num_recv_que)
1062                 nchan = rsscaps.num_recv_que;
1063         net_dev->num_channel = nchan;
1064
1065         if (net_dev->num_channel == 1) {
1066                 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1067                 goto out;
1068         }
1069         
1070         /* request host to create sub channels */
1071         init_pkt = &net_dev->channel_init_packet;
1072         memset(init_pkt, 0, sizeof(nvsp_msg));
1073
1074         init_pkt->hdr.msg_type = nvsp_msg5_type_subchannel;
1075         init_pkt->msgs.vers_5_msgs.subchannel_request.op =
1076             NVSP_SUBCHANNE_ALLOCATE;
1077         init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
1078             net_dev->num_channel - 1;
1079
1080         ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
1081             sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
1082             HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
1083             HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1084         if (ret != 0) {
1085                 device_printf(dev, "Fail to allocate subchannel\n");
1086                 goto out;
1087         }
1088
1089         sema_wait(&net_dev->channel_init_sema);
1090
1091         if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
1092             nvsp_status_success) {
1093                 ret = ENODEV;
1094                 device_printf(dev, "sub channel complete error\n");
1095                 goto out;
1096         }
1097
1098         net_dev->num_channel = 1 +
1099             init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
1100
1101         ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1102
1103 out:
1104         if (ret)
1105                 net_dev->num_channel = 1;
1106
1107         return (ret);
1108 }
1109
1110 /*
1111  * RNDIS filter on device remove
1112  */
1113 int
1114 hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
1115 {
1116         hn_softc_t *sc = device_get_softc(device->device);
1117         netvsc_dev *net_dev = sc->net_dev;
1118         rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1119         int ret;
1120
1121         /* Halt and release the rndis device */
1122         ret = hv_rf_halt_device(rndis_dev);
1123
1124         hv_put_rndis_device(rndis_dev);
1125         net_dev->extension = NULL;
1126
1127         /* Pass control to inner driver to remove the device */
1128         ret |= hv_nv_on_device_remove(device, destroy_channel);
1129
1130         return (ret);
1131 }
1132
1133 /*
1134  * RNDIS filter on open
1135  */
1136 int
1137 hv_rf_on_open(struct hv_device *device)
1138 {
1139         hn_softc_t *sc = device_get_softc(device->device);      
1140         netvsc_dev *net_dev = sc->net_dev;
1141
1142         return (hv_rf_open_device((rndis_device *)net_dev->extension));
1143 }
1144
1145 /*
1146  * RNDIS filter on close
1147  */
1148 int 
1149 hv_rf_on_close(struct hv_device *device)
1150 {
1151         hn_softc_t *sc = device_get_softc(device->device);      
1152         netvsc_dev *net_dev = sc->net_dev;
1153
1154         return (hv_rf_close_device((rndis_device *)net_dev->extension));
1155 }
1156
1157 /*
1158  * RNDIS filter on send request completion callback
1159  */
1160 static void 
1161 hv_rf_on_send_request_completion(struct hv_vmbus_channel *chan __unused,
1162     void *context __unused)
1163 {
1164 }
1165
1166 /*
1167  * RNDIS filter on send request (halt only) completion callback
1168  */
1169 static void 
1170 hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *chan __unused,
1171     void *context)
1172 {
1173         rndis_request *request = context;
1174
1175         /*
1176          * Notify hv_rf_halt_device() about halt completion.
1177          * The halt code must wait for completion before freeing
1178          * the transaction resources.
1179          */
1180         request->halt_complete_flag = 1;
1181 }
1182
1183 void
1184 hv_rf_channel_rollup(struct hv_vmbus_channel *chan)
1185 {
1186
1187         netvsc_channel_rollup(chan);
1188 }