1 /* 2 Driver for USB RNDIS Network devices 3 Copyright (C) 2022 Adrien Destugues <pulkomandy@pulkomandy.tk> 4 Distributed under the terms of the MIT license. 5 */ 6 #include <ether_driver.h> 7 #include <net/if_media.h> 8 #include <string.h> 9 #include <stdlib.h> 10 11 #include "RNDISDevice.h" 12 #include "Driver.h" 13 14 15 const uint32 OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106; 16 const uint32 OID_GEN_LINK_SPEED = 0x00010107; 17 const uint32 OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E; 18 const uint32 OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114; 19 const uint32 OID_802_3_PERMANENT_ADDRESS = 0x01010101; 20 21 22 enum RndisCommands { 23 REMOTE_NDIS_PACKET_MSG = 1, 24 REMOTE_NDIS_INITIALIZE_MSG = 2, 25 REMOTE_NDIS_INITIALIZE_CMPLT = 0x80000002, 26 REMOTE_NDIS_HALT_MSG = 3, 27 REMOTE_NDIS_QUERY_MSG = 4, 28 REMOTE_NDIS_QUERY_CMPLT = 0x80000004, 29 REMOTE_NDIS_SET_MSG = 5, 30 REMOTE_NDIS_SET_CMPLT = 0x80000005, 31 REMOTE_NDIS_RESET_MSG = 6, 32 REMOTE_NDIS_RESET_CMPLT = 0x80000006, 33 REMOTE_NDIS_INDICATE_STATUS_MSG = 7, 34 REMOTE_NDIS_KEEPALIVE_MSG = 8, 35 REMOTE_NDIS_KEEPALIVE_CMPLT = 0x80000008 36 }; 37 38 39 enum Status 40 { 41 RNDIS_STATUS_SUCCESS = 0, 42 RNDIS_STATUS_FAILURE = 0xC0000001, 43 RNDIS_STATUS_INVALID_DATA = 0xC0010015, 44 RNDIS_STATUS_NOT_SUPPORTED = 0xC00000BB, 45 RNDIS_STATUS_MEDIA_CONNECT = 0x4001000B, 46 RNDIS_STATUS_MEDIA_DISCONNECT = 0x4001000C, 47 }; 48 49 50 enum MediaConnectStatus 51 { 52 MEDIA_STATE_UNKNOWN, 53 MEDIA_STATE_CONNECTED, 54 MEDIA_STATE_DISCONNECTED 55 }; 56 57 58 const uint32 NDIS_PACKET_TYPE_ALL_MULTICAST = 0x00000004; 59 const uint32 NDIS_PACKET_TYPE_BROADCAST = 0x00000008; 60 61 62 63 RNDISDevice::RNDISDevice(usb_device device) 64 : fStatus(B_ERROR), 65 fOpen(false), 66 fRemoved(false), 67 fInsideNotify(0), 68 fDevice(device), 69 fDataInterfaceIndex(0), 70 fMaxSegmentSize(0), 71 fNotifyEndpoint(0), 72 fReadEndpoint(0), 73 fWriteEndpoint(0), 74 fNotifyReadSem(-1), 75 fNotifyWriteSem(-1), 76 fNotifyControlSem(-1), 77 fLinkStateChangeSem(-1), 78 fMediaConnectState(MEDIA_STATE_UNKNOWN), 79 fDownstreamSpeed(0) 80 { 81 const usb_device_descriptor *deviceDescriptor 82 = gUSBModule->get_device_descriptor(device); 83 84 if (deviceDescriptor == NULL) { 85 TRACE_ALWAYS("failed to get device descriptor\n"); 86 return; 87 } 88 89 fVendorID = deviceDescriptor->vendor_id; 90 fProductID = deviceDescriptor->product_id; 91 92 fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read"); 93 if (fNotifyReadSem < B_OK) { 94 TRACE_ALWAYS("failed to create read notify sem\n"); 95 return; 96 } 97 98 fNotifyWriteSem = create_sem(0, DRIVER_NAME"_notify_write"); 99 if (fNotifyWriteSem < B_OK) { 100 TRACE_ALWAYS("failed to create write notify sem\n"); 101 return; 102 } 103 104 fNotifyControlSem = create_sem(0, DRIVER_NAME"_notify_control"); 105 if (fNotifyControlSem < B_OK) { 106 TRACE_ALWAYS("failed to create control notify sem\n"); 107 return; 108 } 109 110 if (_SetupDevice() != B_OK) { 111 TRACE_ALWAYS("failed to setup device\n"); 112 return; 113 } 114 115 fStatus = B_OK; 116 } 117 118 119 RNDISDevice::~RNDISDevice() 120 { 121 if (fNotifyReadSem >= B_OK) 122 delete_sem(fNotifyReadSem); 123 if (fNotifyWriteSem >= B_OK) 124 delete_sem(fNotifyWriteSem); 125 126 if (!fRemoved) 127 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 128 } 129 130 131 status_t 132 RNDISDevice::Open() 133 { 134 if (fOpen) 135 return B_BUSY; 136 if (fRemoved) 137 return B_ERROR; 138 139 // reset the device by switching the data interface to the disabled first 140 // interface and then enable it by setting the second actual data interface 141 const usb_configuration_info *config 142 = gUSBModule->get_configuration(fDevice); 143 144 usb_interface_info *interface = config->interface[fDataInterfaceIndex].active; 145 if (interface->endpoint_count < 2) { 146 TRACE_ALWAYS("setting the data alternate interface failed\n"); 147 return B_ERROR; 148 } 149 150 if (!(interface->endpoint[0].descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)) 151 fWriteEndpoint = interface->endpoint[0].handle; 152 else 153 fReadEndpoint = interface->endpoint[0].handle; 154 155 if (interface->endpoint[1].descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) 156 fReadEndpoint = interface->endpoint[1].handle; 157 else 158 fWriteEndpoint = interface->endpoint[1].handle; 159 160 if (fReadEndpoint == 0 || fWriteEndpoint == 0) { 161 TRACE_ALWAYS("no read and write endpoints found\n"); 162 return B_ERROR; 163 } 164 165 if (gUSBModule->queue_interrupt(fNotifyEndpoint, &fNotifyBuffer, 166 sizeof(fNotifyBuffer), _NotifyCallback, this) != B_OK) { 167 TRACE_ALWAYS("failed to setup notification interrupt\n"); 168 return B_ERROR; 169 } 170 171 status_t status = _RNDISInitialize(); 172 if (status != B_OK) { 173 TRACE_ALWAYS("failed to read mac address\n"); 174 return status; 175 } 176 177 status = _ReadMACAddress(fDevice, fMACAddress); 178 if (status != B_OK) { 179 TRACE_ALWAYS("failed to read mac address\n"); 180 return status; 181 } 182 183 // TODO these are non-fatal but make sure we have sane defaults for them 184 status = _ReadMaxSegmentSize(fDevice); 185 if (status != B_OK) { 186 TRACE_ALWAYS("failed to read fragment siez\n"); 187 } 188 189 status = _ReadMediaState(fDevice); 190 if (status != B_OK) { 191 fMediaConnectState = MEDIA_STATE_CONNECTED; 192 TRACE_ALWAYS("failed to read media state\n"); 193 } 194 195 status = _ReadLinkSpeed(fDevice); 196 if (status != B_OK) { 197 fDownstreamSpeed = 1000 * 100; // 10Mbps 198 TRACE_ALWAYS("failed to read link speed\n"); 199 } 200 201 // Tell the device to connect 202 status = _EnableBroadcast(fDevice); 203 TRACE("Initialization result: %s\n", strerror(status)); 204 205 // the device should now be ready 206 if (status == B_OK) 207 fOpen = true; 208 return status; 209 } 210 211 212 status_t 213 RNDISDevice::Close() 214 { 215 if (fRemoved) { 216 fOpen = false; 217 return B_OK; 218 } 219 220 // TODO tell the device to disconnect? 221 222 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 223 gUSBModule->cancel_queued_transfers(fReadEndpoint); 224 gUSBModule->cancel_queued_transfers(fWriteEndpoint); 225 226 fOpen = false; 227 return B_OK; 228 } 229 230 231 status_t 232 RNDISDevice::Free() 233 { 234 return B_OK; 235 } 236 237 238 status_t 239 RNDISDevice::Read(uint8 *buffer, size_t *numBytes) 240 { 241 if (fRemoved) { 242 *numBytes = 0; 243 return B_DEVICE_NOT_FOUND; 244 } 245 246 iovec vec[2]; 247 uint32 header[11] = { 0 }; 248 249 vec[0].iov_base = &header; 250 vec[0].iov_len = sizeof(header); 251 252 vec[1].iov_base = buffer; 253 vec[1].iov_len = *numBytes; 254 255 status_t result = gUSBModule->queue_bulk_v(fReadEndpoint, vec, 2, 256 _ReadCallback, this); 257 if (result != B_OK) { 258 *numBytes = 0; 259 return result; 260 } 261 262 result = acquire_sem_etc(fNotifyReadSem, 1, B_CAN_INTERRUPT, 0); 263 if (result < B_OK) { 264 *numBytes = 0; 265 return result; 266 } 267 268 if (fStatusRead != B_OK && fStatusRead != B_CANCELED && !fRemoved) { 269 TRACE_ALWAYS("device status error 0x%08" B_PRIx32 "\n", fStatusRead); 270 result = gUSBModule->clear_feature(fReadEndpoint, 271 USB_FEATURE_ENDPOINT_HALT); 272 if (result != B_OK) { 273 TRACE_ALWAYS("failed to clear halt state on read\n"); 274 *numBytes = 0; 275 return result; 276 } 277 } 278 279 // TODO buffering is needed if we receive multiple packets, OOB data, etc since each Read 280 // call can only return one packet? (which isn't great and could be improved on network stack 281 // side to reduce syscalls if we had a readmmsg device call or something similar...) 282 283 if (header[0] != REMOTE_NDIS_PACKET_MSG) { 284 TRACE_ALWAYS("Received unexpected packet type %08" B_PRIx32 " on data link\n", header[0]); 285 *numBytes = 0; 286 return B_BAD_VALUE; 287 } 288 289 if (header[1] != fActualLengthRead) { 290 TRACE_ALWAYS("Received frame length %08" B_PRIx32 " but USB transfer length is %08" 291 B_PRIx32 "\n", header[1], fActualLengthRead); 292 } 293 294 if (header[4] != 0 || header[5] != 0 || header[6] != 0) { 295 TRACE_ALWAYS("Received frame has out of bound data: off %08" B_PRIx32 " len %08" B_PRIx32 296 " count %08" B_PRIx32 "\n", header[4], header[5], header[6]); 297 } 298 299 if (header[7] != 0 || header[8] != 0) { 300 TRACE_ALWAYS("Received frame has per-packet info: off %08" B_PRIx32 " len %08" B_PRIx32 301 "\n", header[7], header[8]); 302 } 303 304 if (header[9] != 0) { 305 TRACE_ALWAYS("Received frame has non-0 reserved fied %08x\n", header[9]); 306 } 307 308 *numBytes = header[3]; 309 310 TRACE("Received data packet len %08x data [off %08x len %08x]\n", 311 header[1], header[2], header[3]); 312 313 return B_OK; 314 } 315 316 317 status_t 318 RNDISDevice::Write(const uint8 *buffer, size_t *numBytes) 319 { 320 if (fRemoved) { 321 *numBytes = 0; 322 return B_DEVICE_NOT_FOUND; 323 } 324 325 iovec vec[2]; 326 327 uint32 header[11] = { 0 }; 328 header[0] = REMOTE_NDIS_PACKET_MSG; 329 header[1] = *numBytes + sizeof(header); 330 header[2] = 0x24; 331 header[3] = *numBytes; 332 333 vec[0].iov_base = &header; 334 vec[0].iov_len = sizeof(header); 335 336 vec[1].iov_base = (void*)buffer; 337 vec[1].iov_len = *numBytes; 338 339 status_t result = gUSBModule->queue_bulk_v(fWriteEndpoint, vec, 2, _WriteCallback, this); 340 if (result != B_OK) { 341 *numBytes = 0; 342 return result; 343 } 344 345 result = acquire_sem_etc(fNotifyWriteSem, 1, B_CAN_INTERRUPT, 0); 346 if (result < B_OK) { 347 *numBytes = 0; 348 return result; 349 } 350 351 if (fStatusWrite != B_OK && fStatusWrite != B_CANCELED && !fRemoved) { 352 TRACE_ALWAYS("device status error 0x%08" B_PRIx32 "\n", fStatusWrite); 353 result = gUSBModule->clear_feature(fWriteEndpoint, 354 USB_FEATURE_ENDPOINT_HALT); 355 if (result != B_OK) { 356 TRACE_ALWAYS("failed to clear halt state on write\n"); 357 *numBytes = 0; 358 return result; 359 } 360 } 361 362 *numBytes = fActualLengthWrite; 363 return B_OK; 364 } 365 366 367 status_t 368 RNDISDevice::Control(uint32 op, void *buffer, size_t length) 369 { 370 switch (op) { 371 case ETHER_INIT: 372 return B_OK; 373 374 case ETHER_GETADDR: 375 memcpy(buffer, &fMACAddress, sizeof(fMACAddress)); 376 return B_OK; 377 378 case ETHER_GETFRAMESIZE: 379 *(uint32 *)buffer = fMaxSegmentSize; 380 return B_OK; 381 382 case ETHER_SET_LINK_STATE_SEM: 383 fLinkStateChangeSem = *(sem_id *)buffer; 384 return B_OK; 385 386 case ETHER_GET_LINK_STATE: 387 { 388 ether_link_state *state = (ether_link_state *)buffer; 389 // FIXME get media duplex state from OID_GEN_LINK_STATE if supported 390 state->media = IFM_ETHER | IFM_FULL_DUPLEX; 391 if (fMediaConnectState != MEDIA_STATE_DISCONNECTED) 392 state->media |= IFM_ACTIVE; 393 state->quality = 1000; 394 state->speed = fDownstreamSpeed * 100; 395 return B_OK; 396 } 397 398 default: 399 TRACE_ALWAYS("unsupported ioctl %" B_PRIu32 "\n", op); 400 } 401 402 return B_DEV_INVALID_IOCTL; 403 } 404 405 406 void 407 RNDISDevice::Removed() 408 { 409 fRemoved = true; 410 fMediaConnectState = MEDIA_STATE_DISCONNECTED; 411 fDownstreamSpeed = 0; 412 413 // the notify hook is different from the read and write hooks as it does 414 // itself schedule traffic (while the other hooks only release a semaphore 415 // to notify another thread which in turn safly checks for the removed 416 // case) - so we must ensure that we are not inside the notify hook anymore 417 // before returning, as we would otherwise violate the promise not to use 418 // any of the pipes after returning from the removed hook 419 while (atomic_add(&fInsideNotify, 0) != 0) 420 snooze(100); 421 422 gUSBModule->cancel_queued_transfers(fNotifyEndpoint); 423 gUSBModule->cancel_queued_transfers(fReadEndpoint); 424 gUSBModule->cancel_queued_transfers(fWriteEndpoint); 425 426 if (fLinkStateChangeSem >= B_OK) 427 release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 428 } 429 430 431 status_t 432 RNDISDevice::CompareAndReattach(usb_device device) 433 { 434 const usb_device_descriptor *deviceDescriptor 435 = gUSBModule->get_device_descriptor(device); 436 437 if (deviceDescriptor == NULL) { 438 TRACE_ALWAYS("failed to get device descriptor\n"); 439 return B_ERROR; 440 } 441 442 if (deviceDescriptor->vendor_id != fVendorID 443 && deviceDescriptor->product_id != fProductID) { 444 // this certainly isn't the same device 445 return B_BAD_VALUE; 446 } 447 448 // this might be the same device that was replugged - read the MAC address 449 // (which should be at the same index) to make sure 450 uint8 macBuffer[6]; 451 if (_ReadMACAddress(device, macBuffer) != B_OK 452 || memcmp(macBuffer, fMACAddress, sizeof(macBuffer)) != 0) { 453 // reading the MAC address failed or they are not the same 454 return B_BAD_VALUE; 455 } 456 457 // this is the same device that was replugged - clear the removed state, 458 // re-setup the endpoints and transfers and open the device if it was 459 // previously opened 460 fDevice = device; 461 fRemoved = false; 462 status_t result = _SetupDevice(); 463 if (result != B_OK) { 464 fRemoved = true; 465 return result; 466 } 467 468 // in case notifications do not work we will have a hardcoded connection 469 // need to register that and notify the network stack ourselfs if this is 470 // the case as the open will not result in a corresponding notification 471 bool noNotifications = (fMediaConnectState == MEDIA_STATE_CONNECTED); 472 473 if (fOpen) { 474 fOpen = false; 475 result = Open(); 476 if (result == B_OK && noNotifications && fLinkStateChangeSem >= B_OK) 477 release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE); 478 } 479 480 return B_OK; 481 } 482 483 484 status_t 485 RNDISDevice::_SendCommand(const void* data, size_t length) 486 { 487 size_t actualLength; 488 return gUSBModule->send_request(fDevice, USB_REQTYPE_INTERFACE_OUT | USB_REQTYPE_CLASS, 489 USB_CDC_SEND_ENCAPSULATED_COMMAND, 0, 0, length, (void*)data, &actualLength); 490 } 491 492 493 status_t 494 RNDISDevice::_ReadResponse(void* data, size_t length) 495 { 496 size_t actualLength; 497 return gUSBModule->send_request(fDevice, USB_REQTYPE_INTERFACE_IN | USB_REQTYPE_CLASS, 498 USB_CDC_GET_ENCAPSULATED_RESPONSE, 0, 0, length, data, &actualLength); 499 } 500 501 502 status_t 503 RNDISDevice::_RNDISInitialize() 504 { 505 uint32 request[] = { 506 REMOTE_NDIS_INITIALIZE_MSG, 507 6 * sizeof(uint32), // MessageLength 508 0x00000000, // RequestID 509 0x00000001, 0x00000000, // Version (major, minor) 510 0x00004000 // MaxTransferSize 511 }; 512 513 status_t result = _SendCommand(request, sizeof(request)); 514 TRACE("Send init command results in %s\n", strerror(result)); 515 516 acquire_sem(fNotifyControlSem); 517 518 TRACE("Received notification after init command\n"); 519 520 uint32 response[0x34 / 4]; 521 522 result = _ReadResponse(response, sizeof(response)); 523 TRACE("Read init command results in %s\n", strerror(result)); 524 if (result != B_OK) 525 return result; 526 527 TRACE("Type %" B_PRIx32 "\n", response[0]); 528 TRACE("Length %" B_PRIx32 "\n", response[1]); 529 TRACE("Req ID %" B_PRIx32 "\n", response[2]); 530 TRACE("Status %" B_PRIx32 "\n", response[3]); 531 TRACE("Vers Maj %" B_PRIx32 "\n", response[4]); 532 TRACE("Vers Min %" B_PRIx32 "\n", response[5]); 533 TRACE("DevFlags %" B_PRIx32 "\n", response[6]); 534 TRACE("Medium %" B_PRIx32 "\n", response[7]); 535 TRACE("Max Pkts %" B_PRIx32 "\n", response[8]); 536 TRACE("Max Bytes %" B_PRIx32 "\n", response[9]); 537 TRACE("Alignment %" B_PRIx32 "\n", response[10]); 538 TRACE("Reserved "); 539 for (int i = 11; i < 0x34 / 4; i++) 540 TRACE("%" B_PRIx32 " ", response[i]); 541 TRACE("\n"); 542 543 // TODO configure stuff until we get a SET_CPLT message meaning everything is configured 544 // TODO set up a notification sytem to be notified if these change? Do we have OIDs for them? 545 // OID_GEN_HARDWARE_STATUS, OID_GEN_MEDIA_IN_USE 546 547 return B_OK; 548 } 549 550 551 status_t 552 RNDISDevice::_SetupDevice() 553 { 554 const usb_device_descriptor *deviceDescriptor 555 = gUSBModule->get_device_descriptor(fDevice); 556 557 if (deviceDescriptor == NULL) { 558 TRACE_ALWAYS("failed to get device descriptor\n"); 559 return B_ERROR; 560 } 561 562 uint8 controlIndex = 0; 563 uint8 dataIndex = 0; 564 bool foundUnionDescriptor = false; 565 bool foundCMDescriptor = false; 566 bool found = false; 567 const usb_configuration_info *config = NULL; 568 for (int i = 0; i < deviceDescriptor->num_configurations && !found; i++) { 569 config = gUSBModule->get_nth_configuration(fDevice, i); 570 if (config == NULL) 571 continue; 572 573 for (size_t j = 0; j < config->interface_count && !found; j++) { 574 const usb_interface_info *interface = config->interface[j].active; 575 usb_interface_descriptor *descriptor = interface->descr; 576 if (descriptor->interface_class != USB_COMMUNICATION_WIRELESS_DEVICE_CLASS 577 || descriptor->interface_subclass != 0x01 578 || descriptor->interface_protocol != 0x03 579 || interface->generic_count == 0) { 580 continue; 581 } 582 583 // try to find and interpret the union and call management functional 584 // descriptors (they allow us to locate the data interface) 585 foundUnionDescriptor = foundCMDescriptor = false; 586 for (size_t k = 0; k < interface->generic_count; k++) { 587 usb_generic_descriptor *generic = &interface->generic[k]->generic; 588 if (generic->length >= sizeof(usb_cdc_union_functional_descriptor) 589 && generic->data[0] == USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR) { 590 controlIndex = generic->data[1]; 591 foundUnionDescriptor = true; 592 } else if (generic->length >= sizeof(usb_cdc_cm_functional_descriptor) 593 && generic->data[0] == USB_CDC_CM_FUNCTIONAL_DESCRIPTOR) { 594 usb_cdc_cm_functional_descriptor *cm 595 = (usb_cdc_cm_functional_descriptor *)generic; 596 dataIndex = cm->data_interface; 597 foundCMDescriptor = true; 598 } 599 600 if (foundUnionDescriptor && foundCMDescriptor) { 601 found = true; 602 break; 603 } 604 } 605 } 606 } 607 608 if (!foundUnionDescriptor) { 609 TRACE_ALWAYS("did not find a union descriptor\n"); 610 return B_ERROR; 611 } 612 613 if (!foundCMDescriptor) { 614 TRACE_ALWAYS("did not find an ethernet descriptor\n"); 615 return B_ERROR; 616 } 617 618 // set the current configuration 619 gUSBModule->set_configuration(fDevice, config); 620 if (controlIndex >= config->interface_count) { 621 TRACE_ALWAYS("control interface index invalid\n"); 622 return B_ERROR; 623 } 624 625 // check that the indicated control interface fits our needs 626 usb_interface_info *interface = config->interface[controlIndex].active; 627 usb_interface_descriptor *descriptor = interface->descr; 628 if ((descriptor->interface_class != 0xE0 629 || descriptor->interface_subclass != 0x01 630 || descriptor->interface_protocol != 0x03) 631 || interface->endpoint_count == 0) { 632 TRACE_ALWAYS("control interface invalid\n"); 633 return B_ERROR; 634 } 635 636 fNotifyEndpoint = interface->endpoint[0].handle; 637 if (interface->endpoint[0].descr->max_packet_size > sizeof(fNotifyBuffer)) { 638 TRACE_ALWAYS("Notify buffer is too small, need at least %d bytes\n", 639 interface->endpoint[0].descr->max_packet_size); 640 return B_ERROR; 641 } 642 643 if (dataIndex >= config->interface_count) { 644 TRACE_ALWAYS("data interface index %d out of range %" B_PRIuSIZE "\n", dataIndex, 645 config->interface_count); 646 return B_ERROR; 647 } 648 649 interface = &config->interface[dataIndex].alt[0]; 650 descriptor = interface->descr; 651 if (descriptor->interface_class != USB_CDC_DATA_INTERFACE_CLASS 652 || interface->endpoint_count < 2) { 653 TRACE_ALWAYS("data interface %d invalid (class %x, %" B_PRIuSIZE " endpoints)\n", dataIndex, 654 descriptor->interface_class, interface->endpoint_count); 655 return B_ERROR; 656 } 657 658 fDataInterfaceIndex = dataIndex; 659 return B_OK; 660 } 661 662 663 status_t 664 RNDISDevice::_GetOID(uint32 oid, void* buffer, size_t length) 665 { 666 uint32 request[] = { 667 REMOTE_NDIS_QUERY_MSG, 668 7 * sizeof(uint32), // Length of the request 669 0x00000001, // Request ID (FIXME generate this dynamically if we need multiple requests in 670 // flight, so we can match up the replies with the different requests) 671 oid, 672 0, 0, 0 673 }; 674 675 status_t result = _SendCommand(request, sizeof(request)); 676 if (result != B_OK) 677 return result; 678 679 acquire_sem(fNotifyControlSem); 680 681 uint8 response[length + 24]; 682 result = _ReadResponse(response, length + 24); 683 memcpy(buffer, &response[24], length); 684 return result; 685 } 686 687 688 status_t 689 RNDISDevice::_ReadMACAddress(usb_device device, uint8 *buffer) 690 { 691 status_t result = _GetOID(OID_802_3_PERMANENT_ADDRESS, buffer, 6); 692 if (result != B_OK) 693 return result; 694 695 TRACE_ALWAYS("mac address: %02x:%02x:%02x:%02x:%02x:%02x\n", 696 buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); 697 return B_OK; 698 } 699 700 701 status_t 702 RNDISDevice::_ReadMaxSegmentSize(usb_device device) 703 { 704 status_t result = _GetOID(OID_GEN_MAXIMUM_FRAME_SIZE, &fMaxSegmentSize, 705 sizeof(fMaxSegmentSize)); 706 if (result != B_OK) 707 return result; 708 709 TRACE_ALWAYS("max frame size: %" B_PRId32 "\n", fMaxSegmentSize); 710 return B_OK; 711 } 712 713 714 status_t 715 RNDISDevice::_ReadMediaState(usb_device device) 716 { 717 status_t result = _GetOID(OID_GEN_MEDIA_CONNECT_STATUS, &fMediaConnectState, 718 sizeof(fMediaConnectState)); 719 if (result != B_OK) 720 return result; 721 722 TRACE_ALWAYS("media connect state: %" B_PRId32 "\n", fMediaConnectState); 723 return B_OK; 724 } 725 726 727 status_t 728 RNDISDevice::_ReadLinkSpeed(usb_device device) 729 { 730 status_t result = _GetOID(OID_GEN_LINK_SPEED, &fDownstreamSpeed, 731 sizeof(fDownstreamSpeed)); 732 if (result != B_OK) 733 return result; 734 735 TRACE_ALWAYS("link speed: %" B_PRId32 " * 100bps\n", fDownstreamSpeed); 736 return B_OK; 737 } 738 739 740 status_t 741 RNDISDevice::_EnableBroadcast(usb_device device) 742 { 743 uint32 request[] = { 744 REMOTE_NDIS_SET_MSG, 745 8 * sizeof(uint32), // Length of the request 746 0x00000001, // Request ID (FIXME generate this dynamically if we need multiple requests in 747 // flight, so we can match up the replies with the different requests) 748 OID_GEN_CURRENT_PACKET_FILTER, 749 0x14, // buffer length 750 0x14, // buffer offset 751 0, // reserved 752 NDIS_PACKET_TYPE_ALL_MULTICAST | NDIS_PACKET_TYPE_BROADCAST 753 }; 754 755 status_t result = _SendCommand(request, sizeof(request)); 756 if (result != B_OK) { 757 TRACE_ALWAYS("Failed to start traffic (set oid: %s)\n", strerror(result)); 758 return result; 759 } 760 761 acquire_sem(fNotifyControlSem); 762 763 uint32 response[4]; 764 result = _ReadResponse(response, 4 * sizeof(uint32)); 765 if (result != B_OK) { 766 TRACE_ALWAYS("Failed to start traffic (response: %s)\n", strerror(result)); 767 return result; 768 } 769 770 // TODO check other fields in the response (message type, length, request id) match our request 771 772 switch (response[3]) 773 { 774 case RNDIS_STATUS_SUCCESS: 775 return B_OK; 776 case RNDIS_STATUS_FAILURE: 777 return B_ERROR; 778 case RNDIS_STATUS_INVALID_DATA: 779 return B_BAD_DATA; 780 case RNDIS_STATUS_NOT_SUPPORTED: 781 return B_NOT_SUPPORTED; 782 case RNDIS_STATUS_MEDIA_CONNECT: 783 return EISCONN; 784 case RNDIS_STATUS_MEDIA_DISCONNECT: 785 return ENOTCONN; 786 default: 787 TRACE_ALWAYS("Unexpected error code %" B_PRIx32 "\n", response[3]); 788 return B_IO_ERROR; 789 } 790 } 791 792 793 void 794 RNDISDevice::_ReadCallback(void *cookie, int32 status, void *data, 795 size_t actualLength) 796 { 797 RNDISDevice *device = (RNDISDevice *)cookie; 798 device->fActualLengthRead = actualLength; 799 device->fStatusRead = status; 800 release_sem_etc(device->fNotifyReadSem, 1, B_DO_NOT_RESCHEDULE); 801 } 802 803 804 void 805 RNDISDevice::_WriteCallback(void *cookie, int32 status, void *data, 806 size_t actualLength) 807 { 808 RNDISDevice *device = (RNDISDevice *)cookie; 809 device->fActualLengthWrite = actualLength; 810 device->fStatusWrite = status; 811 release_sem_etc(device->fNotifyWriteSem, 1, B_DO_NOT_RESCHEDULE); 812 } 813 814 815 void 816 RNDISDevice::_NotifyCallback(void *cookie, int32 status, void *_data, 817 size_t actualLength) 818 { 819 RNDISDevice *device = (RNDISDevice *)cookie; 820 atomic_add(&device->fInsideNotify, 1); 821 if (status == B_CANCELED || device->fRemoved) { 822 atomic_add(&device->fInsideNotify, -1); 823 return; 824 } 825 826 if (status != B_OK) { 827 TRACE_ALWAYS("device status error 0x%08" B_PRIx32 "\n", status); 828 if (gUSBModule->clear_feature(device->fNotifyEndpoint, 829 USB_FEATURE_ENDPOINT_HALT) != B_OK) 830 TRACE_ALWAYS("failed to clear halt state in notify hook\n"); 831 } else if (actualLength != 8) { 832 TRACE_ALWAYS("Received notification with unexpected number of bytes %" B_PRIuSIZE "\n", 833 actualLength); 834 } else { 835 #ifdef TRACE_RNDIS 836 uint32* data = (uint32*)_data; 837 uint32 notification = data[0]; 838 uint32 reserved = data[1]; 839 TRACE("Received notification %" PRIx32 " %" PRIx32 "\n", notification, reserved); 840 #endif 841 release_sem_etc(device->fNotifyControlSem, 1, B_DO_NOT_RESCHEDULE); 842 } 843 844 // schedule next notification buffer 845 gUSBModule->queue_interrupt(device->fNotifyEndpoint, device->fNotifyBuffer, 846 sizeof(device->fNotifyBuffer), _NotifyCallback, device); 847 atomic_add(&device->fInsideNotify, -1); 848 } 849