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