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