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