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
| 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: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c 266794 2014-05-28 09:06:36Z marius $"); 31
|
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 */ 52static int hv_rf_send_request(rndis_device *device, rndis_request *request, 53 uint32_t message_type); 54static void hv_rf_receive_response(rndis_device *device, rndis_msg *response); 55static void hv_rf_receive_indicate_status(rndis_device *device, 56 rndis_msg *response); 57static void hv_rf_receive_data(rndis_device *device, rndis_msg *message, 58 netvsc_packet *pkt); 59static int hv_rf_query_device(rndis_device *device, uint32_t oid, 60 void *result, uint32_t *result_size); 61static inline int hv_rf_query_device_mac(rndis_device *device); 62static inline int hv_rf_query_device_link_status(rndis_device *device); 63static int hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter); 64static int hv_rf_init_device(rndis_device *device); 65static int hv_rf_open_device(rndis_device *device); 66static int hv_rf_close_device(rndis_device *device); 67static void hv_rf_on_send_completion(void *context); 68static void hv_rf_on_send_request_completion(void *context); 69static 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 */ 75static inline rndis_device * 76hv_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 */ 98static inline void 99hv_put_rndis_device(rndis_device *device) 100{ 101 mtx_destroy(&device->req_lock); 102 free(device, M_DEVBUF); 103} 104 105/* 106 * 107 */ 108static inline rndis_request * 109hv_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 */ 148static inline void 149hv_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 */ 167static int 168hv_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 */ 205static void 206hv_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 */ 251static void 252hv_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 */ 268static void 269hv_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 */ 319int 320hv_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 */
| 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 */ 55static int hv_rf_send_request(rndis_device *device, rndis_request *request, 56 uint32_t message_type); 57static void hv_rf_receive_response(rndis_device *device, rndis_msg *response); 58static void hv_rf_receive_indicate_status(rndis_device *device, 59 rndis_msg *response); 60static void hv_rf_receive_data(rndis_device *device, rndis_msg *message, 61 netvsc_packet *pkt); 62static int hv_rf_query_device(rndis_device *device, uint32_t oid, 63 void *result, uint32_t *result_size); 64static inline int hv_rf_query_device_mac(rndis_device *device); 65static inline int hv_rf_query_device_link_status(rndis_device *device); 66static int hv_rf_set_packet_filter(rndis_device *device, uint32_t new_filter); 67static int hv_rf_init_device(rndis_device *device); 68static int hv_rf_open_device(rndis_device *device); 69static int hv_rf_close_device(rndis_device *device); 70static void hv_rf_on_send_completion(void *context); 71static void hv_rf_on_send_request_completion(void *context); 72static 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 */ 78static inline rndis_device * 79hv_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 */ 101static inline void 102hv_put_rndis_device(rndis_device *device) 103{ 104 mtx_destroy(&device->req_lock); 105 free(device, M_DEVBUF); 106} 107 108/* 109 * 110 */ 111static inline rndis_request * 112hv_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 */ 151static inline void 152hv_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 */ 170static int 171hv_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 */ 208static void 209hv_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 */ 254static void 255hv_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 */ 271static void 272hv_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 */ 322int 323hv_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 */
|
337 rndis_hdr = (rndis_msg *)(pkt->page_buffers[0].pfn << PAGE_SHIFT);
| 340 rndis_hdr = (rndis_msg *)(uintptr_t)(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 */ 393static int 394hv_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 441cleanup: 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 */ 451static inline int 452hv_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 */ 463static inline int 464hv_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 */ 478static int 479hv_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 530cleanup: 531 if (request != NULL) { 532 hv_put_rndis_request(device, request); 533 } 534exit: 535 return (ret); 536} 537 538/* 539 * RNDIS filter init device 540 */ 541static int 542hv_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 588cleanup: 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 */ 601static int 602hv_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 */ 656static int 657hv_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 */ 685static int 686hv_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 */ 705int 706hv_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 */ 765int 766hv_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 */ 788int 789hv_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 */ 800int 801hv_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 */ 812int 813hv_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 */ 897static void 898hv_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 */ 909static void 910hv_rf_on_send_request_completion(void *context) 911{ 912} 913 914/* 915 * RNDIS filter on send request (halt only) completion callback 916 */ 917static void 918hv_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
| 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 */ 396static int 397hv_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 444cleanup: 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 */ 454static inline int 455hv_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 */ 466static inline int 467hv_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 */ 481static int 482hv_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 533cleanup: 534 if (request != NULL) { 535 hv_put_rndis_request(device, request); 536 } 537exit: 538 return (ret); 539} 540 541/* 542 * RNDIS filter init device 543 */ 544static int 545hv_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 591cleanup: 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 */ 604static int 605hv_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 */ 659static int 660hv_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 */ 688static int 689hv_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 */ 708int 709hv_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 */ 768int 769hv_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 */ 791int 792hv_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 */ 803int 804hv_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 */ 815int 816hv_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 */ 900static void 901hv_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 */ 912static void 913hv_rf_on_send_request_completion(void *context) 914{ 915} 916 917/* 918 * RNDIS filter on send request (halt only) completion callback 919 */ 920static void 921hv_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
|