1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "rndishost.h" 6 7#include <ddk/binding.h> 8#include <ddk/debug.h> 9#include <ddk/device.h> 10#include <ddk/driver.h> 11#include <ddk/protocol/ethernet.h> 12#include <ddk/protocol/usb.h> 13#include <ddk/usb/usb.h> 14#include <zircon/hw/usb-cdc.h> 15#include <zircon/hw/usb.h> 16#include <zircon/listnode.h> 17 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21#include <threads.h> 22 23#define READ_REQ_COUNT 8 24#define WRITE_REQ_COUNT 4 25#define ETH_HEADER_SIZE 4 26 27#define ETHMAC_MAX_TRANSMIT_DELAY 100 28#define ETHMAC_MAX_RECV_DELAY 100 29#define ETHMAC_TRANSMIT_DELAY 10 30#define ETHMAC_RECV_DELAY 10 31#define ETHMAC_INITIAL_TRANSMIT_DELAY 0 32#define ETHMAC_INITIAL_RECV_DELAY 0 33 34typedef struct { 35 zx_device_t* zxdev; 36 zx_device_t* usb_zxdev; 37 usb_protocol_t usb; 38 39 uint8_t mac_addr[6]; 40 uint8_t control_intf; 41 uint32_t request_id; 42 uint32_t mtu; 43 44 uint8_t bulk_in_addr; 45 uint8_t bulk_out_addr; 46 uint8_t intr_addr; 47 48 list_node_t free_read_reqs; 49 list_node_t free_write_reqs; 50 list_node_t free_intr_reqs; 51 52 uint64_t rx_endpoint_delay; // wait time between 2 recv requests 53 uint64_t tx_endpoint_delay; // wait time between 2 transmit requests 54 55 // Interface to the ethernet layer. 56 ethmac_ifc_t* ifc; 57 void* cookie; 58 59 mtx_t mutex; 60} rndishost_t; 61 62static void dump_buffer(void* buf) { 63 uint8_t* p = buf; 64 for (int i = 0; i < RNDIS_BUFFER_SIZE; i += 4) { 65 if (i != 0 && i % 24 == 0) { 66 zxlogf(DEBUG1, "\n"); 67 } 68 zxlogf(DEBUG1, "%08x ", p[i] | p[i + 1] << 8 | p[i + 2] << 16 | p[i + 3] << 24); 69 } 70 zxlogf(DEBUG1, "\n"); 71} 72 73static bool command_succeeded(void* buf, uint32_t type, uint32_t length) { 74 rndis_header_complete* header = buf; 75 if (header->msg_type != type) { 76 zxlogf(DEBUG1, "Bad type: Actual: %x, Expected: %x.\n", 77 header->msg_type, type); 78 return false; 79 } 80 if (header->msg_length != length) { 81 zxlogf(DEBUG1, "Bad length: Actual: %d, Expected: %d.\n", 82 header->msg_length, length); 83 return false; 84 } 85 if (header->status != RNDIS_STATUS_SUCCESS) { 86 zxlogf(DEBUG1, "Bad status: %x.\n", header->status); 87 return false; 88 } 89 return true; 90} 91 92static zx_status_t rndis_command(rndishost_t* eth, void* buf) { 93 rndis_header* header = buf; 94 uint32_t request_id = eth->request_id++; 95 header->request_id = request_id; 96 97 zx_status_t status; 98 status = usb_control(ð->usb, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 99 USB_CDC_SEND_ENCAPSULATED_COMMAND, 100 0, eth->control_intf, buf, header->msg_length, ZX_TIME_INFINITE, NULL); 101 102 if (status < 0) { 103 return status; 104 } 105 106 // TODO: Set a reasonable timeout on this call. 107 status = usb_control(ð->usb, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 108 USB_CDC_GET_ENCAPSULATED_RESPONSE, 109 0, eth->control_intf, buf, RNDIS_BUFFER_SIZE, ZX_TIME_INFINITE, NULL); 110 111 if (header->request_id != request_id) { 112 return ZX_ERR_IO_DATA_INTEGRITY; 113 } 114 115 return status; 116} 117 118static void rndis_read_complete(usb_request_t* request, void* cookie) { 119 zxlogf(TRACE, "rndis_read_complete\n"); 120 rndishost_t* eth = (rndishost_t*)cookie; 121 122 if (request->response.status == ZX_ERR_IO_NOT_PRESENT) { 123 usb_req_release(ð->usb, request); 124 return; 125 } 126 127 mtx_lock(ð->mutex); 128 if (request->response.status == ZX_ERR_IO_REFUSED) { 129 zxlogf(TRACE, "rndis_read_complete usb_reset_endpoint\n"); 130 usb_reset_endpoint(ð->usb, eth->bulk_in_addr); 131 } else if (request->response.status == ZX_ERR_IO_INVALID) { 132 zxlogf(TRACE, "rndis_read_complete Slowing down the requests by %d usec" 133 " and resetting the recv endpoint\n", ETHMAC_RECV_DELAY); 134 if (eth->rx_endpoint_delay < ETHMAC_MAX_RECV_DELAY) { 135 eth->rx_endpoint_delay += ETHMAC_RECV_DELAY; 136 } 137 usb_reset_endpoint(ð->usb, eth->bulk_in_addr); 138 } 139 if ((request->response.status == ZX_OK) && eth->ifc) { 140 size_t len = request->response.actual; 141 142 uint8_t* read_data; 143 zx_status_t status = usb_req_mmap(ð->usb, request, (void*)&read_data); 144 if (status != ZX_OK) { 145 printf("usb_req_mmap failed: %d\n", status); 146 mtx_unlock(ð->mutex); 147 return; 148 } 149 150 eth->ifc->recv(eth->cookie, read_data, len, 0); 151 } 152 153 // TODO: Only usb_request_queue if the device is online. 154 zx_nanosleep(zx_deadline_after(ZX_USEC(eth->rx_endpoint_delay))); 155 usb_request_queue(ð->usb, request); 156 157 mtx_unlock(ð->mutex); 158} 159 160static void rndis_write_complete(usb_request_t* request, void* cookie) { 161 rndishost_t* eth = (rndishost_t*)cookie; 162 163 if (request->response.status == ZX_ERR_IO_NOT_PRESENT) { 164 zxlogf(ERROR, "rndis_write_complete zx_err_io_not_present\n"); 165 usb_req_release(ð->usb, request); 166 return; 167 } 168 169 mtx_lock(ð->mutex); 170 if (request->response.status == ZX_ERR_IO_REFUSED) { 171 zxlogf(TRACE, "rndishost usb_reset_endpoint\n"); 172 usb_reset_endpoint(ð->usb, eth->bulk_out_addr); 173 } else if (request->response.status == ZX_ERR_IO_INVALID) { 174 zxlogf(TRACE, "rndis_write_complete Slowing down the requests by %d usec" 175 " and resetting the transmit endpoint\n", ETHMAC_TRANSMIT_DELAY); 176 if (eth->tx_endpoint_delay < ETHMAC_MAX_TRANSMIT_DELAY) { 177 eth->tx_endpoint_delay += ETHMAC_TRANSMIT_DELAY; 178 } 179 usb_reset_endpoint(ð->usb, eth->bulk_out_addr); 180 } 181 182 list_add_tail(ð->free_write_reqs, &request->node); 183 mtx_unlock(ð->mutex); 184} 185 186static void rndishost_free(rndishost_t* eth) { 187 usb_request_t* txn; 188 while ((txn = list_remove_head_type(ð->free_read_reqs, usb_request_t, node)) != NULL) { 189 usb_req_release(ð->usb, txn); 190 } 191 while ((txn = list_remove_head_type(ð->free_write_reqs, usb_request_t, node)) != NULL) { 192 usb_req_release(ð->usb, txn); 193 } 194 while ((txn = list_remove_head_type(ð->free_intr_reqs, usb_request_t, node)) != NULL) { 195 usb_req_release(ð->usb, txn); 196 } 197 free(eth); 198} 199 200static zx_status_t rndishost_query(void* ctx, uint32_t options, ethmac_info_t* info) { 201 zxlogf(TRACE, "rndishost_query\n"); 202 rndishost_t* eth = (rndishost_t*)ctx; 203 204 zxlogf(DEBUG1, "options = %x\n", options); 205 if (options) { 206 return ZX_ERR_INVALID_ARGS; 207 } 208 209 memset(info, 0, sizeof(*info)); 210 info->mtu = eth->mtu; 211 memcpy(info->mac, eth->mac_addr, sizeof(eth->mac_addr)); 212 213 return ZX_OK; 214} 215 216static void rndishost_stop(void* ctx) { 217 rndishost_t* eth = (rndishost_t*)ctx; 218 mtx_lock(ð->mutex); 219 eth->ifc = NULL; 220 mtx_unlock(ð->mutex); 221} 222 223static zx_status_t rndishost_start(void* ctx, ethmac_ifc_t* ifc, void* cookie) { 224 rndishost_t* eth = (rndishost_t*)ctx; 225 zx_status_t status = ZX_OK; 226 227 mtx_lock(ð->mutex); 228 if (eth->ifc) { 229 status = ZX_ERR_ALREADY_BOUND; 230 } else { 231 eth->ifc = ifc; 232 eth->cookie = cookie; 233 // TODO: Check that the device is online before sending ETH_STATUS_ONLINE. 234 eth->ifc->status(eth->cookie, ETH_STATUS_ONLINE); 235 } 236 mtx_unlock(ð->mutex); 237 238 return status; 239} 240 241static zx_status_t rndishost_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf) { 242 size_t length = netbuf->len; 243 rndishost_t* eth = (rndishost_t*)ctx; 244 uint8_t* byte_data = netbuf->data; 245 zx_status_t status = ZX_OK; 246 247 mtx_lock(ð->mutex); 248 249 usb_request_t* req = list_remove_head_type(ð->free_write_reqs, usb_request_t, node); 250 if (req == NULL) { 251 zxlogf(DEBUG1, "dropped a packet.\n"); 252 status = ZX_ERR_NO_RESOURCES; 253 goto done; 254 } 255 256 // TODO: Check that length + header <= MTU 257 258 rndis_packet_header header; 259 uint8_t* header_data = (uint8_t*)&header; 260 memset(header_data, 0, sizeof(rndis_packet_header)); 261 header.msg_type = RNDIS_PACKET_MSG; 262 header.msg_length = sizeof(rndis_packet_header) + length; 263 // The offset should be given from the beginning of the data_offset field. 264 // So subtract 8 bytes for msg_type and msg_length. 265 header.data_offset = sizeof(rndis_packet_header) - 8; 266 header.data_length = length; 267 268 usb_req_copy_to(ð->usb, req, header_data, sizeof(rndis_packet_header), 0); 269 ssize_t bytes_copied = usb_req_copy_to(ð->usb, req, byte_data, length, 270 sizeof(rndis_packet_header)); 271 req->header.length = sizeof(rndis_packet_header) + length; 272 if (bytes_copied < 0) { 273 printf("rndishost: failed to copy data into send txn (error %zd)\n", bytes_copied); 274 list_add_tail(ð->free_write_reqs, &req->node); 275 goto done; 276 } 277 zx_nanosleep(zx_deadline_after(ZX_USEC(eth->tx_endpoint_delay))); 278 usb_request_queue(ð->usb, req); 279 280done: 281 mtx_unlock(ð->mutex); 282 return status; 283} 284 285static void rndishost_unbind(void* ctx) { 286 rndishost_t* eth = (rndishost_t*)ctx; 287 device_remove(eth->zxdev); 288} 289 290static void rndishost_release(void* ctx) { 291 rndishost_t* eth = (rndishost_t*)ctx; 292 rndishost_free(eth); 293} 294 295static zx_status_t rndishost_set_param(void *ctx, uint32_t param, int32_t value, void* data) { 296 return ZX_ERR_NOT_SUPPORTED; 297} 298 299static ethmac_protocol_ops_t ethmac_ops = { 300 .query = rndishost_query, 301 .stop = rndishost_stop, 302 .start = rndishost_start, 303 .queue_tx = rndishost_queue_tx, 304 .set_param = rndishost_set_param, 305}; 306 307static zx_protocol_device_t rndishost_device_proto = { 308 .version = DEVICE_OPS_VERSION, 309 .unbind = rndishost_unbind, 310 .release = rndishost_release, 311}; 312 313static int rndis_start_thread(void* arg) { 314 rndishost_t* eth = (rndishost_t*)arg; 315 void* buf = malloc(RNDIS_BUFFER_SIZE); 316 memset(buf, 0, RNDIS_BUFFER_SIZE); 317 318 // Send an initialization message to the device. 319 rndis_init* init = buf; 320 init->msg_type = RNDIS_INITIALIZE_MSG; 321 init->msg_length = sizeof(rndis_init); 322 init->major_version = RNDIS_MAJOR_VERSION; 323 init->minor_version = RNDIS_MINOR_VERSION; 324 init->max_xfer_size = RNDIS_MAX_XFER_SIZE; 325 326 zx_status_t status = rndis_command(eth, buf); 327 if (status < 0) { 328 zxlogf(DEBUG1, "rndishost bad status on initial message. %d\n", status); 329 goto fail; 330 } 331 332 // TODO: Save important fields of init_cmplt. 333 rndis_init_complete* init_cmplt = buf; 334 if (!command_succeeded(buf, RNDIS_INITIALIZE_CMPLT, sizeof(*init_cmplt))) { 335 zxlogf(DEBUG1, "rndishost initialization failed.\n"); 336 status = ZX_ERR_IO; 337 goto fail; 338 } 339 eth->mtu = init_cmplt->max_xfer_size; 340 341 // Check the PHY, this is optional and may not be supported by the device. 342 uint32_t* phy; 343 memset(buf, 0, RNDIS_BUFFER_SIZE); 344 rndis_query* query = buf; 345 query->msg_type = RNDIS_QUERY_MSG; 346 query->msg_length = sizeof(rndis_query) + sizeof(*phy); 347 query->oid = OID_GEN_PHYSICAL_MEDIUM; 348 query->info_buffer_length = sizeof(*phy); 349 query->info_buffer_offset = RNDIS_QUERY_BUFFER_OFFSET; 350 status = rndis_command(eth, buf); 351 if (status == ZX_OK) { 352 // TODO: Do something with this information. 353 rndis_query_complete* phy_query_cmplt = buf; 354 if (command_succeeded(buf, RNDIS_QUERY_CMPLT, sizeof(*phy_query_cmplt) + 355 phy_query_cmplt->info_buffer_length)) { 356 // The offset given in the reply is from the beginning of the request_id 357 // field. So, add 8 for the msg_type and msg_length fields. 358 phy = buf + 8 + phy_query_cmplt->info_buffer_offset; 359 } 360 } 361 362 // Query the device for a MAC address. 363 memset(buf, 0, RNDIS_BUFFER_SIZE); 364 query->msg_type = RNDIS_QUERY_MSG; 365 query->msg_length = sizeof(rndis_query) + 48; 366 query->oid = OID_802_3_PERMANENT_ADDRESS; 367 query->info_buffer_length = 48; 368 query->info_buffer_offset = RNDIS_QUERY_BUFFER_OFFSET; 369 status = rndis_command(eth, buf); 370 if (status < 0) { 371 zxlogf(ERROR, "Couldn't get device physical address\n"); 372 goto fail; 373 } 374 375 rndis_query_complete* mac_query_cmplt = buf; 376 if (!command_succeeded(buf, RNDIS_QUERY_CMPLT, sizeof(*mac_query_cmplt) + 377 mac_query_cmplt->info_buffer_length)) { 378 zxlogf(DEBUG1, "rndishost MAC query failed.\n"); 379 status = ZX_ERR_IO; 380 goto fail; 381 } 382 uint8_t* mac_addr = buf + 8 + mac_query_cmplt->info_buffer_offset; 383 memcpy(eth->mac_addr, mac_addr, sizeof(eth->mac_addr)); 384 zxlogf(INFO, "rndishost MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", 385 eth->mac_addr[0], eth->mac_addr[1], eth->mac_addr[2], 386 eth->mac_addr[3], eth->mac_addr[4], eth->mac_addr[5]); 387 388 // Enable data transfers 389 memset(buf, 0, RNDIS_BUFFER_SIZE); 390 rndis_set* set = buf; 391 set->msg_type = RNDIS_SET_MSG; 392 set->msg_length = sizeof(rndis_set) + 4; // 4 bytes for the filter 393 set->oid = OID_GEN_CURRENT_PACKET_FILTER; 394 set->info_buffer_length = 4; 395 // Offset should begin at oid, so subtract 8 bytes for msg_type and msg_length. 396 set->info_buffer_offset = sizeof(rndis_set) - 8; 397 uint8_t* filter = buf + sizeof(rndis_set); 398 *filter = RNDIS_PACKET_TYPE_DIRECTED | 399 RNDIS_PACKET_TYPE_BROADCAST | 400 RNDIS_PACKET_TYPE_ALL_MULTICAST | 401 RNDIS_PACKET_TYPE_PROMISCUOUS; 402 status = rndis_command(eth, buf); 403 if (status < 0) { 404 zxlogf(ERROR, "Couldn't set the packet filter.\n"); 405 goto fail; 406 } 407 408 if (!command_succeeded(buf, RNDIS_SET_CMPLT, sizeof(rndis_set_complete))) { 409 zxlogf(ERROR, "rndishost set filter failed.\n"); 410 status = ZX_ERR_IO; 411 goto fail; 412 } 413 414 free(buf); 415 device_make_visible(eth->zxdev); 416 return ZX_OK; 417 418fail: 419 free(buf); 420 rndishost_unbind(eth); 421 rndishost_free(eth); 422 return status; 423} 424 425static zx_status_t rndishost_bind(void* ctx, zx_device_t* device) { 426 usb_protocol_t usb; 427 428 zx_status_t status = device_get_protocol(device, ZX_PROTOCOL_USB, &usb); 429 if (status != ZX_OK) { 430 return status; 431 } 432 433 // Find our endpoints. 434 usb_desc_iter_t iter; 435 status = usb_desc_iter_init(&usb, &iter); 436 if (status < 0) { 437 return status; 438 } 439 440 // We should have two interfaces: the CDC classified interface the bulk in 441 // and out endpoints, and the RNDIS interface for control. The RNDIS 442 // interface will be classified as USB_CLASS_WIRELESS when the device is 443 // used for tethering. 444 // TODO: Figure out how to handle other RNDIS use cases. 445 usb_interface_descriptor_t* intf = usb_desc_iter_next_interface(&iter, false); 446 uint8_t bulk_in_addr = 0; 447 uint8_t bulk_out_addr = 0; 448 uint8_t intr_addr = 0; 449 uint8_t control_intf = 0; 450 while (intf) { 451 if (intf->bInterfaceClass == USB_CLASS_WIRELESS) { 452 control_intf = intf->bInterfaceNumber; 453 if (intf->bNumEndpoints != 1) { 454 usb_desc_iter_release(&iter); 455 return ZX_ERR_NOT_SUPPORTED; 456 } 457 usb_endpoint_descriptor_t* endp = usb_desc_iter_next_endpoint(&iter); 458 while (endp) { 459 if (usb_ep_direction(endp) == USB_ENDPOINT_IN && 460 usb_ep_type(endp) == USB_ENDPOINT_INTERRUPT) { 461 intr_addr = endp->bEndpointAddress; 462 } 463 endp = usb_desc_iter_next_endpoint(&iter); 464 } 465 } else if (intf->bInterfaceClass == USB_CLASS_CDC) { 466 if (intf->bNumEndpoints != 2) { 467 usb_desc_iter_release(&iter); 468 return ZX_ERR_NOT_SUPPORTED; 469 } 470 usb_endpoint_descriptor_t* endp = usb_desc_iter_next_endpoint(&iter); 471 while (endp) { 472 if (usb_ep_direction(endp) == USB_ENDPOINT_OUT) { 473 if (usb_ep_type(endp) == USB_ENDPOINT_BULK) { 474 bulk_out_addr = endp->bEndpointAddress; 475 } 476 } else if (usb_ep_direction(endp) == USB_ENDPOINT_IN) { 477 if (usb_ep_type(endp) == USB_ENDPOINT_BULK) { 478 bulk_in_addr = endp->bEndpointAddress; 479 } 480 } 481 endp = usb_desc_iter_next_endpoint(&iter); 482 } 483 } else { 484 usb_desc_iter_release(&iter); 485 return ZX_ERR_NOT_SUPPORTED; 486 } 487 intf = usb_desc_iter_next_interface(&iter, false); 488 } 489 usb_desc_iter_release(&iter); 490 491 if (!bulk_in_addr || !bulk_out_addr || !intr_addr) { 492 zxlogf(ERROR, "rndishost couldn't find endpoints\n"); 493 return ZX_ERR_NOT_SUPPORTED; 494 } 495 496 rndishost_t* eth = calloc(1, sizeof(rndishost_t)); 497 if (!eth) { 498 return ZX_ERR_NO_MEMORY; 499 } 500 501 list_initialize(ð->free_read_reqs); 502 list_initialize(ð->free_write_reqs); 503 list_initialize(ð->free_intr_reqs); 504 505 mtx_init(ð->mutex, mtx_plain); 506 507 eth->usb_zxdev = device; 508 eth->control_intf = control_intf; 509 eth->bulk_in_addr = bulk_in_addr; 510 eth->bulk_out_addr = bulk_out_addr; 511 eth->intr_addr = intr_addr; 512 eth->ifc = NULL; 513 memcpy(ð->usb, &usb, sizeof(eth->usb)); 514 515 for (int i = 0; i < READ_REQ_COUNT; i++) { 516 usb_request_t* req; 517 zx_status_t alloc_result = usb_req_alloc(ð->usb, &req, RNDIS_BUFFER_SIZE, bulk_in_addr); 518 if (alloc_result != ZX_OK) { 519 status = alloc_result; 520 goto fail; 521 } 522 req->complete_cb = rndis_read_complete; 523 req->cookie = eth; 524 list_add_head(ð->free_read_reqs, &req->node); 525 } 526 for (int i = 0; i < WRITE_REQ_COUNT; i++) { 527 usb_request_t* req; 528 // TODO: Allocate based on mtu. 529 zx_status_t alloc_result = usb_req_alloc(ð->usb, &req, RNDIS_BUFFER_SIZE, bulk_out_addr); 530 if (alloc_result != ZX_OK) { 531 status = alloc_result; 532 goto fail; 533 } 534 req->complete_cb = rndis_write_complete; 535 req->cookie = eth; 536 list_add_head(ð->free_write_reqs, &req->node); 537 } 538 539 device_add_args_t args = { 540 .version = DEVICE_ADD_ARGS_VERSION, 541 .name = "rndishost", 542 .ctx = eth, 543 .ops = &rndishost_device_proto, 544 .proto_id = ZX_PROTOCOL_ETHERNET_IMPL, 545 .proto_ops = ðmac_ops, 546 .flags = DEVICE_ADD_INVISIBLE, 547 }; 548 549 status = device_add(eth->usb_zxdev, &args, ð->zxdev); 550 if (status < 0) { 551 zxlogf(ERROR, "rndishost: failed to create device: %d\n", status); 552 goto fail; 553 } 554 555 thrd_t thread; 556 int ret = thrd_create_with_name(&thread, rndis_start_thread, 557 eth, "rndishost_start_thread"); 558 if (ret != thrd_success) { 559 status = ZX_ERR_NO_RESOURCES; 560 goto fail; 561 } 562 // TODO: Save the thread in rndishost_t and join when we release the device. 563 thrd_detach(thread); 564 565 return ZX_OK; 566 567fail: 568 zxlogf(ERROR, "rndishost_bind failed: %d\n", status); 569 rndishost_free(eth); 570 return status; 571} 572 573static zx_driver_ops_t rndis_driver_ops = { 574 .version = DRIVER_OPS_VERSION, 575 .bind = rndishost_bind, 576}; 577 578// TODO: Make sure we can bind to all RNDIS use cases. USB_CLASS_WIRELESS only 579// covers the tethered device case. 580ZIRCON_DRIVER_BEGIN(rndishost, rndis_driver_ops, "zircon", "0.1", 4) 581 BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_USB), 582 BI_ABORT_IF(NE, BIND_USB_CLASS, USB_CLASS_WIRELESS), 583 BI_ABORT_IF(NE, BIND_USB_SUBCLASS, RNDIS_SUBCLASS), 584 BI_MATCH_IF(EQ, BIND_USB_PROTOCOL, RNDIS_PROTOCOL), 585ZIRCON_DRIVER_END(rndishost) 586