2 * Copyright (c) 2009-2012 Microsoft Corp.
3 * Copyright (c) 2010-2012 Citrix Inc.
4 * Copyright (c) 2012 NetApp Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
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.
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.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
34 #include <sys/socket.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>
43 #include <vm/vm_param.h>
46 #include <dev/hyperv/include/hyperv.h>
47 #include "hv_net_vsc.h"
49 #include "hv_rndis_filter.h"
53 * Forward declarations
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,
60 static void hv_rf_receive_data(rndis_device *device, rndis_msg *message,
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);
76 * Allow module_param to work and override to switch to promiscuous mode.
78 static inline rndis_device *
79 hv_get_rndis_device(void)
83 device = malloc(sizeof(rndis_device), M_DEVBUF, M_NOWAIT | M_ZERO);
88 mtx_init(&device->req_lock, "HV-FRL", NULL, MTX_SPIN | MTX_RECURSE);
90 /* Same effect as STAILQ_HEAD_INITIALIZER() static initializer */
91 STAILQ_INIT(&device->myrequest_list);
93 device->state = RNDIS_DEV_UNINITIALIZED;
102 hv_put_rndis_device(rndis_device *device)
104 mtx_destroy(&device->req_lock);
105 free(device, M_DEVBUF);
111 static inline rndis_request *
112 hv_rndis_request(rndis_device *device, uint32_t message_type,
113 uint32_t message_length)
115 rndis_request *request;
116 rndis_msg *rndis_mesg;
117 rndis_set_request *set;
119 request = malloc(sizeof(rndis_request), M_DEVBUF, M_NOWAIT | M_ZERO);
120 if (request == NULL) {
124 sema_init(&request->wait_sema, 0, "rndis sema");
126 rndis_mesg = &request->request_msg;
127 rndis_mesg->ndis_msg_type = message_type;
128 rndis_mesg->msg_len = message_length;
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
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;
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);
152 hv_put_rndis_request(rndis_device *device, rndis_request *request)
154 mtx_lock_spin(&device->req_lock);
155 /* Fixme: Has O(n) performance */
157 * XXXKYS: Use Doubly linked lists.
159 STAILQ_REMOVE(&device->myrequest_list, request, rndis_request_,
161 mtx_unlock_spin(&device->req_lock);
163 sema_destroy(&request->wait_sema);
164 free(request, M_DEVBUF);
171 hv_rf_send_request(rndis_device *device, rndis_request *request,
172 uint32_t message_type)
175 netvsc_packet *packet;
177 /* Set up the packet to send it */
178 packet = &request->pkt;
180 packet->is_data_pkt = FALSE;
181 packet->tot_data_buf_len = request->request_msg.msg_len;
182 packet->page_buf_count = 1;
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);
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;
195 packet->compl.send.on_send_completion =
196 hv_rf_on_send_request_halt_completion;
198 packet->compl.send.send_completion_tid = (unsigned long)device;
200 ret = hv_nv_on_send(device->net_dev->dev, packet);
206 * RNDIS filter receive response
209 hv_rf_receive_response(rndis_device *device, rndis_msg *response)
211 rndis_request *request = NULL;
212 rndis_request *next_request;
213 boolean_t found = FALSE;
215 mtx_lock_spin(&device->req_lock);
216 request = STAILQ_FIRST(&device->myrequest_list);
217 while (request != NULL) {
219 * All request/response message contains request_id as the
222 if (request->request_msg.msg.init_request.request_id ==
223 response->msg.init_complete.request_id) {
227 next_request = STAILQ_NEXT(request, mylist_entry);
228 request = next_request;
230 mtx_unlock_spin(&device->req_lock);
233 if (response->msg_len <= sizeof(rndis_msg)) {
234 memcpy(&request->response_msg, response,
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;
242 request->response_msg.msg.init_complete.status =
243 STATUS_BUFFER_OVERFLOW;
247 sema_post(&request->wait_sema);
252 * RNDIS filter receive indicate status
255 hv_rf_receive_indicate_status(rndis_device *device, rndis_msg *response)
257 rndis_indicate_status *indicate = &response->msg.indicate_status;
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);
269 * RNDIS filter receive data
272 hv_rf_receive_data(rndis_device *device, rndis_msg *message, netvsc_packet *pkt)
274 rndis_packet *rndis_pkt;
275 rndis_per_packet_info *rppi;
276 ndis_8021q_info *rppi_vlan_info;
277 uint32_t data_offset;
279 rndis_pkt = &message->msg.packet;
282 * Fixme: Handle multiple rndis pkt msgs that may be enclosed in this
283 * netvsc packet (ie tot_data_buf_len != message_length)
286 /* Remove rndis header, then pass data packet up the stack */
287 data_offset = RNDIS_HEADER_SIZE + rndis_pkt->data_offset;
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;
295 pkt->is_data_pkt = TRUE;
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.
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;
316 netvsc_recv(device->net_dev->dev, pkt);
320 * RNDIS filter on receive
323 hv_rf_on_receive(struct hv_device *device, netvsc_packet *pkt)
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;
331 /* Make sure the rndis device state is initialized */
332 if (net_dev->extension == NULL)
335 rndis_dev = (rndis_device *)net_dev->extension;
336 if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED)
339 /* Shift virtual page number to form virtual page address */
340 rndis_hdr = (rndis_msg *)(uintptr_t)(pkt->page_buffers[0].pfn << PAGE_SHIFT);
342 rndis_hdr = (void *)((unsigned long)rndis_hdr
343 + pkt->page_buffers[0].offset);
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
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);
362 memcpy(&rndis_mesg, rndis_hdr,
363 (rndis_hdr->msg_len > sizeof(rndis_msg)) ?
364 sizeof(rndis_msg) : rndis_hdr->msg_len);
366 switch (rndis_mesg.ndis_msg_type) {
369 case REMOTE_NDIS_PACKET_MSG:
370 hv_rf_receive_data(rndis_dev, &rndis_mesg, pkt);
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);
380 /* notification message */
381 case REMOTE_NDIS_INDICATE_STATUS_MSG:
382 hv_rf_receive_indicate_status(rndis_dev, &rndis_mesg);
385 printf("hv_rf_on_receive(): Unknown msg_type 0x%x\n",
386 rndis_mesg.ndis_msg_type);
394 * RNDIS filter query device
397 hv_rf_query_device(rndis_device *device, uint32_t oid, void *result,
398 uint32_t *result_size)
400 rndis_request *request;
401 uint32_t in_result_size = *result_size;
402 rndis_query_request *query;
403 rndis_query_complete *query_complete;
407 request = hv_rndis_request(device, REMOTE_NDIS_QUERY_MSG,
408 RNDIS_MESSAGE_SIZE(rndis_query_request));
409 if (request == NULL) {
414 /* Set up the rndis query */
415 query = &request->request_msg.msg.query_request;
417 query->info_buffer_offset = sizeof(rndis_query_request);
418 query->info_buffer_length = 0;
419 query->device_vc_handle = 0;
421 ret = hv_rf_send_request(device, request, REMOTE_NDIS_QUERY_MSG);
423 /* Fixme: printf added */
424 printf("RNDISFILTER request failed to Send!\n");
428 sema_wait(&request->wait_sema);
430 /* Copy the response back */
431 query_complete = &request->response_msg.msg.query_complete;
433 if (query_complete->info_buffer_length > in_result_size) {
438 memcpy(result, (void *)((unsigned long)query_complete +
439 query_complete->info_buffer_offset),
440 query_complete->info_buffer_length);
442 *result_size = query_complete->info_buffer_length;
446 hv_put_rndis_request(device, request);
452 * RNDIS filter query device MAC address
455 hv_rf_query_device_mac(rndis_device *device)
457 uint32_t size = HW_MACADDR_LEN;
459 return (hv_rf_query_device(device,
460 RNDIS_OID_802_3_PERMANENT_ADDRESS, device->hw_mac_addr, &size));
464 * RNDIS filter query device link status
467 hv_rf_query_device_link_status(rndis_device *device)
469 uint32_t size = sizeof(uint32_t);
471 return (hv_rf_query_device(device,
472 RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, &device->link_status, &size));
476 * RNDIS filter set packet filter
477 * Sends an rndis request with the new filter, then waits for a response
479 * Returns zero on success, non-zero on failure.
482 hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter)
484 rndis_request *request;
485 rndis_set_request *set;
486 rndis_set_complete *set_complete;
490 request = hv_rndis_request(device, REMOTE_NDIS_SET_MSG,
491 RNDIS_MESSAGE_SIZE(rndis_set_request) + sizeof(uint32_t));
492 if (request == NULL) {
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);
503 memcpy((void *)((unsigned long)set + sizeof(rndis_set_request)),
504 &new_filter, sizeof(uint32_t));
506 ret = hv_rf_send_request(device, request, REMOTE_NDIS_SET_MSG);
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.
516 ret = sema_timedwait(&request->wait_sema, 500);
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 */
527 * We cannot deallocate the request since we may still
528 * receive a send completion for it.
534 if (request != NULL) {
535 hv_put_rndis_request(device, request);
542 * RNDIS filter init device
545 hv_rf_init_device(rndis_device *device)
547 rndis_request *request;
548 rndis_initialize_request *init;
549 rndis_initialize_complete *init_complete;
553 request = hv_rndis_request(device, REMOTE_NDIS_INITIALIZE_MSG,
554 RNDIS_MESSAGE_SIZE(rndis_initialize_request));
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;
565 * Per the RNDIS document, this should be set to the max MTU
566 * plus the header size. However, 2048 works fine, so leaving
569 init->max_xfer_size = 2048;
571 device->state = RNDIS_DEV_INITIALIZING;
573 ret = hv_rf_send_request(device, request, REMOTE_NDIS_INITIALIZE_MSG);
575 device->state = RNDIS_DEV_UNINITIALIZED;
579 sema_wait(&request->wait_sema);
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;
587 device->state = RNDIS_DEV_UNINITIALIZED;
593 hv_put_rndis_request(device, request);
599 #define HALT_COMPLETION_WAIT_COUNT 25
602 * RNDIS filter halt device
605 hv_rf_halt_device(rndis_device *device)
607 rndis_request *request;
608 rndis_halt_request *halt;
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) {
618 /* initialize "poor man's semaphore" */
619 request->halt_complete_flag = 0;
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;
627 ret = hv_rf_send_request(device, request, REMOTE_NDIS_HALT_MSG);
633 * Wait for halt response from halt callback. We must wait for
634 * the transaction response before freeing the request and other
637 for (i=HALT_COMPLETION_WAIT_COUNT; i > 0; i--) {
638 if (request->halt_complete_flag != 0) {
647 device->state = RNDIS_DEV_UNINITIALIZED;
649 if (request != NULL) {
650 hv_put_rndis_request(device, request);
657 * RNDIS filter open device
660 hv_rf_open_device(rndis_device *device)
664 if (device->state != RNDIS_DEV_INITIALIZED) {
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);
674 ret = hv_rf_set_packet_filter(device,
675 NDIS_PACKET_TYPE_PROMISCUOUS);
679 device->state = RNDIS_DEV_DATAINITIALIZED;
686 * RNDIS filter close device
689 hv_rf_close_device(rndis_device *device)
693 if (device->state != RNDIS_DEV_DATAINITIALIZED) {
697 ret = hv_rf_set_packet_filter(device, 0);
699 device->state = RNDIS_DEV_INITIALIZED;
706 * RNDIS filter on device add
709 hv_rf_on_device_add(struct hv_device *device, void *additl_info)
713 rndis_device *rndis_dev;
714 netvsc_device_info *dev_info = (netvsc_device_info *)additl_info;
716 rndis_dev = hv_get_rndis_device();
717 if (rndis_dev == NULL) {
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.
727 net_dev = hv_nv_on_device_add(device, additl_info);
729 hv_put_rndis_device(rndis_dev);
735 * Initialize the rndis device
738 net_dev->extension = rndis_dev;
739 rndis_dev->net_dev = net_dev;
741 /* Send the rndis initialization message */
742 ret = hv_rf_init_device(rndis_dev);
745 * TODO: If rndis init failed, we will need to shut down
750 /* Get the mac address */
751 ret = hv_rf_query_device_mac(rndis_dev);
753 /* TODO: shut down rndis device and the channel */
756 memcpy(dev_info->mac_addr, rndis_dev->hw_mac_addr, HW_MACADDR_LEN);
758 hv_rf_query_device_link_status(rndis_dev);
760 dev_info->link_state = rndis_dev->link_status;
766 * RNDIS filter on device remove
769 hv_rf_on_device_remove(struct hv_device *device, boolean_t destroy_channel)
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;
776 /* Halt and release the rndis device */
777 ret = hv_rf_halt_device(rndis_dev);
779 hv_put_rndis_device(rndis_dev);
780 net_dev->extension = NULL;
782 /* Pass control to inner driver to remove the device */
783 ret |= hv_nv_on_device_remove(device, destroy_channel);
789 * RNDIS filter on open
792 hv_rf_on_open(struct hv_device *device)
794 hn_softc_t *sc = device_get_softc(device->device);
795 netvsc_dev *net_dev = sc->net_dev;
797 return (hv_rf_open_device((rndis_device *)net_dev->extension));
801 * RNDIS filter on close
804 hv_rf_on_close(struct hv_device *device)
806 hn_softc_t *sc = device_get_softc(device->device);
807 netvsc_dev *net_dev = sc->net_dev;
809 return (hv_rf_close_device((rndis_device *)net_dev->extension));
813 * RNDIS filter on send
816 hv_rf_on_send(struct hv_device *device, netvsc_packet *pkt)
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;
826 /* Add the rndis header */
827 filter_pkt = (rndis_filter_packet *)pkt->extension;
829 memset(filter_pkt, 0, sizeof(rndis_filter_packet));
831 rndis_mesg = &filter_pkt->message;
832 rndis_msg_size = RNDIS_MESSAGE_SIZE(rndis_packet);
834 if (pkt->vlan_tci != 0) {
835 rndis_msg_size += sizeof(rndis_per_packet_info) +
836 sizeof(ndis_8021q_info);
839 rndis_mesg->ndis_msg_type = REMOTE_NDIS_PACKET_MSG;
840 rndis_mesg->msg_len = pkt->tot_data_buf_len + rndis_msg_size;
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;
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;
852 /* Save the packet context */
853 filter_pkt->completion_context =
854 pkt->compl.send.send_completion_context;
857 pkt->compl.send.on_send_completion = hv_rf_on_send_completion;
858 pkt->compl.send.send_completion_context = filter_pkt;
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
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);
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);
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);
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;
889 * Invoke netvsc send. If return status is bad, the caller now
890 * resets the context pointers before retrying.
892 ret = hv_nv_on_send(device, pkt);
898 * RNDIS filter on send completion callback
901 hv_rf_on_send_completion(void *context)
903 rndis_filter_packet *filter_pkt = (rndis_filter_packet *)context;
905 /* Pass it back to the original handler */
906 netvsc_xmit_completion(filter_pkt->completion_context);
910 * RNDIS filter on send request completion callback
913 hv_rf_on_send_request_completion(void *context)
918 * RNDIS filter on send request (halt only) completion callback
921 hv_rf_on_send_request_halt_completion(void *context)
923 rndis_request *request = context;
926 * Notify hv_rf_halt_device() about halt completion.
927 * The halt code must wait for completion before freeing
928 * the transaction resources.
930 request->halt_complete_flag = 1;