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 |
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); |
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
|