]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
hyperv/hn: Mark sysctls MPSAFE
[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         device_t dev = device->net_dev->dev->device;
448
449         rndis_pkt = &message->msg.packet;
450
451         /*
452          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
453          * netvsc packet (ie tot_data_buf_len != message_length)
454          */
455
456         /* Remove rndis header, then pass data packet up the stack */
457         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
458
459         pkt->tot_data_buf_len -= data_offset;
460         if (pkt->tot_data_buf_len < rndis_pkt->data_length) {
461                 pkt->status = nvsp_status_failure;
462                 device_printf(dev,
463                     "total length %u is less than data length %u\n",
464                     pkt->tot_data_buf_len, rndis_pkt->data_length);
465                 return;
466         }
467
468         pkt->tot_data_buf_len = rndis_pkt->data_length;
469         pkt->data = (void *)((unsigned long)pkt->data + data_offset);
470
471         rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info);
472         if (rppi_vlan_info) {
473                 pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id;
474         } else {
475                 pkt->vlan_tci = 0;
476         }
477
478         csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info);
479         netvsc_recv(chan, pkt, csum_info);
480 }
481
482 /*
483  * RNDIS filter on receive
484  */
485 int
486 hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device,
487     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
488 {
489         rndis_device *rndis_dev;
490         rndis_msg *rndis_hdr;
491
492         /* Make sure the rndis device state is initialized */
493         if (net_dev->extension == NULL) {
494                 pkt->status = nvsp_status_failure;
495                 return (ENODEV);
496         }
497
498         rndis_dev = (rndis_device *)net_dev->extension;
499         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
500                 pkt->status = nvsp_status_failure;
501                 return (EINVAL);
502         }
503
504         rndis_hdr = pkt->data;
505
506         switch (rndis_hdr->ndis_msg_type) {
507
508         /* data message */
509         case REMOTE_NDIS_PACKET_MSG:
510                 hv_rf_receive_data(rndis_dev, rndis_hdr, chan, pkt);
511                 break;
512         /* completion messages */
513         case REMOTE_NDIS_INITIALIZE_CMPLT:
514         case REMOTE_NDIS_QUERY_CMPLT:
515         case REMOTE_NDIS_SET_CMPLT:
516         case REMOTE_NDIS_RESET_CMPLT:
517         case REMOTE_NDIS_KEEPALIVE_CMPLT:
518                 hv_rf_receive_response(rndis_dev, rndis_hdr);
519                 break;
520         /* notification message */
521         case REMOTE_NDIS_INDICATE_STATUS_MSG:
522                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
523                 break;
524         default:
525                 printf("hv_rf_on_receive():  Unknown msg_type 0x%x\n",
526                         rndis_hdr->ndis_msg_type);
527                 break;
528         }
529
530         return (0);
531 }
532
533 /*
534  * RNDIS filter query device
535  */
536 static int
537 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
538                    uint32_t *result_size)
539 {
540         rndis_request *request;
541         uint32_t in_result_size = *result_size;
542         rndis_query_request *query;
543         rndis_query_complete *query_complete;
544         int ret = 0;
545
546         *result_size = 0;
547         request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
548             RNDIS_MESSAGE_SIZE(rndis_query_request));
549         if (request == NULL) {
550                 ret = -1;
551                 goto cleanup;
552         }
553
554         /* Set up the rndis query */
555         query = &request->request_msg.msg.query_request;
556         query->oid = oid;
557         query->info_buffer_offset = sizeof(rndis_query_request); 
558         query->info_buffer_length = 0;
559         query->device_vc_handle = 0;
560
561         if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
562                 struct rndis_recv_scale_cap *cap;
563
564                 request->request_msg.msg_len += 
565                         sizeof(struct rndis_recv_scale_cap);
566                 query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
567                 cap = (struct rndis_recv_scale_cap *)((unsigned long)query + 
568                                                 query->info_buffer_offset);
569                 cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
570                 cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
571                 cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
572         }
573
574         ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
575         if (ret != 0) {
576                 /* Fixme:  printf added */
577                 printf("RNDISFILTER request failed to Send!\n");
578                 goto cleanup;
579         }
580
581         sema_wait(&request->wait_sema);
582
583         /* Copy the response back */
584         query_complete = &request->response_msg.msg.query_complete;
585         
586         if (query_complete->info_buffer_length > in_result_size) {
587                 ret = EINVAL;
588                 goto cleanup;
589         }
590
591         memcpy(result, (void *)((unsigned long)query_complete +
592             query_complete->info_buffer_offset),
593             query_complete->info_buffer_length);
594
595         *result_size = query_complete->info_buffer_length;
596
597 cleanup:
598         if (request != NULL)
599                 hv_put_rndis_request(device, request);
600
601         return (ret);
602 }
603
604 /*
605  * RNDIS filter query device MAC address
606  */
607 static inline int
608 hv_rf_query_device_mac(rndis_device *device)
609 {
610         uint32_t size = HW_MACADDR_LEN;
611
612         return (hv_rf_query_device(device,
613             RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
614 }
615
616 /*
617  * RNDIS filter query device link status
618  */
619 static inline int
620 hv_rf_query_device_link_status(rndis_device *device)
621 {
622         uint32_t size = sizeof(uint32_t);
623
624         return (hv_rf_query_device(device,
625             RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
626 }
627
628 static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
629         0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
630         0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
631         0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
632         0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
633         0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
634 };
635
636 /*
637  * RNDIS set vRSS parameters
638  */
639 static int
640 hv_rf_set_rss_param(rndis_device *device, int num_queue)
641 {
642         rndis_request *request;
643         rndis_set_request *set;
644         rndis_set_complete *set_complete;
645         rndis_recv_scale_param *rssp;
646         uint32_t extlen = sizeof(rndis_recv_scale_param) +
647             (4 * ITAB_NUM) + HASH_KEYLEN;
648         uint32_t *itab, status;
649         uint8_t *keyp;
650         int i, ret;
651
652
653         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
654             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
655         if (request == NULL) {
656                 if (bootverbose)
657                         printf("Netvsc: No memory to set vRSS parameters.\n");
658                 ret = -1;
659                 goto cleanup;
660         }
661
662         set = &request->request_msg.msg.set_request;
663         set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
664         set->info_buffer_length = extlen;
665         set->info_buffer_offset = sizeof(rndis_set_request);
666         set->device_vc_handle = 0;
667
668         /* Fill out the rssp parameter structure */
669         rssp = (rndis_recv_scale_param *)(set + 1);
670         rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
671         rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
672         rssp->hdr.size = sizeof(rndis_recv_scale_param);
673         rssp->flag = 0;
674         rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
675             RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
676         rssp->indirect_tabsize = 4 * ITAB_NUM;
677         rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
678         rssp->hashkey_size = HASH_KEYLEN;
679         rssp->hashkey_offset = rssp->indirect_taboffset +
680             rssp->indirect_tabsize;
681
682         /* Set indirection table entries */
683         itab = (uint32_t *)(rssp + 1);
684         for (i = 0; i < ITAB_NUM; i++)
685                 itab[i] = i % num_queue;
686
687         /* Set hash key values */
688         keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
689         for (i = 0; i < HASH_KEYLEN; i++)
690                 keyp[i] = netvsc_hash_key[i];
691
692         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
693         if (ret != 0) {
694                 goto cleanup;
695         }
696
697         /*
698          * Wait for the response from the host.  Another thread will signal
699          * us when the response has arrived.  In the failure case,
700          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
701          */
702         ret = sema_timedwait(&request->wait_sema, 5 * hz);
703         if (ret == 0) {
704                 /* Response received, check status */
705                 set_complete = &request->response_msg.msg.set_complete;
706                 status = set_complete->status;
707                 if (status != RNDIS_STATUS_SUCCESS) {
708                         /* Bad response status, return error */
709                         if (bootverbose)
710                                 printf("Netvsc: Failed to set vRSS "
711                                     "parameters.\n");
712                         ret = -2;
713                 } else {
714                         if (bootverbose)
715                                 printf("Netvsc: Successfully set vRSS "
716                                     "parameters.\n");
717                 }
718         } else {
719                 /*
720                  * We cannot deallocate the request since we may still
721                  * receive a send completion for it.
722                  */
723                 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
724                     request->request_msg.msg.init_request.request_id, ret);
725                 goto exit;
726         }
727
728 cleanup:
729         if (request != NULL) {
730                 hv_put_rndis_request(device, request);
731         }
732 exit:
733         return (ret);
734 }
735
736 /*
737  * RNDIS filter set packet filter
738  * Sends an rndis request with the new filter, then waits for a response
739  * from the host.
740  * Returns zero on success, non-zero on failure.
741  */
742 static int
743 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
744 {
745         rndis_request *request;
746         rndis_set_request *set;
747         rndis_set_complete *set_complete;
748         uint32_t status;
749         int ret;
750
751         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
752             RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
753         if (request == NULL) {
754                 ret = -1;
755                 goto cleanup;
756         }
757
758         /* Set up the rndis set */
759         set = &request->request_msg.msg.set_request;
760         set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
761         set->info_buffer_length = sizeof(uint32_t);
762         set->info_buffer_offset = sizeof(rndis_set_request); 
763
764         memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
765             &new_filter, sizeof(uint32_t));
766
767         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
768         if (ret != 0) {
769                 goto cleanup;
770         }
771
772         /*
773          * Wait for the response from the host.  Another thread will signal
774          * us when the response has arrived.  In the failure case,
775          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
776          */
777         ret = sema_timedwait(&request->wait_sema, 5 * hz);
778         if (ret == 0) {
779                 /* Response received, check status */
780                 set_complete = &request->response_msg.msg.set_complete;
781                 status = set_complete->status;
782                 if (status != RNDIS_STATUS_SUCCESS) {
783                         /* Bad response status, return error */
784                         ret = -2;
785                 }
786         } else {
787                 /*
788                  * We cannot deallocate the request since we may still
789                  * receive a send completion for it.
790                  */
791                 goto exit;
792         }
793
794 cleanup:
795         if (request != NULL) {
796                 hv_put_rndis_request(device, request);
797         }
798 exit:
799         return (ret);
800 }
801
802 /*
803  * RNDIS filter init device
804  */
805 static int
806 hv_rf_init_device(rndis_device *device)
807 {
808         rndis_request *request;
809         rndis_initialize_request *init;
810         rndis_initialize_complete *init_complete;
811         uint32_t status;
812         int ret;
813
814         request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
815             RNDIS_MESSAGE_SIZE(rndis_initialize_request));
816         if (!request) {
817                 ret = -1;
818                 goto cleanup;
819         }
820
821         /* Set up the rndis set */
822         init = &request->request_msg.msg.init_request;
823         init->major_version = RNDIS_MAJOR_VERSION;
824         init->minor_version = RNDIS_MINOR_VERSION;
825         /*
826          * Per the RNDIS document, this should be set to the max MTU
827          * plus the header size.  However, 2048 works fine, so leaving
828          * it as is.
829          */
830         init->max_xfer_size = 2048;
831         
832         device->state = RNDIS_DEV_INITIALIZING;
833
834         ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
835         if (ret != 0) {
836                 device->state = RNDIS_DEV_UNINITIALIZED;
837                 goto cleanup;
838         }
839
840         sema_wait(&request->wait_sema);
841
842         init_complete = &request->response_msg.msg.init_complete;
843         status = init_complete->status;
844         if (status == RNDIS_STATUS_SUCCESS) {
845                 device->state = RNDIS_DEV_INITIALIZED;
846                 ret = 0;
847         } else {
848                 device->state = RNDIS_DEV_UNINITIALIZED; 
849                 ret = -1;
850         }
851
852 cleanup:
853         if (request) {
854                 hv_put_rndis_request(device, request);
855         }
856
857         return (ret);
858 }
859
860 #define HALT_COMPLETION_WAIT_COUNT      25
861
862 /*
863  * RNDIS filter halt device
864  */
865 static int
866 hv_rf_halt_device(rndis_device *device)
867 {
868         rndis_request *request;
869         rndis_halt_request *halt;
870         int i, ret;
871
872         /* Attempt to do a rndis device halt */
873         request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
874             RNDIS_MESSAGE_SIZE(rndis_halt_request));
875         if (request == NULL) {
876                 return (-1);
877         }
878
879         /* initialize "poor man's semaphore" */
880         request->halt_complete_flag = 0;
881
882         /* Set up the rndis set */
883         halt = &request->request_msg.msg.halt_request;
884         halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
885         /* Increment to get the new value (call above returns old value) */
886         halt->request_id += 1;
887         
888         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
889         if (ret != 0) {
890                 return (-1);
891         }
892
893         /*
894          * Wait for halt response from halt callback.  We must wait for
895          * the transaction response before freeing the request and other
896          * resources.
897          */
898         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
899                 if (request->halt_complete_flag != 0) {
900                         break;
901                 }
902                 DELAY(400);
903         }
904         if (i == 0) {
905                 return (-1);
906         }
907
908         device->state = RNDIS_DEV_UNINITIALIZED;
909
910         hv_put_rndis_request(device, request);
911
912         return (0);
913 }
914
915 /*
916  * RNDIS filter open device
917  */
918 static int
919 hv_rf_open_device(rndis_device *device)
920 {
921         int ret;
922
923         if (device->state != RNDIS_DEV_INITIALIZED) {
924                 return (0);
925         }
926
927         if (hv_promisc_mode != 1) {
928                 ret = hv_rf_set_packet_filter(device, 
929                     NDIS_PACKET_TYPE_BROADCAST     |
930                     NDIS_PACKET_TYPE_ALL_MULTICAST |
931                     NDIS_PACKET_TYPE_DIRECTED);
932         } else {
933                 ret = hv_rf_set_packet_filter(device, 
934                     NDIS_PACKET_TYPE_PROMISCUOUS);
935         }
936
937         if (ret == 0) {
938                 device->state = RNDIS_DEV_DATAINITIALIZED;
939         }
940
941         return (ret);
942 }
943
944 /*
945  * RNDIS filter close device
946  */
947 static int
948 hv_rf_close_device(rndis_device *device)
949 {
950         int ret;
951
952         if (device->state != RNDIS_DEV_DATAINITIALIZED) {
953                 return (0);
954         }
955
956         ret = hv_rf_set_packet_filter(device, 0);
957         if (ret == 0) {
958                 device->state = RNDIS_DEV_INITIALIZED;
959         }
960
961         return (ret);
962 }
963
964 /*
965  * RNDIS filter on device add
966  */
967 int
968 hv_rf_on_device_add(struct hv_device *device, void *additl_info,
969     int nchan)
970 {
971         int ret;
972         netvsc_dev *net_dev;
973         rndis_device *rndis_dev;
974         nvsp_msg *init_pkt;
975         rndis_offload_params offloads;
976         struct rndis_recv_scale_cap rsscaps;
977         uint32_t rsscaps_size = sizeof(struct rndis_recv_scale_cap);
978         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
979         device_t dev = device->device;
980
981         rndis_dev = hv_get_rndis_device();
982         if (rndis_dev == NULL) {
983                 return (ENOMEM);
984         }
985
986         /*
987          * Let the inner driver handle this first to create the netvsc channel
988          * NOTE! Once the channel is created, we may get a receive callback 
989          * (hv_rf_on_receive()) before this call is completed.
990          * Note:  Earlier code used a function pointer here.
991          */
992         net_dev = hv_nv_on_device_add(device, additl_info);
993         if (!net_dev) {
994                 hv_put_rndis_device(rndis_dev);
995
996                 return (ENOMEM);
997         }
998
999         /*
1000          * Initialize the rndis device
1001          */
1002
1003         net_dev->extension = rndis_dev;
1004         rndis_dev->net_dev = net_dev;
1005
1006         /* Send the rndis initialization message */
1007         ret = hv_rf_init_device(rndis_dev);
1008         if (ret != 0) {
1009                 /*
1010                  * TODO: If rndis init failed, we will need to shut down
1011                  * the channel
1012                  */
1013         }
1014
1015         /* Get the mac address */
1016         ret = hv_rf_query_device_mac(rndis_dev);
1017         if (ret != 0) {
1018                 /* TODO: shut down rndis device and the channel */
1019         }
1020
1021         /* config csum offload and send request to host */
1022         memset(&offloads, 0, sizeof(offloads));
1023         offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1024         offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1025         offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1026         offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1027         offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
1028         offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
1029
1030         ret = hv_rf_send_offload_request(device, &offloads);
1031         if (ret != 0) {
1032                 /* TODO: shut down rndis device and the channel */
1033                 device_printf(dev,
1034                     "hv_rf_send_offload_request failed, ret=%d\n", ret);
1035         }
1036         
1037         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
1038
1039         hv_rf_query_device_link_status(rndis_dev);
1040         
1041         dev_info->link_state = rndis_dev->link_status;
1042
1043         net_dev->num_channel = 1;
1044         if (net_dev->nvsp_version < NVSP_PROTOCOL_VERSION_5 || nchan == 1)
1045                 return (0);
1046
1047         memset(&rsscaps, 0, rsscaps_size);
1048         ret = hv_rf_query_device(rndis_dev,
1049                         RNDIS_OID_GEN_RSS_CAPABILITIES,
1050                         &rsscaps, &rsscaps_size);
1051         if ((ret != 0) || (rsscaps.num_recv_que < 2)) {
1052                 device_printf(dev, "hv_rf_query_device failed or "
1053                         "rsscaps.num_recv_que < 2 \n");
1054                 goto out;
1055         }
1056         device_printf(dev, "channel, offered %u, requested %d\n",
1057             rsscaps.num_recv_que, nchan);
1058         if (nchan > rsscaps.num_recv_que)
1059                 nchan = rsscaps.num_recv_que;
1060         net_dev->num_channel = nchan;
1061
1062         if (net_dev->num_channel == 1) {
1063                 device_printf(dev, "net_dev->num_channel == 1 under VRSS\n");
1064                 goto out;
1065         }
1066         
1067         /* request host to create sub channels */
1068         init_pkt = &net_dev->channel_init_packet;
1069         memset(init_pkt, 0, sizeof(nvsp_msg));
1070
1071         init_pkt->hdr.msg_type = nvsp_msg5_type_subchannel;
1072         init_pkt->msgs.vers_5_msgs.subchannel_request.op =
1073             NVSP_SUBCHANNE_ALLOCATE;
1074         init_pkt->msgs.vers_5_msgs.subchannel_request.num_subchannels =
1075             net_dev->num_channel - 1;
1076
1077         ret = hv_vmbus_channel_send_packet(device->channel, init_pkt,
1078             sizeof(nvsp_msg), (uint64_t)(uintptr_t)init_pkt,
1079             HV_VMBUS_PACKET_TYPE_DATA_IN_BAND,
1080             HV_VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
1081         if (ret != 0) {
1082                 device_printf(dev, "Fail to allocate subchannel\n");
1083                 goto out;
1084         }
1085
1086         sema_wait(&net_dev->channel_init_sema);
1087
1088         if (init_pkt->msgs.vers_5_msgs.subchn_complete.status !=
1089             nvsp_status_success) {
1090                 ret = ENODEV;
1091                 device_printf(dev, "sub channel complete error\n");
1092                 goto out;
1093         }
1094
1095         net_dev->num_channel = 1 +
1096             init_pkt->msgs.vers_5_msgs.subchn_complete.num_subchannels;
1097
1098         ret = hv_rf_set_rss_param(rndis_dev, net_dev->num_channel);
1099
1100 out:
1101         if (ret)
1102                 net_dev->num_channel = 1;
1103
1104         return (ret);
1105 }
1106
1107 /*
1108  * RNDIS filter on device remove
1109  */
1110 int
1111 hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
1112 {
1113         hn_softc_t *sc = device_get_softc(device->device);
1114         netvsc_dev *net_dev = sc->net_dev;
1115         rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
1116         int ret;
1117
1118         /* Halt and release the rndis device */
1119         ret = hv_rf_halt_device(rndis_dev);
1120
1121         hv_put_rndis_device(rndis_dev);
1122         net_dev->extension = NULL;
1123
1124         /* Pass control to inner driver to remove the device */
1125         ret |= hv_nv_on_device_remove(device, destroy_channel);
1126
1127         return (ret);
1128 }
1129
1130 /*
1131  * RNDIS filter on open
1132  */
1133 int
1134 hv_rf_on_open(struct hv_device *device)
1135 {
1136         hn_softc_t *sc = device_get_softc(device->device);      
1137         netvsc_dev *net_dev = sc->net_dev;
1138
1139         return (hv_rf_open_device((rndis_device *)net_dev->extension));
1140 }
1141
1142 /*
1143  * RNDIS filter on close
1144  */
1145 int 
1146 hv_rf_on_close(struct hv_device *device)
1147 {
1148         hn_softc_t *sc = device_get_softc(device->device);      
1149         netvsc_dev *net_dev = sc->net_dev;
1150
1151         return (hv_rf_close_device((rndis_device *)net_dev->extension));
1152 }
1153
1154 /*
1155  * RNDIS filter on send request completion callback
1156  */
1157 static void 
1158 hv_rf_on_send_request_completion(struct hv_vmbus_channel *chan __unused,
1159     void *context __unused)
1160 {
1161 }
1162
1163 /*
1164  * RNDIS filter on send request (halt only) completion callback
1165  */
1166 static void 
1167 hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *chan __unused,
1168     void *context)
1169 {
1170         rndis_request *request = context;
1171
1172         /*
1173          * Notify hv_rf_halt_device() about halt completion.
1174          * The halt code must wait for completion before freeing
1175          * the transaction resources.
1176          */
1177         request->halt_complete_flag = 1;
1178 }
1179
1180 void
1181 hv_rf_channel_rollup(struct hv_vmbus_channel *chan)
1182 {
1183
1184         netvsc_channel_rollup(chan);
1185 }