hyperv: Use WAITOK in the places where we can wait
[freebsd.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/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 "hv_net_vsc.h"
48 #include "hv_rndis.h"
49 #include "hv_rndis_filter.h"
50
51
52 /*
53  * Forward declarations
54  */
55 static int  hv_rf_send_request(rndis_device *device, rndis_request *request,
56                                uint32_t message_type);
57 static void hv_rf_receive_response(rndis_device *device, rndis_msg *response);
58 static void hv_rf_receive_indicate_status(rndis_device *device,
59                                           rndis_msg *response);
60 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
61                                netvsc_packet *pkt);
62 static int  hv_rf_query_device(rndis_device *device, uint32_t oid,
63                                void *result, uint32_t *result_size);
64 static inline int hv_rf_query_device_mac(rndis_device *device);
65 static inline int hv_rf_query_device_link_status(rndis_device *device);
66 static int  hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter);
67 static int  hv_rf_init_device(rndis_device *device);
68 static int  hv_rf_open_device(rndis_device *device);
69 static int  hv_rf_close_device(rndis_device *device);
70 static void hv_rf_on_send_request_completion(void *context);
71 static void hv_rf_on_send_request_halt_completion(void *context);
72 int
73 hv_rf_send_offload_request(struct hv_device *device,
74     rndis_offload_params *offloads);
75 /*
76  * Set the Per-Packet-Info with the specified type
77  */
78 void *
79 hv_set_rppi_data(rndis_msg *rndis_mesg, uint32_t rppi_size,
80         int pkt_type)
81 {
82         rndis_packet *rndis_pkt;
83         rndis_per_packet_info *rppi;
84
85         rndis_pkt = &rndis_mesg->msg.packet;
86         rndis_pkt->data_offset += rppi_size;
87
88         rppi = (rndis_per_packet_info *)((char *)rndis_pkt +
89             rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_length);
90
91         rppi->size = rppi_size;
92         rppi->type = pkt_type;
93         rppi->per_packet_info_offset = sizeof(rndis_per_packet_info);
94
95         rndis_pkt->per_pkt_info_length += rppi_size;
96
97         return (rppi);
98 }
99
100 /*
101  * Get the Per-Packet-Info with the specified type
102  * return NULL if not found.
103  */
104 void *
105 hv_get_ppi_data(rndis_packet *rpkt, uint32_t type)
106 {
107         rndis_per_packet_info *ppi;
108         int len;
109
110         if (rpkt->per_pkt_info_offset == 0)
111                 return (NULL);
112
113         ppi = (rndis_per_packet_info *)((unsigned long)rpkt +
114             rpkt->per_pkt_info_offset);
115         len = rpkt->per_pkt_info_length;
116
117         while (len > 0) {
118                 if (ppi->type == type)
119                         return (void *)((unsigned long)ppi +
120                             ppi->per_packet_info_offset);
121
122                 len -= ppi->size;
123                 ppi = (rndis_per_packet_info *)((unsigned long)ppi + ppi->size);
124         }
125
126         return (NULL);
127 }
128
129
130 /*
131  * Allow module_param to work and override to switch to promiscuous mode.
132  */
133 static inline rndis_device *
134 hv_get_rndis_device(void)
135 {
136         rndis_device *device;
137
138         device = malloc(sizeof(rndis_device), M_NETVSC, M_WAITOK | M_ZERO);
139
140         mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_DEF);
141
142         /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
143         STAILQ_INIT(&device->myrequest_list);
144
145         device->state = RNDIS_DEV_UNINITIALIZED;
146
147         return (device);
148 }
149
150 /*
151  *
152  */
153 static inline void
154 hv_put_rndis_device(rndis_device *device)
155 {
156         mtx_destroy(&device->req_lock);
157         free(device, M_NETVSC);
158 }
159
160 /*
161  *
162  */
163 static inline rndis_request *
164 hv_rndis_request(rndis_device *device, uint32_t message_type,
165                  uint32_t message_length)
166 {
167         rndis_request *request;
168         rndis_msg *rndis_mesg;
169         rndis_set_request *set;
170
171         request = malloc(sizeof(rndis_request), M_NETVSC, M_WAITOK | M_ZERO);
172
173         sema_init(&request->wait_sema, 0, "rndis sema");
174         
175         rndis_mesg = &request->request_msg;
176         rndis_mesg->ndis_msg_type = message_type;
177         rndis_mesg->msg_len = message_length;
178
179         /*
180          * Set the request id. This field is always after the rndis header
181          * for request/response packet types so we just use the set_request
182          * as a template.
183          */
184         set = &rndis_mesg->msg.set_request;
185         set->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
186         /* Increment to get the new value (call above returns old value) */
187         set->request_id += 1;
188
189         /* Add to the request list */
190         mtx_lock(&device->req_lock);
191         STAILQ_INSERT_TAIL(&device->myrequest_list, request, mylist_entry);
192         mtx_unlock(&device->req_lock);
193
194         return (request);
195 }
196
197 /*
198  *
199  */
200 static inline void
201 hv_put_rndis_request(rndis_device *device, rndis_request *request)
202 {
203         mtx_lock(&device->req_lock);
204         /* Fixme:  Has O(n) performance */
205         /*
206          * XXXKYS: Use Doubly linked lists.
207          */
208         STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
209             mylist_entry);
210         mtx_unlock(&device->req_lock);
211
212         sema_destroy(&request->wait_sema);
213         free(request, M_NETVSC);
214 }
215
216 /*
217  *
218  */
219 static int
220 hv_rf_send_request(rndis_device *device, rndis_request *request,
221     uint32_t message_type)
222 {
223         int ret;
224         netvsc_packet *packet;
225
226         /* Set up the packet to send it */
227         packet = &request->pkt;
228         
229         packet->is_data_pkt = FALSE;
230         packet->tot_data_buf_len = request->request_msg.msg_len;
231         packet->page_buf_count = 1;
232
233         packet->page_buffers[0].pfn =
234             hv_get_phys_addr(&request->request_msg) >> PAGE_SHIFT;
235         packet->page_buffers[0].length = request->request_msg.msg_len;
236         packet->page_buffers[0].offset =
237             (unsigned long)&request->request_msg & (PAGE_SIZE - 1);
238
239         packet->compl.send.send_completion_context = request; /* packet */
240         if (message_type != REMOTE_NDIS_HALT_MSG) {
241                 packet->compl.send.on_send_completion =
242                     hv_rf_on_send_request_completion;
243         } else {
244                 packet->compl.send.on_send_completion =
245                     hv_rf_on_send_request_halt_completion;
246         }
247         packet->compl.send.send_completion_tid = (unsigned long)device;
248         packet->send_buf_section_idx =
249             NVSP_1_CHIMNEY_SEND_INVALID_SECTION_INDEX;
250         packet->send_buf_section_size = 0;
251
252         ret = hv_nv_on_send(device->net_dev->dev, packet);
253
254         return (ret);
255 }
256
257 /*
258  * RNDIS filter receive response
259  */
260 static void 
261 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
262 {
263         rndis_request *request = NULL;
264         rndis_request *next_request;
265         boolean_t found = FALSE;
266
267         mtx_lock(&device->req_lock);
268         request = STAILQ_FIRST(&device->myrequest_list);
269         while (request != NULL) {
270                 /*
271                  * All request/response message contains request_id as the
272                  * first field
273                  */
274                 if (request->request_msg.msg.init_request.request_id ==
275                                       response->msg.init_complete.request_id) {
276                         found = TRUE;
277                         break;
278                 }
279                 next_request = STAILQ_NEXT(request, mylist_entry);
280                 request = next_request;
281         }
282         mtx_unlock(&device->req_lock);
283
284         if (found) {
285                 if (response->msg_len <= sizeof(rndis_msg)) {
286                         memcpy(&request->response_msg, response,
287                             response->msg_len);
288                 } else {
289                         if (response->ndis_msg_type == REMOTE_NDIS_RESET_CMPLT) {
290                                 /* Does not have a request id field */
291                                 request->response_msg.msg.reset_complete.status =
292                                     STATUS_BUFFER_OVERFLOW;
293                         } else {
294                                 request->response_msg.msg.init_complete.status =
295                                     STATUS_BUFFER_OVERFLOW;
296                         }
297                 }
298
299                 sema_post(&request->wait_sema);
300         }
301 }
302
303 int
304 hv_rf_send_offload_request(struct hv_device *device,
305     rndis_offload_params *offloads)
306 {
307         rndis_request *request;
308         rndis_set_request *set;
309         rndis_offload_params *offload_req;
310         rndis_set_complete *set_complete;       
311         rndis_device *rndis_dev;
312         hn_softc_t *sc = device_get_softc(device->device);
313         device_t dev = device->device;
314         netvsc_dev *net_dev = sc->net_dev;
315         uint32_t vsp_version = net_dev->nvsp_version;
316         uint32_t extlen = sizeof(rndis_offload_params);
317         int ret;
318
319         if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
320                 extlen = VERSION_4_OFFLOAD_SIZE;
321                 /* On NVSP_PROTOCOL_VERSION_4 and below, we do not support
322                  * UDP checksum offload.
323                  */
324                 offloads->udp_ipv4_csum = 0;
325                 offloads->udp_ipv6_csum = 0;
326         }
327
328         rndis_dev = net_dev->extension;
329
330         request = hv_rndis_request(rndis_dev, REMOTE_NDIS_SET_MSG,
331             RNDIS_MESSAGE_SIZE(rndis_set_request) + extlen);
332         if (!request)
333                 return (ENOMEM);
334
335         set = &request->request_msg.msg.set_request;
336         set->oid = RNDIS_OID_TCP_OFFLOAD_PARAMETERS;
337         set->info_buffer_length = extlen;
338         set->info_buffer_offset = sizeof(rndis_set_request);
339         set->device_vc_handle = 0;
340
341         offload_req = (rndis_offload_params *)((unsigned long)set +
342             set->info_buffer_offset);
343         *offload_req = *offloads;
344         offload_req->header.type = RNDIS_OBJECT_TYPE_DEFAULT;
345         offload_req->header.revision = RNDIS_OFFLOAD_PARAMETERS_REVISION_3;
346         offload_req->header.size = extlen;
347
348         ret = hv_rf_send_request(rndis_dev, request, REMOTE_NDIS_SET_MSG);
349         if (ret != 0) {
350                 device_printf(dev, "hv send offload request failed, ret=%d!\n",
351                     ret);
352                 goto cleanup;
353         }
354
355         ret = sema_timedwait(&request->wait_sema, 500);
356         if (ret != 0) {
357                 device_printf(dev, "hv send offload request timeout\n");
358                 goto cleanup;
359         }
360
361         set_complete = &request->response_msg.msg.set_complete;
362         if (set_complete->status == RNDIS_STATUS_SUCCESS) {
363                 device_printf(dev, "hv send offload request succeeded\n");
364                 ret = 0;
365         } else {
366                 if (set_complete->status == STATUS_NOT_SUPPORTED) {
367                         device_printf(dev, "HV Not support offload\n");
368                         ret = 0;
369                 } else {
370                         ret = set_complete->status;
371                 }
372         }
373
374 cleanup:
375         if (request)
376                 hv_put_rndis_request(rndis_dev, request);
377
378         return (ret);
379 }
380
381 /*
382  * RNDIS filter receive indicate status
383  */
384 static void 
385 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
386 {
387         rndis_indicate_status *indicate = &response->msg.indicate_status;
388                 
389         switch(indicate->status) {
390         case RNDIS_STATUS_MEDIA_CONNECT:
391                 netvsc_linkstatus_callback(device->net_dev->dev, 1);
392                 break;
393         case RNDIS_STATUS_MEDIA_DISCONNECT:
394                 netvsc_linkstatus_callback(device->net_dev->dev, 0);
395                 break;
396         default:
397                 /* TODO: */
398                 device_printf(device->net_dev->dev->device,
399                     "unknown status %d received\n", indicate->status);
400                 break;
401         }
402 }
403
404 /*
405  * RNDIS filter receive data
406  */
407 static void
408 hv_rf_receive_data(rndis_device *device, rndis_msg *message, netvsc_packet *pkt)
409 {
410         rndis_packet *rndis_pkt;
411         ndis_8021q_info *rppi_vlan_info;
412         uint32_t data_offset;
413         rndis_tcp_ip_csum_info *csum_info = NULL;
414         device_t dev = device->net_dev->dev->device;
415
416         rndis_pkt = &message->msg.packet;
417
418         /*
419          * Fixme:  Handle multiple rndis pkt msgs that may be enclosed in this
420          * netvsc packet (ie tot_data_buf_len != message_length)
421          */
422
423         /* Remove rndis header, then pass data packet up the stack */
424         data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
425
426         pkt->tot_data_buf_len -= data_offset;
427         if (pkt->tot_data_buf_len < rndis_pkt->data_length) {
428                 pkt->status = nvsp_status_failure;
429                 device_printf(dev,
430                     "total length %u is less than data length %u\n",
431                     pkt->tot_data_buf_len, rndis_pkt->data_length);
432                 return;
433         }
434
435         pkt->tot_data_buf_len = rndis_pkt->data_length;
436         pkt->data = (void *)((unsigned long)pkt->data + data_offset);
437
438         rppi_vlan_info = hv_get_ppi_data(rndis_pkt, ieee_8021q_info);
439         if (rppi_vlan_info) {
440                 pkt->vlan_tci = rppi_vlan_info->u1.s1.vlan_id;
441         } else {
442                 pkt->vlan_tci = 0;
443         }
444
445         csum_info = hv_get_ppi_data(rndis_pkt, tcpip_chksum_info);
446         netvsc_recv(device->net_dev->dev, pkt, csum_info);
447 }
448
449 /*
450  * RNDIS filter on receive
451  */
452 int
453 hv_rf_on_receive(netvsc_dev *net_dev, struct hv_device *device, netvsc_packet *pkt)
454 {
455         rndis_device *rndis_dev;
456         rndis_msg *rndis_hdr;
457
458         /* Make sure the rndis device state is initialized */
459         if (net_dev->extension == NULL) {
460                 pkt->status = nvsp_status_failure;
461                 return (ENODEV);
462         }
463
464         rndis_dev = (rndis_device *)net_dev->extension;
465         if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
466                 pkt->status = nvsp_status_failure;
467                 return (EINVAL);
468         }
469
470         rndis_hdr = pkt->data;
471
472         switch (rndis_hdr->ndis_msg_type) {
473
474         /* data message */
475         case REMOTE_NDIS_PACKET_MSG:
476                 hv_rf_receive_data(rndis_dev, rndis_hdr, pkt);
477                 break;
478         /* completion messages */
479         case REMOTE_NDIS_INITIALIZE_CMPLT:
480         case REMOTE_NDIS_QUERY_CMPLT:
481         case REMOTE_NDIS_SET_CMPLT:
482         case REMOTE_NDIS_RESET_CMPLT:
483         case REMOTE_NDIS_KEEPALIVE_CMPLT:
484                 hv_rf_receive_response(rndis_dev, rndis_hdr);
485                 break;
486         /* notification message */
487         case REMOTE_NDIS_INDICATE_STATUS_MSG:
488                 hv_rf_receive_indicate_status(rndis_dev, rndis_hdr);
489                 break;
490         default:
491                 printf("hv_rf_on_receive():  Unknown msg_type 0x%x\n",
492                         rndis_hdr->ndis_msg_type);
493                 break;
494         }
495
496         return (0);
497 }
498
499 /*
500  * RNDIS filter query device
501  */
502 static int
503 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
504                    uint32_t *result_size)
505 {
506         rndis_request *request;
507         uint32_t in_result_size = *result_size;
508         rndis_query_request *query;
509         rndis_query_complete *query_complete;
510         int ret = 0;
511
512         *result_size = 0;
513         request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
514             RNDIS_MESSAGE_SIZE(rndis_query_request));
515         if (request == NULL) {
516                 ret = -1;
517                 goto cleanup;
518         }
519
520         /* Set up the rndis query */
521         query = &request->request_msg.msg.query_request;
522         query->oid = oid;
523         query->info_buffer_offset = sizeof(rndis_query_request); 
524         query->info_buffer_length = 0;
525         query->device_vc_handle = 0;
526
527         ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
528         if (ret != 0) {
529                 /* Fixme:  printf added */
530                 printf("RNDISFILTER request failed to Send!\n");
531                 goto cleanup;
532         }
533
534         sema_wait(&request->wait_sema);
535
536         /* Copy the response back */
537         query_complete = &request->response_msg.msg.query_complete;
538         
539         if (query_complete->info_buffer_length > in_result_size) {
540                 ret = EINVAL;
541                 goto cleanup;
542         }
543
544         memcpy(result, (void *)((unsigned long)query_complete +
545             query_complete->info_buffer_offset),
546             query_complete->info_buffer_length);
547
548         *result_size = query_complete->info_buffer_length;
549
550 cleanup:
551         if (request != NULL)
552                 hv_put_rndis_request(device, request);
553
554         return (ret);
555 }
556
557 /*
558  * RNDIS filter query device MAC address
559  */
560 static inline int
561 hv_rf_query_device_mac(rndis_device *device)
562 {
563         uint32_t size = HW_MACADDR_LEN;
564
565         return (hv_rf_query_device(device,
566             RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
567 }
568
569 /*
570  * RNDIS filter query device link status
571  */
572 static inline int
573 hv_rf_query_device_link_status(rndis_device *device)
574 {
575         uint32_t size = sizeof(uint32_t);
576
577         return (hv_rf_query_device(device,
578             RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
579 }
580
581 /*
582  * RNDIS filter set packet filter
583  * Sends an rndis request with the new filter, then waits for a response
584  * from the host.
585  * Returns zero on success, non-zero on failure.
586  */
587 static int
588 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
589 {
590         rndis_request *request;
591         rndis_set_request *set;
592         rndis_set_complete *set_complete;
593         uint32_t status;
594         int ret;
595
596         request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
597             RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
598         if (request == NULL) {
599                 ret = -1;
600                 goto cleanup;
601         }
602
603         /* Set up the rndis set */
604         set = &request->request_msg.msg.set_request;
605         set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
606         set->info_buffer_length = sizeof(uint32_t);
607         set->info_buffer_offset = sizeof(rndis_set_request); 
608
609         memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
610             &new_filter, sizeof(uint32_t));
611
612         ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
613         if (ret != 0) {
614                 goto cleanup;
615         }
616
617         /*
618          * Wait for the response from the host.  Another thread will signal
619          * us when the response has arrived.  In the failure case,
620          * sema_timedwait() returns a non-zero status after waiting 5 seconds.
621          */
622         ret = sema_timedwait(&request->wait_sema, 500);
623         if (ret == 0) {
624                 /* Response received, check status */
625                 set_complete = &request->response_msg.msg.set_complete;
626                 status = set_complete->status;
627                 if (status != RNDIS_STATUS_SUCCESS) {
628                         /* Bad response status, return error */
629                         ret = -2;
630                 }
631         } else {
632                 /*
633                  * We cannot deallocate the request since we may still
634                  * receive a send completion for it.
635                  */
636                 goto exit;
637         }
638
639 cleanup:
640         if (request != NULL) {
641                 hv_put_rndis_request(device, request);
642         }
643 exit:
644         return (ret);
645 }
646
647 /*
648  * RNDIS filter init device
649  */
650 static int
651 hv_rf_init_device(rndis_device *device)
652 {
653         rndis_request *request;
654         rndis_initialize_request *init;
655         rndis_initialize_complete *init_complete;
656         uint32_t status;
657         int ret;
658
659         request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
660             RNDIS_MESSAGE_SIZE(rndis_initialize_request));
661         if (!request) {
662                 ret = -1;
663                 goto cleanup;
664         }
665
666         /* Set up the rndis set */
667         init = &request->request_msg.msg.init_request;
668         init->major_version = RNDIS_MAJOR_VERSION;
669         init->minor_version = RNDIS_MINOR_VERSION;
670         /*
671          * Per the RNDIS document, this should be set to the max MTU
672          * plus the header size.  However, 2048 works fine, so leaving
673          * it as is.
674          */
675         init->max_xfer_size = 2048;
676         
677         device->state = RNDIS_DEV_INITIALIZING;
678
679         ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
680         if (ret != 0) {
681                 device->state = RNDIS_DEV_UNINITIALIZED;
682                 goto cleanup;
683         }
684
685         sema_wait(&request->wait_sema);
686
687         init_complete = &request->response_msg.msg.init_complete;
688         status = init_complete->status;
689         if (status == RNDIS_STATUS_SUCCESS) {
690                 device->state = RNDIS_DEV_INITIALIZED;
691                 ret = 0;
692         } else {
693                 device->state = RNDIS_DEV_UNINITIALIZED; 
694                 ret = -1;
695         }
696
697 cleanup:
698         if (request) {
699                 hv_put_rndis_request(device, request);
700         }
701
702         return (ret);
703 }
704
705 #define HALT_COMPLETION_WAIT_COUNT      25
706
707 /*
708  * RNDIS filter halt device
709  */
710 static int
711 hv_rf_halt_device(rndis_device *device)
712 {
713         rndis_request *request;
714         rndis_halt_request *halt;
715         int i, ret;
716
717         /* Attempt to do a rndis device halt */
718         request = hv_rndis_request(device, REMOTE_NDIS_HALT_MSG,
719             RNDIS_MESSAGE_SIZE(rndis_halt_request));
720         if (request == NULL) {
721                 return (-1);
722         }
723
724         /* initialize "poor man's semaphore" */
725         request->halt_complete_flag = 0;
726
727         /* Set up the rndis set */
728         halt = &request->request_msg.msg.halt_request;
729         halt->request_id = atomic_fetchadd_int(&device->new_request_id, 1);
730         /* Increment to get the new value (call above returns old value) */
731         halt->request_id += 1;
732         
733         ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
734         if (ret != 0) {
735                 return (-1);
736         }
737
738         /*
739          * Wait for halt response from halt callback.  We must wait for
740          * the transaction response before freeing the request and other
741          * resources.
742          */
743         for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
744                 if (request->halt_complete_flag != 0) {
745                         break;
746                 }
747                 DELAY(400);
748         }
749         if (i == 0) {
750                 return (-1);
751         }
752
753         device->state = RNDIS_DEV_UNINITIALIZED;
754         
755         if (request != NULL) {
756                 hv_put_rndis_request(device, request);
757         }
758
759         return (0);
760 }
761
762 /*
763  * RNDIS filter open device
764  */
765 static int
766 hv_rf_open_device(rndis_device *device)
767 {
768         int ret;
769
770         if (device->state != RNDIS_DEV_INITIALIZED) {
771                 return (0);
772         }
773
774         if (hv_promisc_mode != 1) {
775                 ret = hv_rf_set_packet_filter(device, 
776                     NDIS_PACKET_TYPE_BROADCAST     |
777                     NDIS_PACKET_TYPE_ALL_MULTICAST |
778                     NDIS_PACKET_TYPE_DIRECTED);
779         } else {
780                 ret = hv_rf_set_packet_filter(device, 
781                     NDIS_PACKET_TYPE_PROMISCUOUS);
782         }
783
784         if (ret == 0) {
785                 device->state = RNDIS_DEV_DATAINITIALIZED;
786         }
787
788         return (ret);
789 }
790
791 /*
792  * RNDIS filter close device
793  */
794 static int
795 hv_rf_close_device(rndis_device *device)
796 {
797         int ret;
798
799         if (device->state != RNDIS_DEV_DATAINITIALIZED) {
800                 return (0);
801         }
802
803         ret = hv_rf_set_packet_filter(device, 0);
804         if (ret == 0) {
805                 device->state = RNDIS_DEV_INITIALIZED;
806         }
807
808         return (ret);
809 }
810
811 /*
812  * RNDIS filter on device add
813  */
814 int
815 hv_rf_on_device_add(struct hv_device *device, void *additl_info)
816 {
817         int ret;
818         netvsc_dev *net_dev;
819         rndis_device *rndis_dev;
820         rndis_offload_params offloads;
821         netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
822         device_t dev = device->device;
823
824         rndis_dev = hv_get_rndis_device();
825         if (rndis_dev == NULL) {
826                 return (ENOMEM);
827         }
828
829         /*
830          * Let the inner driver handle this first to create the netvsc channel
831          * NOTE! Once the channel is created, we may get a receive callback 
832          * (hv_rf_on_receive()) before this call is completed.
833          * Note:  Earlier code used a function pointer here.
834          */
835         net_dev = hv_nv_on_device_add(device, additl_info);
836         if (!net_dev) {
837                 hv_put_rndis_device(rndis_dev);
838
839                 return (ENOMEM);
840         }
841
842         /*
843          * Initialize the rndis device
844          */
845
846         net_dev->extension = rndis_dev;
847         rndis_dev->net_dev = net_dev;
848
849         /* Send the rndis initialization message */
850         ret = hv_rf_init_device(rndis_dev);
851         if (ret != 0) {
852                 /*
853                  * TODO: If rndis init failed, we will need to shut down
854                  * the channel
855                  */
856         }
857
858         /* Get the mac address */
859         ret = hv_rf_query_device_mac(rndis_dev);
860         if (ret != 0) {
861                 /* TODO: shut down rndis device and the channel */
862         }
863
864         /* config csum offload and send request to host */
865         memset(&offloads, 0, sizeof(offloads));
866         offloads.ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
867         offloads.tcp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
868         offloads.udp_ipv4_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
869         offloads.tcp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
870         offloads.udp_ipv6_csum = RNDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED;
871         offloads.lso_v2_ipv4 = RNDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED;
872
873         ret = hv_rf_send_offload_request(device, &offloads);
874         if (ret != 0) {
875                 /* TODO: shut down rndis device and the channel */
876                 device_printf(dev,
877                     "hv_rf_send_offload_request failed, ret=%d\n", ret);
878         }
879         
880         memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
881
882         hv_rf_query_device_link_status(rndis_dev);
883         
884         dev_info->link_state = rndis_dev->link_status;
885
886         return (ret);
887 }
888
889 /*
890  * RNDIS filter on device remove
891  */
892 int
893 hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
894 {
895         hn_softc_t *sc = device_get_softc(device->device);
896         netvsc_dev *net_dev = sc->net_dev;
897         rndis_device *rndis_dev = (rndis_device *)net_dev->extension;
898         int ret;
899
900         /* Halt and release the rndis device */
901         ret = hv_rf_halt_device(rndis_dev);
902
903         hv_put_rndis_device(rndis_dev);
904         net_dev->extension = NULL;
905
906         /* Pass control to inner driver to remove the device */
907         ret |= hv_nv_on_device_remove(device, destroy_channel);
908
909         return (ret);
910 }
911
912 /*
913  * RNDIS filter on open
914  */
915 int
916 hv_rf_on_open(struct hv_device *device)
917 {
918         hn_softc_t *sc = device_get_softc(device->device);      
919         netvsc_dev *net_dev = sc->net_dev;
920
921         return (hv_rf_open_device((rndis_device *)net_dev->extension));
922 }
923
924 /*
925  * RNDIS filter on close
926  */
927 int 
928 hv_rf_on_close(struct hv_device *device)
929 {
930         hn_softc_t *sc = device_get_softc(device->device);      
931         netvsc_dev *net_dev = sc->net_dev;
932
933         return (hv_rf_close_device((rndis_device *)net_dev->extension));
934 }
935
936 /*
937  * RNDIS filter on send request completion callback
938  */
939 static void 
940 hv_rf_on_send_request_completion(void *context)
941 {
942 }
943
944 /*
945  * RNDIS filter on send request (halt only) completion callback
946  */
947 static void 
948 hv_rf_on_send_request_halt_completion(void *context)
949 {
950         rndis_request *request = context;
951
952         /*
953          * Notify hv_rf_halt_device() about halt completion.
954          * The halt code must wait for completion before freeing
955          * the transaction resources.
956          */
957         request->halt_complete_flag = 1;
958 }
959
960 /*
961  * RNDIS filter when "all" reception is done
962  */
963 void
964 hv_rf_receive_rollup(netvsc_dev *net_dev)
965 {
966         rndis_device *rndis_dev;
967
968         rndis_dev = (rndis_device *)net_dev->extension;
969         netvsc_recv_rollup(rndis_dev->net_dev->dev);
970 }
971
972 void
973 hv_rf_channel_rollup(netvsc_dev *net_dev)
974 {
975         rndis_device *rndis_dev;
976
977         rndis_dev = (rndis_device *)net_dev->extension;
978
979         /*
980          * This could be called pretty early, so we need
981          * to make sure everything has been setup.
982          */
983         if (rndis_dev == NULL ||
984             rndis_dev->net_dev == NULL ||
985             rndis_dev->net_dev->dev == NULL)
986                 return;
987         netvsc_channel_rollup(rndis_dev->net_dev->dev);
988 }