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