]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
MFC 302698-302704,302706
[FreeBSD/stable/10.git] / sys / dev / hyperv / netvsc / hv_rndis_filter.c
1 /*-
2  * Copyright (c) 2009-2012,2016 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 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;
58 };
59
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)
69
70 /*
71  * Forward declarations
72  */
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,
77                                           rndis_msg *response);
78 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
79                                struct hv_vmbus_channel *chan,
80                                netvsc_packet *pkt);
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);
91 int
92 hv_rf_send_offload_request(struct hn_softc *sc,
93     rndis_offload_params *offloads);
94 /*
95  * Set the Per-Packet-Info with the specified type
96  */
97 void *
98 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
99         int pkt_type)
100 {
101         rndis_packet *rndis_pkt;
102         rndis_per_packet_info *rppi;
103
104         rndis_pkt = &rndis_mesg->msg.packet;
105         rndis_pkt->data_offset += rppi_size;
106
107         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
108             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
109
110         rppi->size = rppi_size;
111         rppi->type = pkt_type;
112         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
113
114         rndis_pkt->per_pkt_info_length += rppi_size;
115
116         return (rppi);
117 }
118
119 /*
120  * Get the Per-Packet-Info with the specified type
121  * return NULL if not found.
122  */
123 void *
124 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
125 {
126         rndis_per_packet_info *ppi;
127         int len;
128
129         if (rpkt->per_pkt_info_offset == 0)
130                 return (NULL);
131
132         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
133             rpkt->per_pkt_info_offset);
134         len = rpkt->per_pkt_info_length;
135
136         while (len > 0) {
137                 if (ppi->type == type)
138                         return (void *)((unsigned long)ppi +
139                             ppi->per_packet_info_offset);
140
141                 len -= ppi->size;
142                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
143         }
144
145         return (NULL);
146 }
147
148
149 /*
150  * Allow module_param to work and override to switch to promiscuous mode.
151  */
152 static inline rndis_device *
153 hv_get_rndis_device(void)
154 {
155         rndis_device *device;
156
157         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
158
159         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
160
161         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
162         STAILQ_INIT(&device->myrequest_list);
163
164         device->state = RNDIS_DEV_UNINITIALIZED;
165
166         return (device);
167 }
168
169 /*
170  *
171  */
172 static inline void
173 hv_put_rndis_device(rndis_device *device)
174 {
175         mtx_destroy(&device->req_lock);
176         free(device, M_NETVSC);
177 }
178
179 /*
180  *
181  */
182 static inline rndis_request *
183 hv_rndis_request(rndis_device *device, uint32_t message_type,
184                  uint32_t message_length)
185 {
186         rndis_request *request;
187         rndis_msg *rndis_mesg;
188         rndis_set_request *set;
189
190         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
191
192         sema_init(&request->wait_sema, 0, "rndis sema");
193         
194         rndis_mesg = &request->request_msg;
195         rndis_mesg->ndis_msg_type = message_type;
196         rndis_mesg->msg_len = message_length;
197
198         /*
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
201          * as a template.
202          */
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;
207
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);
212
213         return (request);
214 }
215
216 /*
217  *
218  */
219 static inline void
220 hv_put_rndis_request(rndis_device *device, rndis_request *request)
221 {
222         mtx_lock(&device->req_lock);
223         /* Fixme:  Has O(n) performance */
224         /*
225          * XXXKYS: Use Doubly linked lists.
226          */
227         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
228             mylist_entry);
229         mtx_unlock(&device->req_lock);
230
231         sema_destroy(&request->wait_sema);
232         free(request, M_NETVSC);
233 }
234
235 /*
236  *
237  */
238 static int
239 hv_rf_send_request(rndis_device *device, rndis_request *request,
240     uint32_t message_type)
241 {
242         int ret;
243         netvsc_packet *packet;
244         netvsc_dev      *net_dev = device->net_dev;
245         int send_buf_section_idx;
246
247         /* Set up the packet to send it */
248         packet = &request->pkt;
249         
250         packet->is_data_pkt = FALSE;
251         packet->tot_data_buf_len = request->request_msg.msg_len;
252         packet->page_buf_count = 1;
253
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);
259
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;
272         }
273
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;
278         } else {
279                 packet->compl.send.on_send_completion =
280                     hv_rf_on_send_request_halt_completion;
281         }
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);
289
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;
294                         goto sendit;
295                 }
296                 /* Failed to allocate chimney send buffer; move on */
297         }
298         packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
299         packet->send_buf_section_size = 0;
300
301 sendit:
302         ret = hv_nv_on_send(device->net_dev->sc->hn_prichan, packet);
303
304         return (ret);
305 }
306
307 /*
308  * RNDIS filter receive response
309  */
310 static void 
311 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
312 {
313         rndis_request *request = NULL;
314         rndis_request *next_request;
315         boolean_t found = FALSE;
316
317         mtx_lock(&device->req_lock);
318         request = STAILQ_FIRST(&device->myrequest_list);
319         while (request != NULL) {
320                 /*
321                  * All request/response message contains request_id as the
322                  * first field
323                  */
324                 if (request->request_msg.msg.init_request.request_id ==
325                                       response->msg.init_complete.request_id) {
326                         found = TRUE;
327                         break;
328                 }
329                 next_request = STAILQ_NEXT(request, mylist_entry);
330                 request = next_request;
331         }
332         mtx_unlock(&device->req_lock);
333
334         if (found) {
335                 if (response->msg_len <= sizeof(rndis_msg)) {
336                         memcpy(&request->response_msg, response,
337                             response->msg_len);
338                 } else {
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;
343                         } else {
344                                 request->response_msg.msg.init_complete.status =
345                                     STATUS_BUFFER_OVERFLOW;
346                         }
347                 }
348
349                 sema_post(&request->wait_sema);
350         }
351 }
352
353 int
354 hv_rf_send_offload_request(struct hn_softc *sc,
355     rndis_offload_params *offloads)
356 {
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);
366         int ret;
367
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.
372                  */
373                 offloads->udp_ipv4_csum = 0;
374                 offloads->udp_ipv6_csum = 0;
375         }
376
377         rndis_dev = net_dev->extension;
378
379         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
380             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
381         if (!request)
382                 return (ENOMEM);
383
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;
389
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;
396
397         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
398         if (ret != 0) {
399                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
400                     ret);
401                 goto cleanup;
402         }
403
404         ret = sema_timedwait(&request->wait_sema, 5 * hz);
405         if (ret != 0) {
406                 device_printf(dev, "hv send offload request timeout\n");
407                 goto cleanup;
408         }
409
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");
413                 ret = 0;
414         } else {
415                 if (set_complete->status == STATUS_NOT_SUPPORTED) {
416                         device_printf(dev, "HV Not support offload\n");
417                         ret = 0;
418                 } else {
419                         ret = set_complete->status;
420                 }
421         }
422
423 cleanup:
424         hv_put_rndis_request(rndis_dev, request);
425
426         return (ret);
427 }
428
429 /*
430  * RNDIS filter receive indicate status
431  */
432 static void 
433 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
434 {
435         rndis_indicate_status *indicate = &response->msg.indicate_status;
436                 
437         switch(indicate->status) {
438         case RNDIS_STATUS_MEDIA_CONNECT:
439                 netvsc_linkstatus_callback(device->net_dev->sc, 1);
440                 break;
441         case RNDIS_STATUS_MEDIA_DISCONNECT:
442                 netvsc_linkstatus_callback(device->net_dev->sc, 0);
443                 break;
444         default:
445                 /* TODO: */
446                 device_printf(device->net_dev->sc->hn_dev,
447                     "unknown status %d received\n", indicate->status);
448                 break;
449         }
450 }
451
452 static int
453 hv_rf_find_recvinfo(const rndis_packet *rpkt, struct hv_rf_recvinfo *info)
454 {
455         const rndis_per_packet_info *ppi;
456         uint32_t mask, len;
457
458         info->vlan_info = NULL;
459         info->csum_info = NULL;
460         info->hash_info = NULL;
461         info->hash_value = NULL;
462
463         if (rpkt->per_pkt_info_offset == 0)
464                 return 0;
465
466         ppi = (const rndis_per_packet_info *)
467             ((const uint8_t *)rpkt + rpkt->per_pkt_info_offset);
468         len = rpkt->per_pkt_info_length;
469         mask = 0;
470
471         while (len != 0) {
472                 const void *ppi_dptr;
473                 uint32_t ppi_dlen;
474
475                 if (__predict_false(ppi->size < ppi->per_packet_info_offset))
476                         return EINVAL;
477                 ppi_dlen = ppi->size - ppi->per_packet_info_offset;
478                 ppi_dptr = (const uint8_t *)ppi + ppi->per_packet_info_offset;
479
480                 switch (ppi->type) {
481                 case ieee_8021q_info:
482                         if (__predict_false(ppi_dlen < sizeof(ndis_8021q_info)))
483                                 return EINVAL;
484                         info->vlan_info = ppi_dptr;
485                         mask |= HV_RF_RECVINFO_VLAN;
486                         break;
487
488                 case tcpip_chksum_info:
489                         if (__predict_false(ppi_dlen <
490                             sizeof(rndis_tcp_ip_csum_info)))
491                                 return EINVAL;
492                         info->csum_info = ppi_dptr;
493                         mask |= HV_RF_RECVINFO_CSUM;
494                         break;
495
496                 case nbl_hash_value:
497                         if (__predict_false(ppi_dlen <
498                             sizeof(struct rndis_hash_value)))
499                                 return EINVAL;
500                         info->hash_value = ppi_dptr;
501                         mask |= HV_RF_RECVINFO_HASHVAL;
502                         break;
503
504                 case nbl_hash_info:
505                         if (__predict_false(ppi_dlen <
506                             sizeof(struct rndis_hash_info)))
507                                 return EINVAL;
508                         info->hash_info = ppi_dptr;
509                         mask |= HV_RF_RECVINFO_HASHINF;
510                         break;
511
512                 default:
513                         goto skip;
514                 }
515
516                 if (mask == HV_RF_RECVINFO_ALL) {
517                         /* All found; done */
518                         break;
519                 }
520 skip:
521                 if (__predict_false(len < ppi->size))
522                         return EINVAL;
523                 len -= ppi->size;
524                 ppi = (const rndis_per_packet_info *)
525                     ((const uint8_t *)ppi + ppi->size);
526         }
527         return 0;
528 }
529
530 /*
531  * RNDIS filter receive data
532  */
533 static void
534 hv_rf_receive_data(rndis_device *device, rndis_msg *message,
535     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
536 {
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;
541
542         rndis_pkt = &message->msg.packet;
543
544         /*
545          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
546          * netvsc packet (ie tot_data_buf_len != message_length)
547          */
548
549         /* Remove rndis header, then pass data packet up the stack */
550         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
551
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;
555                 device_printf(dev,
556                     "total length %u is less than data length %u\n",
557                     pkt->tot_data_buf_len, rndis_pkt->data_length);
558                 return;
559         }
560
561         pkt->tot_data_buf_len = rndis_pkt->data_length;
562         pkt->data = (void *)((unsigned long)pkt->data + data_offset);
563
564         if (hv_rf_find_recvinfo(rndis_pkt, &info)) {
565                 pkt->status = nvsp_status_failure;
566                 device_printf(dev, "recvinfo parsing failed\n");
567                 return;
568         }
569
570         if (info.vlan_info != NULL)
571                 pkt->vlan_tci = info.vlan_info->u1.s1.vlan_id;
572         else
573                 pkt->vlan_tci = 0;
574
575         netvsc_recv(chan, pkt, info.csum_info, info.hash_info, info.hash_value);
576 }
577
578 /*
579  * RNDIS filter on receive
580  */
581 int
582 hv_rf_on_receive(netvsc_dev *net_dev,
583     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
584 {
585         rndis_device *rndis_dev;
586         rndis_msg *rndis_hdr;
587
588         /* Make sure the rndis device state is initialized */
589         if (net_dev->extension == NULL) {
590                 pkt->status = nvsp_status_failure;
591                 return (ENODEV);
592         }
593
594         rndis_dev = (rndis_device *)net_dev->extension;
595         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
596                 pkt->status = nvsp_status_failure;
597                 return (EINVAL);
598         }
599
600         rndis_hdr = pkt->data;
601
602         switch (rndis_hdr->ndis_msg_type) {
603
604         /* data message */
605         case REMOTE_NDIS_PACKET_MSG:
606                 hv_rf_receive_data(rndis_dev, rndis_hdr, chan, pkt);
607                 break;
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);
615                 break;
616         /* notification message */
617         case REMOTE_NDIS_INDICATE_STATUS_MSG:
618                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
619                 break;
620         default:
621                 printf("hv_rf_on_receive():  Unknown msg_type 0x%x\n",
622                         rndis_hdr->ndis_msg_type);
623                 break;
624         }
625
626         return (0);
627 }
628
629 /*
630  * RNDIS filter query device
631  */
632 static int
633 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
634                    uint32_t *result_size)
635 {
636         rndis_request *request;
637         uint32_t in_result_size = *result_size;
638         rndis_query_request *query;
639         rndis_query_complete *query_complete;
640         int ret = 0;
641
642         *result_size = 0;
643         request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
644             RNDIS_MESSAGE_SIZE(rndis_query_request));
645         if (request == NULL) {
646                 ret = -1;
647                 goto cleanup;
648         }
649
650         /* Set up the rndis query */
651         query = &request->request_msg.msg.query_request;
652         query->oid = oid;
653         query->info_buffer_offset = sizeof(rndis_query_request); 
654         query->info_buffer_length = 0;
655         query->device_vc_handle = 0;
656
657         if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
658                 struct rndis_recv_scale_cap *cap;
659
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);
668         }
669
670         ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
671         if (ret != 0) {
672                 /* Fixme:  printf added */
673                 printf("RNDISFILTER request failed to Send!\n");
674                 goto cleanup;
675         }
676
677         sema_wait(&request->wait_sema);
678
679         /* Copy the response back */
680         query_complete = &request->response_msg.msg.query_complete;
681         
682         if (query_complete->info_buffer_length > in_result_size) {
683                 ret = EINVAL;
684                 goto cleanup;
685         }
686
687         memcpy(result, (void *)((unsigned long)query_complete +
688             query_complete->info_buffer_offset),
689             query_complete->info_buffer_length);
690
691         *result_size = query_complete->info_buffer_length;
692
693 cleanup:
694         if (request != NULL)
695                 hv_put_rndis_request(device, request);
696
697         return (ret);
698 }
699
700 /*
701  * RNDIS filter query device MAC address
702  */
703 static inline int
704 hv_rf_query_device_mac(rndis_device *device)
705 {
706         uint32_t size = HW_MACADDR_LEN;
707
708         return (hv_rf_query_device(device,
709             RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
710 }
711
712 /*
713  * RNDIS filter query device link status
714  */
715 static inline int
716 hv_rf_query_device_link_status(rndis_device *device)
717 {
718         uint32_t size = sizeof(uint32_t);
719
720         return (hv_rf_query_device(device,
721             RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
722 }
723
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
730 };
731
732 /*
733  * RNDIS set vRSS parameters
734  */
735 static int
736 hv_rf_set_rss_param(rndis_device *device, int num_queue)
737 {
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;
745         uint8_t *keyp;
746         int i, ret;
747
748
749         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
750             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
751         if (request == NULL) {
752                 if (bootverbose)
753                         printf("Netvsc: No memory to set vRSS parameters.\n");
754                 ret = -1;
755                 goto cleanup;
756         }
757
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;
763
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);
769         rssp->flag = 0;
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;
777
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;
782
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];
787
788         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
789         if (ret != 0) {
790                 goto cleanup;
791         }
792
793         /*
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.
797          */
798         ret = sema_timedwait(&request->wait_sema, 5 * hz);
799         if (ret == 0) {
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 */
805                         if (bootverbose)
806                                 printf("Netvsc: Failed to set vRSS "
807                                     "parameters.\n");
808                         ret = -2;
809                 } else {
810                         if (bootverbose)
811                                 printf("Netvsc: Successfully set vRSS "
812                                     "parameters.\n");
813                 }
814         } else {
815                 /*
816                  * We cannot deallocate the request since we may still
817                  * receive a send completion for it.
818                  */
819                 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
820                     request->request_msg.msg.init_request.request_id, ret);
821                 goto exit;
822         }
823
824 cleanup:
825         if (request != NULL) {
826                 hv_put_rndis_request(device, request);
827         }
828 exit:
829         return (ret);
830 }
831
832 /*
833  * RNDIS filter set packet filter
834  * Sends an rndis request with the new filter, then waits for a response
835  * from the host.
836  * Returns zero on success, non-zero on failure.
837  */
838 static int
839 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
840 {
841         rndis_request *request;
842         rndis_set_request *set;
843         rndis_set_complete *set_complete;
844         uint32_t status;
845         int ret;
846
847         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
848             RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
849         if (request == NULL) {
850                 ret = -1;
851                 goto cleanup;
852         }
853
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); 
859
860         memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
861             &new_filter, sizeof(uint32_t));
862
863         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
864         if (ret != 0) {
865                 goto cleanup;
866         }
867
868         /*
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.
872          */
873         ret = sema_timedwait(&request->wait_sema, 5 * hz);
874         if (ret == 0) {
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 */
880                         ret = -2;
881                 }
882         } else {
883                 /*
884                  * We cannot deallocate the request since we may still
885                  * receive a send completion for it.
886                  */
887                 goto exit;
888         }
889
890 cleanup:
891         if (request != NULL) {
892                 hv_put_rndis_request(device, request);
893         }
894 exit:
895         return (ret);
896 }
897
898 /*
899  * RNDIS filter init device
900  */
901 static int
902 hv_rf_init_device(rndis_device *device)
903 {
904         rndis_request *request;
905         rndis_initialize_request *init;
906         rndis_initialize_complete *init_complete;
907         uint32_t status;
908         int ret;
909
910         request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
911             RNDIS_MESSAGE_SIZE(rndis_initialize_request));
912         if (!request) {
913                 ret = -1;
914                 goto cleanup;
915         }
916
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;
921         /*
922          * Per the RNDIS document, this should be set to the max MTU
923          * plus the header size.  However, 2048 works fine, so leaving
924          * it as is.
925          */
926         init->max_xfer_size = 2048;
927         
928         device->state = RNDIS_DEV_INITIALIZING;
929
930         ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
931         if (ret != 0) {
932                 device->state = RNDIS_DEV_UNINITIALIZED;
933                 goto cleanup;
934         }
935
936         sema_wait(&request->wait_sema);
937
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;
942                 ret = 0;
943         } else {
944                 device->state = RNDIS_DEV_UNINITIALIZED; 
945                 ret = -1;
946         }
947
948 cleanup:
949         if (request) {
950                 hv_put_rndis_request(device, request);
951         }
952
953         return (ret);
954 }
955
956 #define HALT_COMPLETION_WAIT_COUNT      25
957
958 /*
959  * RNDIS filter halt device
960  */
961 static int
962 hv_rf_halt_device(rndis_device *device)
963 {
964         rndis_request *request;
965         rndis_halt_request *halt;
966         int i, ret;
967
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) {
972                 return (-1);
973         }
974
975         /* initialize "poor man's semaphore" */
976         request->halt_complete_flag = 0;
977
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;
983         
984         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
985         if (ret != 0) {
986                 return (-1);
987         }
988
989         /*
990          * Wait for halt response from halt callback.  We must wait for
991          * the transaction response before freeing the request and other
992          * resources.
993          */
994         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
995                 if (request->halt_complete_flag != 0) {
996                         break;
997                 }
998                 DELAY(400);
999         }
1000         if (i == 0) {
1001                 return (-1);
1002         }
1003
1004         device->state = RNDIS_DEV_UNINITIALIZED;
1005
1006         hv_put_rndis_request(device, request);
1007
1008         return (0);
1009 }
1010
1011 /*
1012  * RNDIS filter open device
1013  */
1014 static int
1015 hv_rf_open_device(rndis_device *device)
1016 {
1017         int ret;
1018
1019         if (device->state != RNDIS_DEV_INITIALIZED) {
1020                 return (0);
1021         }
1022
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);
1028         } else {
1029                 ret = hv_rf_set_packet_filter(device, 
1030                     NDIS_PACKET_TYPE_PROMISCUOUS);
1031         }
1032
1033         if (ret == 0) {
1034                 device->state = RNDIS_DEV_DATAINITIALIZED;
1035         }
1036
1037         return (ret);
1038 }
1039
1040 /*
1041  * RNDIS filter close device
1042  */
1043 static int
1044 hv_rf_close_device(rndis_device *device)
1045 {
1046         int ret;
1047
1048         if (device->state != RNDIS_DEV_DATAINITIALIZED) {
1049                 return (0);
1050         }
1051
1052         ret = hv_rf_set_packet_filter(device, 0);
1053         if (ret == 0) {
1054                 device->state = RNDIS_DEV_INITIALIZED;
1055         }
1056
1057         return (ret);
1058 }
1059
1060 /*
1061  * RNDIS filter on device add
1062  */
1063 int
1064 hv_rf_on_device_add(struct hn_softc *sc, void *additl_info,
1065     int nchan)
1066 {
1067         int ret;
1068         netvsc_dev *net_dev;
1069         rndis_device *rndis_dev;
1070         nvsp_msg *init_pkt;
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;
1076
1077         rndis_dev = hv_get_rndis_device();
1078         if (rndis_dev == NULL) {
1079                 return (ENOMEM);
1080         }
1081
1082         /*
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.
1087          */
1088         net_dev = hv_nv_on_device_add(sc, additl_info);
1089         if (!net_dev) {
1090                 hv_put_rndis_device(rndis_dev);
1091
1092                 return (ENOMEM);
1093         }
1094
1095         /*
1096          * Initialize the rndis device
1097          */
1098
1099         net_dev->extension = rndis_dev;
1100         rndis_dev->net_dev = net_dev;
1101
1102         /* Send the rndis initialization message */
1103         ret = hv_rf_init_device(rndis_dev);
1104         if (ret != 0) {
1105                 /*
1106                  * TODO: If rndis init failed, we will need to shut down
1107                  * the channel
1108                  */
1109         }
1110
1111         /* Get the mac address */
1112         ret = hv_rf_query_device_mac(rndis_dev);
1113         if (ret != 0) {
1114                 /* TODO: shut down rndis device and the channel */
1115         }
1116
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;
1125
1126         ret = hv_rf_send_offload_request(sc, &offloads);
1127         if (ret != 0) {
1128                 /* TODO: shut down rndis device and the channel */
1129                 device_printf(dev,
1130                     "hv_rf_send_offload_request failed, ret=%d\n", ret);
1131         }
1132         
1133         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
1134
1135         hv_rf_query_device_link_status(rndis_dev);
1136         
1137         dev_info->link_state = rndis_dev->link_status;
1138
1139         net_dev->num_channel = 1;
1140         if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1141                 return (0);
1142
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");
1150                 goto out;
1151         }
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;
1157
1158         if (net_dev->num_channel == 1) {
1159                 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1160                 goto out;
1161         }
1162         
1163         /* request host to create sub channels */
1164         init_pkt = &net_dev->channel_init_packet;
1165         memset(init_pkt, 0, sizeof(nvsp_msg));
1166
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;
1172
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);
1177         if (ret != 0) {
1178                 device_printf(dev, "Fail to allocate subchannel\n");
1179                 goto out;
1180         }
1181
1182         sema_wait(&net_dev->channel_init_sema);
1183
1184         if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
1185             nvsp_status_success) {
1186                 ret = ENODEV;
1187                 device_printf(dev, "sub channel complete error\n");
1188                 goto out;
1189         }
1190
1191         net_dev->num_channel = 1 +
1192             init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
1193
1194         ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1195
1196 out:
1197         if (ret)
1198                 net_dev->num_channel = 1;
1199
1200         return (ret);
1201 }
1202
1203 /*
1204  * RNDIS filter on device remove
1205  */
1206 int
1207 hv_rf_on_device_remove(struct hn_softc *sc, boolean_t destroy_channel)
1208 {
1209         netvsc_dev *net_dev = sc->net_dev;
1210         rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1211         int ret;
1212
1213         /* Halt and release the rndis device */
1214         ret = hv_rf_halt_device(rndis_dev);
1215
1216         hv_put_rndis_device(rndis_dev);
1217         net_dev->extension = NULL;
1218
1219         /* Pass control to inner driver to remove the device */
1220         ret |= hv_nv_on_device_remove(sc, destroy_channel);
1221
1222         return (ret);
1223 }
1224
1225 /*
1226  * RNDIS filter on open
1227  */
1228 int
1229 hv_rf_on_open(struct hn_softc *sc)
1230 {
1231         netvsc_dev *net_dev = sc->net_dev;
1232
1233         return (hv_rf_open_device((rndis_device *)net_dev->extension));
1234 }
1235
1236 /*
1237  * RNDIS filter on close
1238  */
1239 int 
1240 hv_rf_on_close(struct hn_softc *sc)
1241 {
1242         netvsc_dev *net_dev = sc->net_dev;
1243
1244         return (hv_rf_close_device((rndis_device *)net_dev->extension));
1245 }
1246
1247 /*
1248  * RNDIS filter on send request completion callback
1249  */
1250 static void 
1251 hv_rf_on_send_request_completion(struct hv_vmbus_channel *chan __unused,
1252     void *context __unused)
1253 {
1254 }
1255
1256 /*
1257  * RNDIS filter on send request (halt only) completion callback
1258  */
1259 static void 
1260 hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *chan __unused,
1261     void *context)
1262 {
1263         rndis_request *request = context;
1264
1265         /*
1266          * Notify hv_rf_halt_device() about halt completion.
1267          * The halt code must wait for completion before freeing
1268          * the transaction resources.
1269          */
1270         request->halt_complete_flag = 1;
1271 }
1272
1273 void
1274 hv_rf_channel_rollup(struct hv_vmbus_channel *chan)
1275 {
1276
1277         netvsc_channel_rollup(chan);
1278 }