]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
MFC 297809,297810,297811
[FreeBSD/stable/10.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/kernel.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36 #include <sys/lock.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>
42 #include <sys/sema.h>
43 #include <vm/vm.h>
44 #include <vm/vm_param.h>
45 #include <vm/pmap.h>
46
47 #include <dev/hyperv/include/hyperv.h>
48 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
49 #include "hv_net_vsc.h"
50 #include "hv_rndis.h"
51 #include "hv_rndis_filter.h"
52
53
54 /*
55  * Forward declarations
56  */
57 static int  hv_rf_send_request(rndis_device *device, rndis_request *request,
58                                uint32_t message_type);
59 static void hv_rf_receive_response(rndis_device *device, rndis_msg *response);
60 static void hv_rf_receive_indicate_status(rndis_device *device,
61                                           rndis_msg *response);
62 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
63                                struct hv_vmbus_channel *chan,
64                                netvsc_packet *pkt);
65 static int  hv_rf_query_device(rndis_device *device, uint32_t oid,
66                                void *result, uint32_t *result_size);
67 static inline int hv_rf_query_device_mac(rndis_device *device);
68 static inline int hv_rf_query_device_link_status(rndis_device *device);
69 static int  hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
70 static int  hv_rf_init_device(rndis_device *device);
71 static int  hv_rf_open_device(rndis_device *device);
72 static int  hv_rf_close_device(rndis_device *device);
73 static void hv_rf_on_send_request_completion(struct hv_vmbus_channel *, void *context);
74 static void hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *, void *context);
75 int
76 hv_rf_send_offload_request(struct hv_device *device,
77     rndis_offload_params *offloads);
78 /*
79  * Set the Per-Packet-Info with the specified type
80  */
81 void *
82 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
83         int pkt_type)
84 {
85         rndis_packet *rndis_pkt;
86         rndis_per_packet_info *rppi;
87
88         rndis_pkt = &rndis_mesg->msg.packet;
89         rndis_pkt->data_offset += rppi_size;
90
91         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
92             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
93
94         rppi->size = rppi_size;
95         rppi->type = pkt_type;
96         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
97
98         rndis_pkt->per_pkt_info_length += rppi_size;
99
100         return (rppi);
101 }
102
103 /*
104  * Get the Per-Packet-Info with the specified type
105  * return NULL if not found.
106  */
107 void *
108 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
109 {
110         rndis_per_packet_info *ppi;
111         int len;
112
113         if (rpkt->per_pkt_info_offset == 0)
114                 return (NULL);
115
116         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
117             rpkt->per_pkt_info_offset);
118         len = rpkt->per_pkt_info_length;
119
120         while (len > 0) {
121                 if (ppi->type == type)
122                         return (void *)((unsigned long)ppi +
123                             ppi->per_packet_info_offset);
124
125                 len -= ppi->size;
126                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
127         }
128
129         return (NULL);
130 }
131
132
133 /*
134  * Allow module_param to work and override to switch to promiscuous mode.
135  */
136 static inline rndis_device *
137 hv_get_rndis_device(void)
138 {
139         rndis_device *device;
140
141         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
142
143         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
144
145         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
146         STAILQ_INIT(&device->myrequest_list);
147
148         device->state = RNDIS_DEV_UNINITIALIZED;
149
150         return (device);
151 }
152
153 /*
154  *
155  */
156 static inline void
157 hv_put_rndis_device(rndis_device *device)
158 {
159         mtx_destroy(&device->req_lock);
160         free(device, M_NETVSC);
161 }
162
163 /*
164  *
165  */
166 static inline rndis_request *
167 hv_rndis_request(rndis_device *device, uint32_t message_type,
168                  uint32_t message_length)
169 {
170         rndis_request *request;
171         rndis_msg *rndis_mesg;
172         rndis_set_request *set;
173
174         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
175
176         sema_init(&request->wait_sema, 0, "rndis sema");
177         
178         rndis_mesg = &request->request_msg;
179         rndis_mesg->ndis_msg_type = message_type;
180         rndis_mesg->msg_len = message_length;
181
182         /*
183          * Set the request id. This field is always after the rndis header
184          * for request/response packet types so we just use the set_request
185          * as a template.
186          */
187         set = &rndis_mesg->msg.set_request;
188         set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
189         /* Increment to get the new value (call above returns old value) */
190         set->request_id += 1;
191
192         /* Add to the request list */
193         mtx_lock(&device->req_lock);
194         STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
195         mtx_unlock(&device->req_lock);
196
197         return (request);
198 }
199
200 /*
201  *
202  */
203 static inline void
204 hv_put_rndis_request(rndis_device *device, rndis_request *request)
205 {
206         mtx_lock(&device->req_lock);
207         /* Fixme:  Has O(n) performance */
208         /*
209          * XXXKYS: Use Doubly linked lists.
210          */
211         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
212             mylist_entry);
213         mtx_unlock(&device->req_lock);
214
215         sema_destroy(&request->wait_sema);
216         free(request, M_NETVSC);
217 }
218
219 /*
220  *
221  */
222 static int
223 hv_rf_send_request(rndis_device *device, rndis_request *request,
224     uint32_t message_type)
225 {
226         int ret;
227         netvsc_packet *packet;
228         netvsc_dev      *net_dev = device->net_dev;
229         int send_buf_section_idx;
230
231         /* Set up the packet to send it */
232         packet = &request->pkt;
233         
234         packet->is_data_pkt = FALSE;
235         packet->tot_data_buf_len = request->request_msg.msg_len;
236         packet->page_buf_count = 1;
237
238         packet->page_buffers[0].pfn =
239             hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
240         packet->page_buffers[0].length = request->request_msg.msg_len;
241         packet->page_buffers[0].offset =
242             (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
243
244         if (packet->page_buffers[0].offset +
245                 packet->page_buffers[0].length > PAGE_SIZE) {
246                 packet->page_buf_count = 2;
247                 packet->page_buffers[0].length =
248                         PAGE_SIZE - packet->page_buffers[0].offset;
249                 packet->page_buffers[1].pfn =
250                         hv_get_phys_addr((char*)&request->request_msg +
251                                 packet->page_buffers[0].length) >> PAGE_SHIFT;
252                 packet->page_buffers[1].offset = 0;
253                 packet->page_buffers[1].length =
254                         request->request_msg.msg_len -
255                                 packet->page_buffers[0].length;
256         }
257
258         packet->compl.send.send_completion_context = request; /* packet */
259         if (message_type != REMOTE_NDIS_HALT_MSG) {
260                 packet->compl.send.on_send_completion =
261                     hv_rf_on_send_request_completion;
262         } else {
263                 packet->compl.send.on_send_completion =
264                     hv_rf_on_send_request_halt_completion;
265         }
266         packet->compl.send.send_completion_tid = (unsigned long)device;
267         if (packet->tot_data_buf_len < net_dev->send_section_size) {
268                 send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
269                 if (send_buf_section_idx !=
270                         NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
271                         char *dest = ((char *)net_dev->send_buf +
272                                 send_buf_section_idx * net_dev->send_section_size);
273
274                         memcpy(dest, &request->request_msg, request->request_msg.msg_len);
275                         packet->send_buf_section_idx = send_buf_section_idx;
276                         packet->send_buf_section_size = packet->tot_data_buf_len;
277                         packet->page_buf_count = 0;
278                         goto sendit;
279                 }
280                 /* Failed to allocate chimney send buffer; move on */
281         }
282         packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
283         packet->send_buf_section_size = 0;
284
285 sendit:
286         ret = hv_nv_on_send(device->net_dev->dev->channel, packet);
287
288         return (ret);
289 }
290
291 /*
292  * RNDIS filter receive response
293  */
294 static void 
295 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
296 {
297         rndis_request *request = NULL;
298         rndis_request *next_request;
299         boolean_t found = FALSE;
300
301         mtx_lock(&device->req_lock);
302         request = STAILQ_FIRST(&device->myrequest_list);
303         while (request != NULL) {
304                 /*
305                  * All request/response message contains request_id as the
306                  * first field
307                  */
308                 if (request->request_msg.msg.init_request.request_id ==
309                                       response->msg.init_complete.request_id) {
310                         found = TRUE;
311                         break;
312                 }
313                 next_request = STAILQ_NEXT(request, mylist_entry);
314                 request = next_request;
315         }
316         mtx_unlock(&device->req_lock);
317
318         if (found) {
319                 if (response->msg_len <= sizeof(rndis_msg)) {
320                         memcpy(&request->response_msg, response,
321                             response->msg_len);
322                 } else {
323                         if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
324                                 /* Does not have a request id field */
325                                 request->response_msg.msg.reset_complete.status =
326                                     STATUS_BUFFER_OVERFLOW;
327                         } else {
328                                 request->response_msg.msg.init_complete.status =
329                                     STATUS_BUFFER_OVERFLOW;
330                         }
331                 }
332
333                 sema_post(&request->wait_sema);
334         }
335 }
336
337 int
338 hv_rf_send_offload_request(struct hv_device *device,
339     rndis_offload_params *offloads)
340 {
341         rndis_request *request;
342         rndis_set_request *set;
343         rndis_offload_params *offload_req;
344         rndis_set_complete *set_complete;       
345         rndis_device *rndis_dev;
346         hn_softc_t *sc = device_get_softc(device->device);
347         device_t dev = device->device;
348         netvsc_dev *net_dev = sc->net_dev;
349         uint32_t vsp_version = net_dev->nvsp_version;
350         uint32_t extlen = sizeof(rndis_offload_params);
351         int ret;
352
353         if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
354                 extlen = VERSION_4_OFFLOAD_SIZE;
355                 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
356                  * UDP checksum offload.
357                  */
358                 offloads->udp_ipv4_csum = 0;
359                 offloads->udp_ipv6_csum = 0;
360         }
361
362         rndis_dev = net_dev->extension;
363
364         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
365             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
366         if (!request)
367                 return (ENOMEM);
368
369         set = &request->request_msg.msg.set_request;
370         set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
371         set->info_buffer_length = extlen;
372         set->info_buffer_offset = sizeof(rndis_set_request);
373         set->device_vc_handle = 0;
374
375         offload_req = (rndis_offload_params *)((unsigned long)set +
376             set->info_buffer_offset);
377         *offload_req = *offloads;
378         offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
379         offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
380         offload_req->header.size = extlen;
381
382         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
383         if (ret != 0) {
384                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
385                     ret);
386                 goto cleanup;
387         }
388
389         ret = sema_timedwait(&request->wait_sema, 5 * hz);
390         if (ret != 0) {
391                 device_printf(dev, "hv send offload request timeout\n");
392                 goto cleanup;
393         }
394
395         set_complete = &request->response_msg.msg.set_complete;
396         if (set_complete->status == RNDIS_STATUS_SUCCESS) {
397                 device_printf(dev, "hv send offload request succeeded\n");
398                 ret = 0;
399         } else {
400                 if (set_complete->status == STATUS_NOT_SUPPORTED) {
401                         device_printf(dev, "HV Not support offload\n");
402                         ret = 0;
403                 } else {
404                         ret = set_complete->status;
405                 }
406         }
407
408 cleanup:
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         hv_put_rndis_request(device, request);
912
913         return (0);
914 }
915
916 /*
917  * RNDIS filter open device
918  */
919 static int
920 hv_rf_open_device(rndis_device *device)
921 {
922         int ret;
923
924         if (device->state != RNDIS_DEV_INITIALIZED) {
925                 return (0);
926         }
927
928         if (hv_promisc_mode != 1) {
929                 ret = hv_rf_set_packet_filter(device, 
930                     NDIS_PACKET_TYPE_BROADCAST     |
931                     NDIS_PACKET_TYPE_ALL_MULTICAST |
932                     NDIS_PACKET_TYPE_DIRECTED);
933         } else {
934                 ret = hv_rf_set_packet_filter(device, 
935                     NDIS_PACKET_TYPE_PROMISCUOUS);
936         }
937
938         if (ret == 0) {
939                 device->state = RNDIS_DEV_DATAINITIALIZED;
940         }
941
942         return (ret);
943 }
944
945 /*
946  * RNDIS filter close device
947  */
948 static int
949 hv_rf_close_device(rndis_device *device)
950 {
951         int ret;
952
953         if (device->state != RNDIS_DEV_DATAINITIALIZED) {
954                 return (0);
955         }
956
957         ret = hv_rf_set_packet_filter(device, 0);
958         if (ret == 0) {
959                 device->state = RNDIS_DEV_INITIALIZED;
960         }
961
962         return (ret);
963 }
964
965 /*
966  * RNDIS filter on device add
967  */
968 int
969 hv_rf_on_device_add(struct hv_device *device, void *additl_info,
970     int nchan)
971 {
972         int ret;
973         netvsc_dev *net_dev;
974         rndis_device *rndis_dev;
975         nvsp_msg *init_pkt;
976         rndis_offload_params offloads;
977         struct rndis_recv_scale_cap rsscaps;
978         uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
979         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
980         device_t dev = device->device;
981
982         rndis_dev = hv_get_rndis_device();
983         if (rndis_dev == NULL) {
984                 return (ENOMEM);
985         }
986
987         /*
988          * Let the inner driver handle this first to create the netvsc channel
989          * NOTE! Once the channel is created, we may get a receive callback 
990          * (hv_rf_on_receive()) before this call is completed.
991          * Note:  Earlier code used a function pointer here.
992          */
993         net_dev = hv_nv_on_device_add(device, additl_info);
994         if (!net_dev) {
995                 hv_put_rndis_device(rndis_dev);
996
997                 return (ENOMEM);
998         }
999
1000         /*
1001          * Initialize the rndis device
1002          */
1003
1004         net_dev->extension = rndis_dev;
1005         rndis_dev->net_dev = net_dev;
1006
1007         /* Send the rndis initialization message */
1008         ret = hv_rf_init_device(rndis_dev);
1009         if (ret != 0) {
1010                 /*
1011                  * TODO: If rndis init failed, we will need to shut down
1012                  * the channel
1013                  */
1014         }
1015
1016         /* Get the mac address */
1017         ret = hv_rf_query_device_mac(rndis_dev);
1018         if (ret != 0) {
1019                 /* TODO: shut down rndis device and the channel */
1020         }
1021
1022         /* config csum offload and send request to host */
1023         memset(&offloads, 0, sizeof(offloads));
1024         offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1025         offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1026         offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1027         offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1028         offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1029         offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1030
1031         ret = hv_rf_send_offload_request(device, &offloads);
1032         if (ret != 0) {
1033                 /* TODO: shut down rndis device and the channel */
1034                 device_printf(dev,
1035                     "hv_rf_send_offload_request failed, ret=%d\n", ret);
1036         }
1037         
1038         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
1039
1040         hv_rf_query_device_link_status(rndis_dev);
1041         
1042         dev_info->link_state = rndis_dev->link_status;
1043
1044         net_dev->num_channel = 1;
1045         if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1046                 return (0);
1047
1048         memset(&rsscaps, 0, rsscaps_size);
1049         ret = hv_rf_query_device(rndis_dev,
1050                         RNDIS_OID_GEN_RSS_CAPABILITIES,
1051                         &rsscaps, &rsscaps_size);
1052         if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
1053                 device_printf(dev, "hv_rf_query_device failed or "
1054                         "rsscaps.num_recv_que < 2 \n");
1055                 goto out;
1056         }
1057         device_printf(dev, "channel, offered %u, requested %d\n",
1058             rsscaps.num_recv_que, nchan);
1059         if (nchan > rsscaps.num_recv_que)
1060                 nchan = rsscaps.num_recv_que;
1061         net_dev->num_channel = nchan;
1062
1063         if (net_dev->num_channel == 1) {
1064                 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1065                 goto out;
1066         }
1067         
1068         /* request host to create sub channels */
1069         init_pkt = &net_dev->channel_init_packet;
1070         memset(init_pkt, 0, sizeof(nvsp_msg));
1071
1072         init_pkt->hdr.msg_type = nvsp_msg5_type_subchannel;
1073         init_pkt->msgs.vers_5_msgs.subchannel_request.op =
1074             NVSP_SUBCHANNE_ALLOCATE;
1075         init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
1076             net_dev->num_channel - 1;
1077
1078         ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
1079             sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
1080             HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
1081             HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1082         if (ret != 0) {
1083                 device_printf(dev, "Fail to allocate subchannel\n");
1084                 goto out;
1085         }
1086
1087         sema_wait(&net_dev->channel_init_sema);
1088
1089         if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
1090             nvsp_status_success) {
1091                 ret = ENODEV;
1092                 device_printf(dev, "sub channel complete error\n");
1093                 goto out;
1094         }
1095
1096         net_dev->num_channel = 1 +
1097             init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
1098
1099         ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1100
1101 out:
1102         if (ret)
1103                 net_dev->num_channel = 1;
1104
1105         return (ret);
1106 }
1107
1108 /*
1109  * RNDIS filter on device remove
1110  */
1111 int
1112 hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
1113 {
1114         hn_softc_t *sc = device_get_softc(device->device);
1115         netvsc_dev *net_dev = sc->net_dev;
1116         rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1117         int ret;
1118
1119         /* Halt and release the rndis device */
1120         ret = hv_rf_halt_device(rndis_dev);
1121
1122         hv_put_rndis_device(rndis_dev);
1123         net_dev->extension = NULL;
1124
1125         /* Pass control to inner driver to remove the device */
1126         ret |= hv_nv_on_device_remove(device, destroy_channel);
1127
1128         return (ret);
1129 }
1130
1131 /*
1132  * RNDIS filter on open
1133  */
1134 int
1135 hv_rf_on_open(struct hv_device *device)
1136 {
1137         hn_softc_t *sc = device_get_softc(device->device);      
1138         netvsc_dev *net_dev = sc->net_dev;
1139
1140         return (hv_rf_open_device((rndis_device *)net_dev->extension));
1141 }
1142
1143 /*
1144  * RNDIS filter on close
1145  */
1146 int 
1147 hv_rf_on_close(struct hv_device *device)
1148 {
1149         hn_softc_t *sc = device_get_softc(device->device);      
1150         netvsc_dev *net_dev = sc->net_dev;
1151
1152         return (hv_rf_close_device((rndis_device *)net_dev->extension));
1153 }
1154
1155 /*
1156  * RNDIS filter on send request completion callback
1157  */
1158 static void 
1159 hv_rf_on_send_request_completion(struct hv_vmbus_channel *chan __unused,
1160     void *context __unused)
1161 {
1162 }
1163
1164 /*
1165  * RNDIS filter on send request (halt only) completion callback
1166  */
1167 static void 
1168 hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *chan __unused,
1169     void *context)
1170 {
1171         rndis_request *request = context;
1172
1173         /*
1174          * Notify hv_rf_halt_device() about halt completion.
1175          * The halt code must wait for completion before freeing
1176          * the transaction resources.
1177          */
1178         request->halt_complete_flag = 1;
1179 }
1180
1181 void
1182 hv_rf_channel_rollup(struct hv_vmbus_channel *chan)
1183 {
1184
1185         netvsc_channel_rollup(chan);
1186 }