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