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