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