]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/hyperv/netvsc/hv_rndis_filter.c
MFC 296379,296380,296381,296593,296594,296595
[FreeBSD/stable/10.git] / sys / dev / hyperv / netvsc / hv_rndis_filter.c
1 /*-
2  * Copyright (c) 2009-2012 Microsoft Corp.
3  * Copyright (c) 2010-2012 Citrix Inc.
4  * Copyright (c) 2012 NetApp Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/mbuf.h>
35 #include <sys/socket.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <net/if_arp.h>
39 #include <net/ethernet.h>
40 #include <sys/types.h>
41 #include <machine/atomic.h>
42 #include <sys/sema.h>
43 #include <vm/vm.h>
44 #include <vm/vm_param.h>
45 #include <vm/pmap.h>
46
47 #include <dev/hyperv/include/hyperv.h>
48 #include <dev/hyperv/vmbus/hv_vmbus_priv.h>
49 #include "hv_net_vsc.h"
50 #include "hv_rndis.h"
51 #include "hv_rndis_filter.h"
52
53
54 /*
55  * Forward declarations
56  */
57 static int  hv_rf_send_request(rndis_device *device, rndis_request *request,
58                                uint32_t message_type);
59 static void hv_rf_receive_response(rndis_device *device, rndis_msg *response);
60 static void hv_rf_receive_indicate_status(rndis_device *device,
61                                           rndis_msg *response);
62 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
63                                struct hv_vmbus_channel *chan,
64                                netvsc_packet *pkt);
65 static int  hv_rf_query_device(rndis_device *device, uint32_t oid,
66                                void *result, uint32_t *result_size);
67 static inline int hv_rf_query_device_mac(rndis_device *device);
68 static inline int hv_rf_query_device_link_status(rndis_device *device);
69 static int  hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
70 static int  hv_rf_init_device(rndis_device *device);
71 static int  hv_rf_open_device(rndis_device *device);
72 static int  hv_rf_close_device(rndis_device *device);
73 static void hv_rf_on_send_request_completion(struct hv_vmbus_channel *, void *context);
74 static void hv_rf_on_send_request_halt_completion(struct hv_vmbus_channel *, void *context);
75 int
76 hv_rf_send_offload_request(struct hv_device *device,
77     rndis_offload_params *offloads);
78 /*
79  * Set the Per-Packet-Info with the specified type
80  */
81 void *
82 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
83         int pkt_type)
84 {
85         rndis_packet *rndis_pkt;
86         rndis_per_packet_info *rppi;
87
88         rndis_pkt = &rndis_mesg->msg.packet;
89         rndis_pkt->data_offset += rppi_size;
90
91         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
92             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
93
94         rppi->size = rppi_size;
95         rppi->type = pkt_type;
96         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
97
98         rndis_pkt->per_pkt_info_length += rppi_size;
99
100         return (rppi);
101 }
102
103 /*
104  * Get the Per-Packet-Info with the specified type
105  * return NULL if not found.
106  */
107 void *
108 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
109 {
110         rndis_per_packet_info *ppi;
111         int len;
112
113         if (rpkt->per_pkt_info_offset == 0)
114                 return (NULL);
115
116         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
117             rpkt->per_pkt_info_offset);
118         len = rpkt->per_pkt_info_length;
119
120         while (len > 0) {
121                 if (ppi->type == type)
122                         return (void *)((unsigned long)ppi +
123                             ppi->per_packet_info_offset);
124
125                 len -= ppi->size;
126                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
127         }
128
129         return (NULL);
130 }
131
132
133 /*
134  * Allow module_param to work and override to switch to promiscuous mode.
135  */
136 static inline rndis_device *
137 hv_get_rndis_device(void)
138 {
139         rndis_device *device;
140
141         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
142
143         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
144
145         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
146         STAILQ_INIT(&device->myrequest_list);
147
148         device->state = RNDIS_DEV_UNINITIALIZED;
149
150         return (device);
151 }
152
153 /*
154  *
155  */
156 static inline void
157 hv_put_rndis_device(rndis_device *device)
158 {
159         mtx_destroy(&device->req_lock);
160         free(device, M_NETVSC);
161 }
162
163 /*
164  *
165  */
166 static inline rndis_request *
167 hv_rndis_request(rndis_device *device, uint32_t message_type,
168                  uint32_t message_length)
169 {
170         rndis_request *request;
171         rndis_msg *rndis_mesg;
172         rndis_set_request *set;
173
174         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
175
176         sema_init(&request->wait_sema, 0, "rndis sema");
177         
178         rndis_mesg = &request->request_msg;
179         rndis_mesg->ndis_msg_type = message_type;
180         rndis_mesg->msg_len = message_length;
181
182         /*
183          * Set the request id. This field is always after the rndis header
184          * for request/response packet types so we just use the set_request
185          * as a template.
186          */
187         set = &rndis_mesg->msg.set_request;
188         set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
189         /* Increment to get the new value (call above returns old value) */
190         set->request_id += 1;
191
192         /* Add to the request list */
193         mtx_lock(&device->req_lock);
194         STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
195         mtx_unlock(&device->req_lock);
196
197         return (request);
198 }
199
200 /*
201  *
202  */
203 static inline void
204 hv_put_rndis_request(rndis_device *device, rndis_request *request)
205 {
206         mtx_lock(&device->req_lock);
207         /* Fixme:  Has O(n) performance */
208         /*
209          * XXXKYS: Use Doubly linked lists.
210          */
211         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
212             mylist_entry);
213         mtx_unlock(&device->req_lock);
214
215         sema_destroy(&request->wait_sema);
216         free(request, M_NETVSC);
217 }
218
219 /*
220  *
221  */
222 static int
223 hv_rf_send_request(rndis_device *device, rndis_request *request,
224     uint32_t message_type)
225 {
226         int ret;
227         netvsc_packet *packet;
228         netvsc_dev      *net_dev = device->net_dev;
229         int send_buf_section_idx;
230
231         /* Set up the packet to send it */
232         packet = &request->pkt;
233         
234         packet->is_data_pkt = FALSE;
235         packet->tot_data_buf_len = request->request_msg.msg_len;
236         packet->page_buf_count = 1;
237
238         packet->page_buffers[0].pfn =
239             hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
240         packet->page_buffers[0].length = request->request_msg.msg_len;
241         packet->page_buffers[0].offset =
242             (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
243
244         if (packet->page_buffers[0].offset +
245                 packet->page_buffers[0].length > PAGE_SIZE) {
246                 packet->page_buf_count = 2;
247                 packet->page_buffers[0].length =
248                         PAGE_SIZE - packet->page_buffers[0].offset;
249                 packet->page_buffers[1].pfn =
250                         hv_get_phys_addr((char*)&request->request_msg +
251                                 packet->page_buffers[0].length) >> PAGE_SHIFT;
252                 packet->page_buffers[1].offset = 0;
253                 packet->page_buffers[1].length =
254                         request->request_msg.msg_len -
255                                 packet->page_buffers[0].length;
256         }
257
258         packet->compl.send.send_completion_context = request; /* packet */
259         if (message_type != REMOTE_NDIS_HALT_MSG) {
260                 packet->compl.send.on_send_completion =
261                     hv_rf_on_send_request_completion;
262         } else {
263                 packet->compl.send.on_send_completion =
264                     hv_rf_on_send_request_halt_completion;
265         }
266         packet->compl.send.send_completion_tid = (unsigned long)device;
267         if (packet->tot_data_buf_len < net_dev->send_section_size) {
268                 send_buf_section_idx = hv_nv_get_next_send_section(net_dev);
269                 if (send_buf_section_idx !=
270                         NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX) {
271                         char *dest = ((char *)net_dev->send_buf +
272                                 send_buf_section_idx * net_dev->send_section_size);
273
274                         memcpy(dest, &request->request_msg, request->request_msg.msg_len);
275                         packet->send_buf_section_idx = send_buf_section_idx;
276                         packet->send_buf_section_size = packet->tot_data_buf_len;
277                         packet->page_buf_count = 0;
278                         goto sendit;
279                 }
280                 /* Failed to allocate chimney send buffer; move on */
281         }
282         packet->send_buf_section_idx = NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
283         packet->send_buf_section_size = 0;
284
285 sendit:
286         ret = hv_nv_on_send(device->net_dev->dev->channel, packet);
287
288         return (ret);
289 }
290
291 /*
292  * RNDIS filter receive response
293  */
294 static void 
295 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
296 {
297         rndis_request *request = NULL;
298         rndis_request *next_request;
299         boolean_t found = FALSE;
300
301         mtx_lock(&device->req_lock);
302         request = STAILQ_FIRST(&device->myrequest_list);
303         while (request != NULL) {
304                 /*
305                  * All request/response message contains request_id as the
306                  * first field
307                  */
308                 if (request->request_msg.msg.init_request.request_id ==
309                                       response->msg.init_complete.request_id) {
310                         found = TRUE;
311                         break;
312                 }
313                 next_request = STAILQ_NEXT(request, mylist_entry);
314                 request = next_request;
315         }
316         mtx_unlock(&device->req_lock);
317
318         if (found) {
319                 if (response->msg_len <= sizeof(rndis_msg)) {
320                         memcpy(&request->response_msg, response,
321                             response->msg_len);
322                 } else {
323                         if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
324                                 /* Does not have a request id field */
325                                 request->response_msg.msg.reset_complete.status =
326                                     STATUS_BUFFER_OVERFLOW;
327                         } else {
328                                 request->response_msg.msg.init_complete.status =
329                                     STATUS_BUFFER_OVERFLOW;
330                         }
331                 }
332
333                 sema_post(&request->wait_sema);
334         }
335 }
336
337 int
338 hv_rf_send_offload_request(struct hv_device *device,
339     rndis_offload_params *offloads)
340 {
341         rndis_request *request;
342         rndis_set_request *set;
343         rndis_offload_params *offload_req;
344         rndis_set_complete *set_complete;       
345         rndis_device *rndis_dev;
346         hn_softc_t *sc = device_get_softc(device->device);
347         device_t dev = device->device;
348         netvsc_dev *net_dev = sc->net_dev;
349         uint32_t vsp_version = net_dev->nvsp_version;
350         uint32_t extlen = sizeof(rndis_offload_params);
351         int ret;
352
353         if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
354                 extlen = VERSION_4_OFFLOAD_SIZE;
355                 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
356                  * UDP checksum offload.
357                  */
358                 offloads->udp_ipv4_csum = 0;
359                 offloads->udp_ipv6_csum = 0;
360         }
361
362         rndis_dev = net_dev->extension;
363
364         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
365             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
366         if (!request)
367                 return (ENOMEM);
368
369         set = &request->request_msg.msg.set_request;
370         set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
371         set->info_buffer_length = extlen;
372         set->info_buffer_offset = sizeof(rndis_set_request);
373         set->device_vc_handle = 0;
374
375         offload_req = (rndis_offload_params *)((unsigned long)set +
376             set->info_buffer_offset);
377         *offload_req = *offloads;
378         offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
379         offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
380         offload_req->header.size = extlen;
381
382         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
383         if (ret != 0) {
384                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
385                     ret);
386                 goto cleanup;
387         }
388
389         ret = sema_timedwait(&request->wait_sema, 5 * hz);
390         if (ret != 0) {
391                 device_printf(dev, "hv send offload request timeout\n");
392                 goto cleanup;
393         }
394
395         set_complete = &request->response_msg.msg.set_complete;
396         if (set_complete->status == RNDIS_STATUS_SUCCESS) {
397                 device_printf(dev, "hv send offload request succeeded\n");
398                 ret = 0;
399         } else {
400                 if (set_complete->status == STATUS_NOT_SUPPORTED) {
401                         device_printf(dev, "HV Not support offload\n");
402                         ret = 0;
403                 } else {
404                         ret = set_complete->status;
405                 }
406         }
407
408 cleanup:
409         if (request)
410                 hv_put_rndis_request(rndis_dev, request);
411
412         return (ret);
413 }
414
415 /*
416  * RNDIS filter receive indicate status
417  */
418 static void 
419 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
420 {
421         rndis_indicate_status *indicate = &response->msg.indicate_status;
422                 
423         switch(indicate->status) {
424         case RNDIS_STATUS_MEDIA_CONNECT:
425                 netvsc_linkstatus_callback(device->net_dev->dev, 1);
426                 break;
427         case RNDIS_STATUS_MEDIA_DISCONNECT:
428                 netvsc_linkstatus_callback(device->net_dev->dev, 0);
429                 break;
430         default:
431                 /* TODO: */
432                 device_printf(device->net_dev->dev->device,
433                     "unknown status %d received\n", indicate->status);
434                 break;
435         }
436 }
437
438 /*
439  * RNDIS filter receive data
440  */
441 static void
442 hv_rf_receive_data(rndis_device *device, rndis_msg *message,
443     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
444 {
445         rndis_packet *rndis_pkt;
446         ndis_8021q_info *rppi_vlan_info;
447         uint32_t data_offset;
448         rndis_tcp_ip_csum_info *csum_info = NULL;
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         netvsc_recv(chan, pkt, csum_info);
482 }
483
484 /*
485  * RNDIS filter on receive
486  */
487 int
488 hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device,
489     struct hv_vmbus_channel *chan, netvsc_packet *pkt)
490 {
491         rndis_device *rndis_dev;
492         rndis_msg *rndis_hdr;
493
494         /* Make sure the rndis device state is initialized */
495         if (net_dev->extension == NULL) {
496                 pkt->status = nvsp_status_failure;
497                 return (ENODEV);
498         }
499
500         rndis_dev = (rndis_device *)net_dev->extension;
501         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
502                 pkt->status = nvsp_status_failure;
503                 return (EINVAL);
504         }
505
506         rndis_hdr = pkt->data;
507
508         switch (rndis_hdr->ndis_msg_type) {
509
510         /* data message */
511         case REMOTE_NDIS_PACKET_MSG:
512                 hv_rf_receive_data(rndis_dev, rndis_hdr, chan, pkt);
513                 break;
514         /* completion messages */
515         case REMOTE_NDIS_INITIALIZE_CMPLT:
516         case REMOTE_NDIS_QUERY_CMPLT:
517         case REMOTE_NDIS_SET_CMPLT:
518         case REMOTE_NDIS_RESET_CMPLT:
519         case REMOTE_NDIS_KEEPALIVE_CMPLT:
520                 hv_rf_receive_response(rndis_dev, rndis_hdr);
521                 break;
522         /* notification message */
523         case REMOTE_NDIS_INDICATE_STATUS_MSG:
524                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
525                 break;
526         default:
527                 printf("hv_rf_on_receive():  Unknown msg_type 0x%x\n",
528                         rndis_hdr->ndis_msg_type);
529                 break;
530         }
531
532         return (0);
533 }
534
535 /*
536  * RNDIS filter query device
537  */
538 static int
539 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
540                    uint32_t *result_size)
541 {
542         rndis_request *request;
543         uint32_t in_result_size = *result_size;
544         rndis_query_request *query;
545         rndis_query_complete *query_complete;
546         int ret = 0;
547
548         *result_size = 0;
549         request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
550             RNDIS_MESSAGE_SIZE(rndis_query_request));
551         if (request == NULL) {
552                 ret = -1;
553                 goto cleanup;
554         }
555
556         /* Set up the rndis query */
557         query = &request->request_msg.msg.query_request;
558         query->oid = oid;
559         query->info_buffer_offset = sizeof(rndis_query_request); 
560         query->info_buffer_length = 0;
561         query->device_vc_handle = 0;
562
563         if (oid == RNDIS_OID_GEN_RSS_CAPABILITIES) {
564                 struct rndis_recv_scale_cap *cap;
565
566                 request->request_msg.msg_len += 
567                         sizeof(struct rndis_recv_scale_cap);
568                 query->info_buffer_length = sizeof(struct rndis_recv_scale_cap);
569                 cap = (struct rndis_recv_scale_cap *)((unsigned long)query + 
570                                                 query->info_buffer_offset);
571                 cap->hdr.type = RNDIS_OBJECT_TYPE_RSS_CAPABILITIES;
572                 cap->hdr.rev = RNDIS_RECEIVE_SCALE_CAPABILITIES_REVISION_2;
573                 cap->hdr.size = sizeof(struct rndis_recv_scale_cap);
574         }
575
576         ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
577         if (ret != 0) {
578                 /* Fixme:  printf added */
579                 printf("RNDISFILTER request failed to Send!\n");
580                 goto cleanup;
581         }
582
583         sema_wait(&request->wait_sema);
584
585         /* Copy the response back */
586         query_complete = &request->response_msg.msg.query_complete;
587         
588         if (query_complete->info_buffer_length > in_result_size) {
589                 ret = EINVAL;
590                 goto cleanup;
591         }
592
593         memcpy(result, (void *)((unsigned long)query_complete +
594             query_complete->info_buffer_offset),
595             query_complete->info_buffer_length);
596
597         *result_size = query_complete->info_buffer_length;
598
599 cleanup:
600         if (request != NULL)
601                 hv_put_rndis_request(device, request);
602
603         return (ret);
604 }
605
606 /*
607  * RNDIS filter query device MAC address
608  */
609 static inline int
610 hv_rf_query_device_mac(rndis_device *device)
611 {
612         uint32_t size = HW_MACADDR_LEN;
613
614         return (hv_rf_query_device(device,
615             RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
616 }
617
618 /*
619  * RNDIS filter query device link status
620  */
621 static inline int
622 hv_rf_query_device_link_status(rndis_device *device)
623 {
624         uint32_t size = sizeof(uint32_t);
625
626         return (hv_rf_query_device(device,
627             RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
628 }
629
630 static uint8_t netvsc_hash_key[HASH_KEYLEN] = {
631         0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
632         0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
633         0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b, 0x30, 0xb4,
634         0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30, 0xf2, 0x0c,
635         0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
636 };
637
638 /*
639  * RNDIS set vRSS parameters
640  */
641 static int
642 hv_rf_set_rss_param(rndis_device *device, int num_queue)
643 {
644         rndis_request *request;
645         rndis_set_request *set;
646         rndis_set_complete *set_complete;
647         rndis_recv_scale_param *rssp;
648         uint32_t extlen = sizeof(rndis_recv_scale_param) +
649             (4 * ITAB_NUM) + HASH_KEYLEN;
650         uint32_t *itab, status;
651         uint8_t *keyp;
652         int i, ret;
653
654
655         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
656             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
657         if (request == NULL) {
658                 if (bootverbose)
659                         printf("Netvsc: No memory to set vRSS parameters.\n");
660                 ret = -1;
661                 goto cleanup;
662         }
663
664         set = &request->request_msg.msg.set_request;
665         set->oid = RNDIS_OID_GEN_RSS_PARAMETERS;
666         set->info_buffer_length = extlen;
667         set->info_buffer_offset = sizeof(rndis_set_request);
668         set->device_vc_handle = 0;
669
670         /* Fill out the rssp parameter structure */
671         rssp = (rndis_recv_scale_param *)(set + 1);
672         rssp->hdr.type = RNDIS_OBJECT_TYPE_RSS_PARAMETERS;
673         rssp->hdr.rev = RNDIS_RECEIVE_SCALE_PARAMETERS_REVISION_2;
674         rssp->hdr.size = sizeof(rndis_recv_scale_param);
675         rssp->flag = 0;
676         rssp->hashinfo = RNDIS_HASH_FUNC_TOEPLITZ | RNDIS_HASH_IPV4 |
677             RNDIS_HASH_TCP_IPV4 | RNDIS_HASH_IPV6 | RNDIS_HASH_TCP_IPV6;
678         rssp->indirect_tabsize = 4 * ITAB_NUM;
679         rssp->indirect_taboffset = sizeof(rndis_recv_scale_param);
680         rssp->hashkey_size = HASH_KEYLEN;
681         rssp->hashkey_offset = rssp->indirect_taboffset +
682             rssp->indirect_tabsize;
683
684         /* Set indirection table entries */
685         itab = (uint32_t *)(rssp + 1);
686         for (i = 0; i < ITAB_NUM; i++)
687                 itab[i] = i % num_queue;
688
689         /* Set hash key values */
690         keyp = (uint8_t *)((unsigned long)rssp + rssp->hashkey_offset);
691         for (i = 0; i < HASH_KEYLEN; i++)
692                 keyp[i] = netvsc_hash_key[i];
693
694         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
695         if (ret != 0) {
696                 goto cleanup;
697         }
698
699         /*
700          * Wait for the response from the host.  Another thread will signal
701          * us when the response has arrived.  In the failure case,
702          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
703          */
704         ret = sema_timedwait(&request->wait_sema, 5 * hz);
705         if (ret == 0) {
706                 /* Response received, check status */
707                 set_complete = &request->response_msg.msg.set_complete;
708                 status = set_complete->status;
709                 if (status != RNDIS_STATUS_SUCCESS) {
710                         /* Bad response status, return error */
711                         if (bootverbose)
712                                 printf("Netvsc: Failed to set vRSS "
713                                     "parameters.\n");
714                         ret = -2;
715                 } else {
716                         if (bootverbose)
717                                 printf("Netvsc: Successfully set vRSS "
718                                     "parameters.\n");
719                 }
720         } else {
721                 /*
722                  * We cannot deallocate the request since we may still
723                  * receive a send completion for it.
724                  */
725                 printf("Netvsc: vRSS set timeout, id = %u, ret = %d\n",
726                     request->request_msg.msg.init_request.request_id, ret);
727                 goto exit;
728         }
729
730 cleanup:
731         if (request != NULL) {
732                 hv_put_rndis_request(device, request);
733         }
734 exit:
735         return (ret);
736 }
737
738 /*
739  * RNDIS filter set packet filter
740  * Sends an rndis request with the new filter, then waits for a response
741  * from the host.
742  * Returns zero on success, non-zero on failure.
743  */
744 static int
745 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
746 {
747         rndis_request *request;
748         rndis_set_request *set;
749         rndis_set_complete *set_complete;
750         uint32_t status;
751         int ret;
752
753         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
754             RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
755         if (request == NULL) {
756                 ret = -1;
757                 goto cleanup;
758         }
759
760         /* Set up the rndis set */
761         set = &request->request_msg.msg.set_request;
762         set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
763         set->info_buffer_length = sizeof(uint32_t);
764         set->info_buffer_offset = sizeof(rndis_set_request); 
765
766         memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
767             &new_filter, sizeof(uint32_t));
768
769         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
770         if (ret != 0) {
771                 goto cleanup;
772         }
773
774         /*
775          * Wait for the response from the host.  Another thread will signal
776          * us when the response has arrived.  In the failure case,
777          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
778          */
779         ret = sema_timedwait(&request->wait_sema, 5 * hz);
780         if (ret == 0) {
781                 /* Response received, check status */
782                 set_complete = &request->response_msg.msg.set_complete;
783                 status = set_complete->status;
784                 if (status != RNDIS_STATUS_SUCCESS) {
785                         /* Bad response status, return error */
786                         ret = -2;
787                 }
788         } else {
789                 /*
790                  * We cannot deallocate the request since we may still
791                  * receive a send completion for it.
792                  */
793                 goto exit;
794         }
795
796 cleanup:
797         if (request != NULL) {
798                 hv_put_rndis_request(device, request);
799         }
800 exit:
801         return (ret);
802 }
803
804 /*
805  * RNDIS filter init device
806  */
807 static int
808 hv_rf_init_device(rndis_device *device)
809 {
810         rndis_request *request;
811         rndis_initialize_request *init;
812         rndis_initialize_complete *init_complete;
813         uint32_t status;
814         int ret;
815
816         request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
817             RNDIS_MESSAGE_SIZE(rndis_initialize_request));
818         if (!request) {
819                 ret = -1;
820                 goto cleanup;
821         }
822
823         /* Set up the rndis set */
824         init = &request->request_msg.msg.init_request;
825         init->major_version = RNDIS_MAJOR_VERSION;
826         init->minor_version = RNDIS_MINOR_VERSION;
827         /*
828          * Per the RNDIS document, this should be set to the max MTU
829          * plus the header size.  However, 2048 works fine, so leaving
830          * it as is.
831          */
832         init->max_xfer_size = 2048;
833         
834         device->state = RNDIS_DEV_INITIALIZING;
835
836         ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
837         if (ret != 0) {
838                 device->state = RNDIS_DEV_UNINITIALIZED;
839                 goto cleanup;
840         }
841
842         sema_wait(&request->wait_sema);
843
844         init_complete = &request->response_msg.msg.init_complete;
845         status = init_complete->status;
846         if (status == RNDIS_STATUS_SUCCESS) {
847                 device->state = RNDIS_DEV_INITIALIZED;
848                 ret = 0;
849         } else {
850                 device->state = RNDIS_DEV_UNINITIALIZED; 
851                 ret = -1;
852         }
853
854 cleanup:
855         if (request) {
856                 hv_put_rndis_request(device, request);
857         }
858
859         return (ret);
860 }
861
862 #define HALT_COMPLETION_WAIT_COUNT      25
863
864 /*
865  * RNDIS filter halt device
866  */
867 static int
868 hv_rf_halt_device(rndis_device *device)
869 {
870         rndis_request *request;
871         rndis_halt_request *halt;
872         int i, ret;
873
874         /* Attempt to do a rndis device halt */
875         request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
876             RNDIS_MESSAGE_SIZE(rndis_halt_request));
877         if (request == NULL) {
878                 return (-1);
879         }
880
881         /* initialize "poor man's semaphore" */
882         request->halt_complete_flag = 0;
883
884         /* Set up the rndis set */
885         halt = &request->request_msg.msg.halt_request;
886         halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
887         /* Increment to get the new value (call above returns old value) */
888         halt->request_id += 1;
889         
890         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
891         if (ret != 0) {
892                 return (-1);
893         }
894
895         /*
896          * Wait for halt response from halt callback.  We must wait for
897          * the transaction response before freeing the request and other
898          * resources.
899          */
900         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
901                 if (request->halt_complete_flag != 0) {
902                         break;
903                 }
904                 DELAY(400);
905         }
906         if (i == 0) {
907                 return (-1);
908         }
909
910         device->state = RNDIS_DEV_UNINITIALIZED;
911         
912         if (request != NULL) {
913                 hv_put_rndis_request(device, request);
914         }
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 }