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