2
* Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License as
6
* published by the Free Software Foundation; either version 2 of the
7
* License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful, but
10
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
* You can also choose to distribute this program under the terms of
20
* the Unmodified Binary Distribution Licence (as given in the file
21
* COPYING.UBDL), provided that you have satisfied its requirements.
24
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28
* Hyper-V network virtual service client
30
* The network virtual service client (NetVSC) connects to the network
31
* virtual service provider (NetVSP) via the Hyper-V virtual machine
32
* bus (VMBus). It provides a transport layer for RNDIS packets.
38
#include <ipxe/umalloc.h>
39
#include <ipxe/rndis.h>
40
#include <ipxe/vmbus.h>
44
* Send control message and wait for completion
46
* @v netvsc NetVSC device
47
* @v xrid Relative transaction ID
49
* @v len Length of data
50
* @ret rc Return status code
52
static int netvsc_control ( struct netvsc_device *netvsc, unsigned int xrid,
53
const void *data, size_t len ) {
54
uint64_t xid = ( NETVSC_BASE_XID + xrid );
58
/* Send control message */
59
if ( ( rc = vmbus_send_control ( netvsc->vmdev, xid, data, len ) ) !=0){
60
DBGC ( netvsc, "NETVSC %s could not send control message: %s\n",
61
netvsc->name, strerror ( rc ) );
65
/* Record transaction ID */
66
netvsc->wait_xrid = xrid;
68
/* Wait for operation to complete */
69
for ( i = 0 ; i < NETVSC_MAX_WAIT_MS ; i++ ) {
71
/* Check for completion */
72
if ( ! netvsc->wait_xrid )
73
return netvsc->wait_rc;
75
/* Poll VMBus device */
76
vmbus_poll ( netvsc->vmdev );
82
DBGC ( netvsc, "NETVSC %s timed out waiting for XRID %d\n",
84
vmbus_dump_channel ( netvsc->vmdev );
89
* Handle generic completion
91
* @v netvsc NetVSC device
93
* @v len Length of data
94
* @ret rc Return status code
96
static int netvsc_completed ( struct netvsc_device *netvsc __unused,
97
const void *data __unused, size_t len __unused ) {
102
* Initialise communication
104
* @v netvsc NetVSC device
105
* @ret rc Return status code
107
static int netvsc_initialise ( struct netvsc_device *netvsc ) {
108
struct netvsc_init_message msg;
111
/* Construct message */
112
memset ( &msg, 0, sizeof ( msg ) );
113
msg.header.type = cpu_to_le32 ( NETVSC_INIT_MSG );
114
msg.min = cpu_to_le32 ( NETVSC_VERSION_1 );
115
msg.max = cpu_to_le32 ( NETVSC_VERSION_1 );
117
/* Send message and wait for completion */
118
if ( ( rc = netvsc_control ( netvsc, NETVSC_INIT_XRID, &msg,
119
sizeof ( msg ) ) ) != 0 ) {
120
DBGC ( netvsc, "NETVSC %s could not initialise: %s\n",
121
netvsc->name, strerror ( rc ) );
129
* Handle initialisation completion
131
* @v netvsc NetVSC device
133
* @v len Length of data
134
* @ret rc Return status code
137
netvsc_initialised ( struct netvsc_device *netvsc, const void *data,
139
const struct netvsc_init_completion *cmplt = data;
141
/* Check completion */
142
if ( len < sizeof ( *cmplt ) ) {
143
DBGC ( netvsc, "NETVSC %s underlength initialisation "
144
"completion (%zd bytes)\n", netvsc->name, len );
147
if ( cmplt->header.type != cpu_to_le32 ( NETVSC_INIT_CMPLT ) ) {
148
DBGC ( netvsc, "NETVSC %s unexpected initialisation completion "
149
"type %d\n", netvsc->name,
150
le32_to_cpu ( cmplt->header.type ) );
153
if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
154
DBGC ( netvsc, "NETVSC %s initialisation failure status %d\n",
155
netvsc->name, le32_to_cpu ( cmplt->status ) );
165
* @v netvsc NetVSC device
166
* @ret rc Return status code
168
static int netvsc_ndis_version ( struct netvsc_device *netvsc ) {
169
struct netvsc_ndis_version_message msg;
172
/* Construct message */
173
memset ( &msg, 0, sizeof ( msg ) );
174
msg.header.type = cpu_to_le32 ( NETVSC_NDIS_VERSION_MSG );
175
msg.major = cpu_to_le32 ( NETVSC_NDIS_MAJOR );
176
msg.minor = cpu_to_le32 ( NETVSC_NDIS_MINOR );
178
/* Send message and wait for completion */
179
if ( ( rc = netvsc_control ( netvsc, NETVSC_NDIS_VERSION_XRID,
180
&msg, sizeof ( msg ) ) ) != 0 ) {
181
DBGC ( netvsc, "NETVSC %s could not set NDIS version: %s\n",
182
netvsc->name, strerror ( rc ) );
190
* Establish data buffer
192
* @v netvsc NetVSC device
193
* @v buffer Data buffer
194
* @ret rc Return status code
196
static int netvsc_establish_buffer ( struct netvsc_device *netvsc,
197
struct netvsc_buffer *buffer ) {
198
struct netvsc_establish_buffer_message msg;
201
/* Construct message */
202
memset ( &msg, 0, sizeof ( msg ) );
203
msg.header.type = cpu_to_le32 ( buffer->establish_type );
204
msg.gpadl = cpu_to_le32 ( buffer->gpadl );
205
msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
207
/* Send message and wait for completion */
208
if ( ( rc = netvsc_control ( netvsc, buffer->establish_xrid, &msg,
209
sizeof ( msg ) ) ) != 0 ) {
210
DBGC ( netvsc, "NETVSC %s could not establish buffer: %s\n",
211
netvsc->name, strerror ( rc ) );
219
* Handle establish receive data buffer completion
221
* @v netvsc NetVSC device
223
* @v len Length of data
224
* @ret rc Return status code
226
static int netvsc_rx_established_buffer ( struct netvsc_device *netvsc,
227
const void *data, size_t len ) {
228
const struct netvsc_rx_establish_buffer_completion *cmplt = data;
230
/* Check completion */
231
if ( len < sizeof ( *cmplt ) ) {
232
DBGC ( netvsc, "NETVSC %s underlength buffer completion (%zd "
233
"bytes)\n", netvsc->name, len );
236
if ( cmplt->header.type != cpu_to_le32 ( NETVSC_RX_ESTABLISH_CMPLT ) ) {
237
DBGC ( netvsc, "NETVSC %s unexpected buffer completion type "
238
"%d\n", netvsc->name, le32_to_cpu ( cmplt->header.type));
241
if ( cmplt->status != cpu_to_le32 ( NETVSC_OK ) ) {
242
DBGC ( netvsc, "NETVSC %s buffer failure status %d\n",
243
netvsc->name, le32_to_cpu ( cmplt->status ) );
253
* @v netvsc NetVSC device
254
* @v buffer Data buffer
255
* @ret rc Return status code
257
static int netvsc_revoke_buffer ( struct netvsc_device *netvsc,
258
struct netvsc_buffer *buffer ) {
259
struct netvsc_revoke_buffer_message msg;
262
/* Construct message */
263
memset ( &msg, 0, sizeof ( msg ) );
264
msg.header.type = cpu_to_le32 ( buffer->revoke_type );
265
msg.pageset = buffer->pages.pageset; /* Already protocol-endian */
267
/* Send message and wait for completion */
268
if ( ( rc = netvsc_control ( netvsc, buffer->revoke_xrid,
269
&msg, sizeof ( msg ) ) ) != 0 ) {
270
DBGC ( netvsc, "NETVSC %s could not revoke buffer: %s\n",
271
netvsc->name, strerror ( rc ) );
279
* Handle received control packet
281
* @v vmdev VMBus device
282
* @v xid Transaction ID
284
* @v len Length of data
285
* @ret rc Return status code
287
static int netvsc_recv_control ( struct vmbus_device *vmdev, uint64_t xid,
288
const void *data, size_t len ) {
289
struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
290
struct netvsc_device *netvsc = rndis->priv;
292
DBGC ( netvsc, "NETVSC %s received unsupported control packet "
293
"(%08llx):\n", netvsc->name, xid );
294
DBGC_HDA ( netvsc, 0, data, len );
299
* Handle received data packet
301
* @v vmdev VMBus device
302
* @v xid Transaction ID
304
* @v len Length of data
305
* @v list List of I/O buffers
306
* @ret rc Return status code
308
static int netvsc_recv_data ( struct vmbus_device *vmdev, uint64_t xid,
309
const void *data, size_t len,
310
struct list_head *list ) {
311
struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
312
struct netvsc_device *netvsc = rndis->priv;
313
const struct netvsc_rndis_message *msg = data;
314
struct io_buffer *iobuf;
315
struct io_buffer *tmp;
319
if ( len < sizeof ( *msg ) ) {
320
DBGC ( netvsc, "NETVSC %s received underlength RNDIS packet "
321
"(%zd bytes)\n", netvsc->name, len );
325
if ( msg->header.type != cpu_to_le32 ( NETVSC_RNDIS_MSG ) ) {
326
DBGC ( netvsc, "NETVSC %s received unexpected RNDIS packet "
327
"type %d\n", netvsc->name,
328
le32_to_cpu ( msg->header.type ) );
333
/* Send completion back to host */
334
if ( ( rc = vmbus_send_completion ( vmdev, xid, NULL, 0 ) ) != 0 ) {
335
DBGC ( netvsc, "NETVSC %s could not send completion: %s\n",
336
netvsc->name, strerror ( rc ) );
340
/* Hand off to RNDIS */
341
list_for_each_entry_safe ( iobuf, tmp, list, list ) {
342
list_del ( &iobuf->list );
343
rndis_rx ( rndis, iob_disown ( iobuf ) );
350
list_for_each_entry_safe ( iobuf, tmp, list, list ) {
351
list_del ( &iobuf->list );
358
* Handle received completion packet
360
* @v vmdev VMBus device
361
* @v xid Transaction ID
363
* @v len Length of data
364
* @ret rc Return status code
366
static int netvsc_recv_completion ( struct vmbus_device *vmdev, uint64_t xid,
367
const void *data, size_t len ) {
368
struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
369
struct netvsc_device *netvsc = rndis->priv;
370
struct io_buffer *iobuf;
371
int ( * completion ) ( struct netvsc_device *netvsc,
372
const void *data, size_t len );
373
unsigned int xrid = ( xid - NETVSC_BASE_XID );
377
/* Handle transmit completion, if applicable */
378
tx_id = ( xrid - NETVSC_TX_BASE_XRID );
379
if ( ( tx_id < NETVSC_TX_NUM_DESC ) &&
380
( ( iobuf = netvsc->tx.iobufs[tx_id] ) != NULL ) ) {
383
netvsc->tx.iobufs[tx_id] = NULL;
384
netvsc->tx.ids[ ( netvsc->tx.id_cons++ ) &
385
( netvsc->tx.count - 1 ) ] = tx_id;
387
/* Hand back to RNDIS */
388
rndis_tx_complete ( rndis, iobuf );
392
/* Otherwise determine completion handler */
393
if ( xrid == NETVSC_INIT_XRID ) {
394
completion = netvsc_initialised;
395
} else if ( xrid == NETVSC_RX_ESTABLISH_XRID ) {
396
completion = netvsc_rx_established_buffer;
397
} else if ( ( netvsc->wait_xrid != 0 ) &&
398
( xrid == netvsc->wait_xrid ) ) {
399
completion = netvsc_completed;
401
DBGC ( netvsc, "NETVSC %s received unexpected completion "
402
"(%08llx)\n", netvsc->name, xid );
406
/* Hand off to completion handler */
407
rc = completion ( netvsc, data, len );
409
/* Record completion handler result if applicable */
410
if ( xrid == netvsc->wait_xrid ) {
411
netvsc->wait_xrid = 0;
412
netvsc->wait_rc = rc;
419
* Handle received cancellation packet
421
* @v vmdev VMBus device
422
* @v xid Transaction ID
423
* @ret rc Return status code
425
static int netvsc_recv_cancellation ( struct vmbus_device *vmdev,
427
struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
428
struct netvsc_device *netvsc = rndis->priv;
430
DBGC ( netvsc, "NETVSC %s received unsupported cancellation packet "
431
"(%08llx):\n", netvsc->name, xid );
435
/** VMBus channel operations */
436
static struct vmbus_channel_operations netvsc_channel_operations = {
437
.recv_control = netvsc_recv_control,
438
.recv_data = netvsc_recv_data,
439
.recv_completion = netvsc_recv_completion,
440
.recv_cancellation = netvsc_recv_cancellation,
444
* Poll for completed and received packets
446
* @v rndis RNDIS device
448
static void netvsc_poll ( struct rndis_device *rndis ) {
449
struct netvsc_device *netvsc = rndis->priv;
450
struct vmbus_device *vmdev = netvsc->vmdev;
452
/* Poll VMBus device */
453
while ( vmbus_has_data ( vmdev ) )
454
vmbus_poll ( vmdev );
460
* @v rndis RNDIS device
461
* @v iobuf I/O buffer
462
* @ret rc Return status code
464
* If this method returns success then the RNDIS device must
465
* eventually report completion via rndis_tx_complete().
467
static int netvsc_transmit ( struct rndis_device *rndis,
468
struct io_buffer *iobuf ) {
469
struct netvsc_device *netvsc = rndis->priv;
470
struct rndis_header *header = iobuf->data;
471
struct netvsc_rndis_message msg;
478
assert ( iob_len ( iobuf ) >= sizeof ( *header ) );
479
assert ( iob_len ( iobuf ) == le32_to_cpu ( header->len ) );
481
/* Check that we have space in the transmit ring */
482
if ( netvsc_ring_is_full ( &netvsc->tx ) )
483
return rndis_tx_defer ( rndis, iobuf );
485
/* Allocate buffer ID and calculate transaction ID */
486
tx_id = netvsc->tx.ids[ netvsc->tx.id_prod & ( netvsc->tx.count - 1 ) ];
487
assert ( netvsc->tx.iobufs[tx_id] == NULL );
488
xrid = ( NETVSC_TX_BASE_XRID + tx_id );
489
xid = ( NETVSC_BASE_XID + xrid );
491
/* Construct message */
492
memset ( &msg, 0, sizeof ( msg ) );
493
msg.header.type = cpu_to_le32 ( NETVSC_RNDIS_MSG );
494
msg.channel = ( ( header->type == cpu_to_le32 ( RNDIS_PACKET_MSG ) ) ?
495
NETVSC_RNDIS_DATA : NETVSC_RNDIS_CONTROL );
496
msg.buffer = cpu_to_le32 ( NETVSC_RNDIS_NO_BUFFER );
499
if ( ( rc = vmbus_send_data ( netvsc->vmdev, xid, &msg, sizeof ( msg ),
501
DBGC ( netvsc, "NETVSC %s could not send RNDIS message: %s\n",
502
netvsc->name, strerror ( rc ) );
506
/* Store I/O buffer and consume buffer ID */
507
netvsc->tx.iobufs[tx_id] = iobuf;
508
netvsc->tx.id_prod++;
514
* Cancel transmission
516
* @v netvsc NetVSC device
517
* @v iobuf I/O buffer
518
* @v tx_id Transmission ID
520
static void netvsc_cancel_transmit ( struct netvsc_device *netvsc,
521
struct io_buffer *iobuf,
522
unsigned int tx_id ) {
526
/* Send cancellation */
527
xrid = ( NETVSC_TX_BASE_XRID + tx_id );
528
xid = ( NETVSC_BASE_XID + xrid );
529
DBGC ( netvsc, "NETVSC %s cancelling transmission %#x\n",
530
netvsc->name, tx_id );
531
vmbus_send_cancellation ( netvsc->vmdev, xid );
533
/* Report back to RNDIS */
534
rndis_tx_complete_err ( netvsc->rndis, iobuf, -ECANCELED );
538
* Create descriptor ring
540
* @v netvsc NetVSC device
541
* @v ring Descriptor ring
542
* @ret rc Return status code
544
static int netvsc_create_ring ( struct netvsc_device *netvsc __unused,
545
struct netvsc_ring *ring ) {
548
/* Initialise buffer ID ring */
549
for ( i = 0 ; i < ring->count ; i++ ) {
551
assert ( ring->iobufs[i] == NULL );
560
* Destroy descriptor ring
562
* @v netvsc NetVSC device
563
* @v ring Descriptor ring
564
* @v discard Method used to discard outstanding buffer, or NULL
566
static void netvsc_destroy_ring ( struct netvsc_device *netvsc,
567
struct netvsc_ring *ring,
568
void ( * discard ) ( struct netvsc_device *,
571
struct io_buffer *iobuf;
574
/* Flush any outstanding buffers */
575
for ( i = 0 ; i < ring->count ; i++ ) {
576
iobuf = ring->iobufs[i];
579
ring->iobufs[i] = NULL;
580
ring->ids[ ( ring->id_cons++ ) & ( ring->count - 1 ) ] = i;
582
discard ( netvsc, iobuf, i );
586
assert ( netvsc_ring_is_empty ( ring ) );
590
* Copy data from data buffer
592
* @v pages Transfer page set
593
* @v data Data buffer
594
* @v offset Offset within page set
595
* @v len Length within page set
596
* @ret rc Return status code
598
static int netvsc_buffer_copy ( struct vmbus_xfer_pages *pages, void *data,
599
size_t offset, size_t len ) {
600
struct netvsc_buffer *buffer =
601
container_of ( pages, struct netvsc_buffer, pages );
604
if ( ( offset > buffer->len ) || ( len > ( buffer->len - offset ) ) )
607
/* Copy data from buffer */
608
copy_from_user ( data, buffer->data, offset, len );
613
/** Transfer page set operations */
614
static struct vmbus_xfer_pages_operations netvsc_xfer_pages_operations = {
615
.copy = netvsc_buffer_copy,
621
* @v netvsc NetVSC device
622
* @v buffer Data buffer
623
* @ret rc Return status code
625
static int netvsc_create_buffer ( struct netvsc_device *netvsc,
626
struct netvsc_buffer *buffer ) {
627
struct vmbus_device *vmdev = netvsc->vmdev;
631
/* Allocate receive buffer */
632
buffer->data = umalloc ( buffer->len );
633
if ( ! buffer->data ) {
634
DBGC ( netvsc, "NETVSC %s could not allocate %zd-byte buffer\n",
635
netvsc->name, buffer->len );
640
/* Establish GPA descriptor list */
641
gpadl = vmbus_establish_gpadl ( vmdev, buffer->data, buffer->len );
644
DBGC ( netvsc, "NETVSC %s could not establish GPADL: %s\n",
645
netvsc->name, strerror ( rc ) );
646
goto err_establish_gpadl;
648
buffer->gpadl = gpadl;
650
/* Register transfer page set */
651
if ( ( rc = vmbus_register_pages ( vmdev, &buffer->pages ) ) != 0 ) {
652
DBGC ( netvsc, "NETVSC %s could not register transfer pages: "
653
"%s\n", netvsc->name, strerror ( rc ) );
654
goto err_register_pages;
659
vmbus_unregister_pages ( vmdev, &buffer->pages );
661
vmbus_gpadl_teardown ( vmdev, gpadl );
663
ufree ( buffer->data );
669
* Destroy data buffer
671
* @v netvsc NetVSC device
672
* @v buffer Data buffer
674
static void netvsc_destroy_buffer ( struct netvsc_device *netvsc,
675
struct netvsc_buffer *buffer ) {
676
struct vmbus_device *vmdev = netvsc->vmdev;
679
/* Unregister transfer pages */
680
vmbus_unregister_pages ( vmdev, &buffer->pages );
682
/* Tear down GPA descriptor list */
683
if ( ( rc = vmbus_gpadl_teardown ( vmdev, buffer->gpadl ) ) != 0 ) {
684
DBGC ( netvsc, "NETVSC %s could not tear down GPADL: %s\n",
685
netvsc->name, strerror ( rc ) );
686
/* Death is imminent. The host may well continue to
687
* write to the data buffer. The best we can do is
688
* leak memory for now and hope that the host doesn't
689
* write to this region after we load an OS.
695
ufree ( buffer->data );
701
* @v rndis RNDIS device
702
* @ret rc Return status code
704
static int netvsc_open ( struct rndis_device *rndis ) {
705
struct netvsc_device *netvsc = rndis->priv;
708
/* Initialise receive buffer */
709
if ( ( rc = netvsc_create_buffer ( netvsc, &netvsc->rx ) ) != 0 )
713
if ( ( rc = vmbus_open ( netvsc->vmdev, &netvsc_channel_operations,
714
PAGE_SIZE, PAGE_SIZE, NETVSC_MTU ) ) != 0 ) {
715
DBGC ( netvsc, "NETVSC %s could not open VMBus: %s\n",
716
netvsc->name, strerror ( rc ) );
720
/* Initialise communication with NetVSP */
721
if ( ( rc = netvsc_initialise ( netvsc ) ) != 0 )
723
if ( ( rc = netvsc_ndis_version ( netvsc ) ) != 0 )
724
goto err_ndis_version;
726
/* Initialise transmit ring */
727
if ( ( rc = netvsc_create_ring ( netvsc, &netvsc->tx ) ) != 0 )
730
/* Establish receive buffer */
731
if ( ( rc = netvsc_establish_buffer ( netvsc, &netvsc->rx ) ) != 0 )
732
goto err_establish_rx;
736
netvsc_revoke_buffer ( netvsc, &netvsc->rx );
738
netvsc_destroy_ring ( netvsc, &netvsc->tx, NULL );
742
vmbus_close ( netvsc->vmdev );
744
netvsc_destroy_buffer ( netvsc, &netvsc->rx );
752
* @v rndis RNDIS device
754
static void netvsc_close ( struct rndis_device *rndis ) {
755
struct netvsc_device *netvsc = rndis->priv;
757
/* Revoke receive buffer */
758
netvsc_revoke_buffer ( netvsc, &netvsc->rx );
760
/* Destroy transmit ring */
761
netvsc_destroy_ring ( netvsc, &netvsc->tx, netvsc_cancel_transmit );
764
vmbus_close ( netvsc->vmdev );
766
/* Destroy receive buffer */
767
netvsc_destroy_buffer ( netvsc, &netvsc->rx );
770
/** RNDIS operations */
771
static struct rndis_operations netvsc_operations = {
773
.close = netvsc_close,
774
.transmit = netvsc_transmit,
781
* @v vmdev VMBus device
782
* @ret rc Return status code
784
static int netvsc_probe ( struct vmbus_device *vmdev ) {
785
struct netvsc_device *netvsc;
786
struct rndis_device *rndis;
789
/* Allocate and initialise structure */
790
rndis = alloc_rndis ( sizeof ( *netvsc ) );
795
rndis_init ( rndis, &netvsc_operations );
796
rndis->netdev->dev = &vmdev->dev;
797
netvsc = rndis->priv;
798
netvsc->vmdev = vmdev;
799
netvsc->rndis = rndis;
800
netvsc->name = vmdev->dev.name;
801
netvsc_init_ring ( &netvsc->tx, NETVSC_TX_NUM_DESC,
802
netvsc->tx_iobufs, netvsc->tx_ids );
803
netvsc_init_buffer ( &netvsc->rx, NETVSC_RX_BUF_PAGESET,
804
&netvsc_xfer_pages_operations,
805
NETVSC_RX_ESTABLISH_MSG, NETVSC_RX_ESTABLISH_XRID,
806
NETVSC_RX_REVOKE_MSG, NETVSC_RX_REVOKE_XRID,
808
vmbus_set_drvdata ( vmdev, rndis );
810
/* Register RNDIS device */
811
if ( ( rc = register_rndis ( rndis ) ) != 0 ) {
812
DBGC ( netvsc, "NETVSC %s could not register: %s\n",
813
netvsc->name, strerror ( rc ) );
819
unregister_rndis ( rndis );
821
free_rndis ( rndis );
829
* @v vmdev VMBus device
831
static void netvsc_remove ( struct vmbus_device *vmdev ) {
832
struct rndis_device *rndis = vmbus_get_drvdata ( vmdev );
834
/* Unregister RNDIS device */
835
unregister_rndis ( rndis );
837
/* Free RNDIS device */
838
free_rndis ( rndis );
842
struct vmbus_driver netvsc_driver __vmbus_driver = {
844
.type = VMBUS_TYPE ( 0xf8615163, 0xdf3e, 0x46c5, 0x913f,
845
0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e ),
846
.probe = netvsc_probe,
847
.remove = netvsc_remove,