|
@@ -56,6 +56,39 @@ struct errortab netdev_errors[] __errortab = {
|
56
|
56
|
__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
|
57
|
57
|
};
|
58
|
58
|
|
|
59
|
+/**
|
|
60
|
+ * Notify drivers of network device or link state change
|
|
61
|
+ *
|
|
62
|
+ * @v netdev Network device
|
|
63
|
+ */
|
|
64
|
+static void netdev_notify ( struct net_device *netdev ) {
|
|
65
|
+ struct net_driver *driver;
|
|
66
|
+
|
|
67
|
+ for_each_table_entry ( driver, NET_DRIVERS )
|
|
68
|
+ driver->notify ( netdev );
|
|
69
|
+}
|
|
70
|
+
|
|
71
|
+/**
|
|
72
|
+ * Mark network device as having a specific link state
|
|
73
|
+ *
|
|
74
|
+ * @v netdev Network device
|
|
75
|
+ * @v rc Link status code
|
|
76
|
+ */
|
|
77
|
+void netdev_link_err ( struct net_device *netdev, int rc ) {
|
|
78
|
+
|
|
79
|
+ /* Record link state */
|
|
80
|
+ netdev->link_rc = rc;
|
|
81
|
+ if ( netdev->link_rc == 0 ) {
|
|
82
|
+ DBGC ( netdev, "NETDEV %p link is up\n", netdev );
|
|
83
|
+ } else {
|
|
84
|
+ DBGC ( netdev, "NETDEV %p link is down: %s\n",
|
|
85
|
+ netdev, strerror ( netdev->link_rc ) );
|
|
86
|
+ }
|
|
87
|
+
|
|
88
|
+ /* Notify drivers of link state change */
|
|
89
|
+ netdev_notify ( netdev );
|
|
90
|
+}
|
|
91
|
+
|
59
|
92
|
/**
|
60
|
93
|
* Mark network device as having link down
|
61
|
94
|
*
|
|
@@ -68,7 +101,7 @@ void netdev_link_down ( struct net_device *netdev ) {
|
68
|
101
|
*/
|
69
|
102
|
if ( ( netdev->link_rc == 0 ) ||
|
70
|
103
|
( netdev->link_rc == -EUNKNOWN_LINK_STATUS ) ) {
|
71
|
|
- netdev->link_rc = -ENOTCONN;
|
|
104
|
+ netdev_link_err ( netdev, -ENOTCONN );
|
72
|
105
|
}
|
73
|
106
|
}
|
74
|
107
|
|
|
@@ -367,6 +400,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
|
367
|
400
|
*/
|
368
|
401
|
int register_netdev ( struct net_device *netdev ) {
|
369
|
402
|
static unsigned int ifindex = 0;
|
|
403
|
+ struct net_driver *driver;
|
370
|
404
|
int rc;
|
371
|
405
|
|
372
|
406
|
/* Create device name */
|
|
@@ -376,22 +410,38 @@ int register_netdev ( struct net_device *netdev ) {
|
376
|
410
|
/* Set initial link-layer address */
|
377
|
411
|
netdev->ll_protocol->init_addr ( netdev->hw_addr, netdev->ll_addr );
|
378
|
412
|
|
|
413
|
+ /* Add to device list */
|
|
414
|
+ netdev_get ( netdev );
|
|
415
|
+ list_add_tail ( &netdev->list, &net_devices );
|
|
416
|
+ DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
|
|
417
|
+ netdev, netdev->name, netdev->dev->name,
|
|
418
|
+ netdev_addr ( netdev ) );
|
|
419
|
+
|
379
|
420
|
/* Register per-netdev configuration settings */
|
380
|
421
|
if ( ( rc = register_settings ( netdev_settings ( netdev ),
|
381
|
422
|
NULL ) ) != 0 ) {
|
382
|
423
|
DBGC ( netdev, "NETDEV %p could not register settings: %s\n",
|
383
|
424
|
netdev, strerror ( rc ) );
|
384
|
|
- return rc;
|
|
425
|
+ goto err_register_settings;
|
385
|
426
|
}
|
386
|
427
|
|
387
|
|
- /* Add to device list */
|
388
|
|
- netdev_get ( netdev );
|
389
|
|
- list_add_tail ( &netdev->list, &net_devices );
|
390
|
|
- DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n",
|
391
|
|
- netdev, netdev->name, netdev->dev->name,
|
392
|
|
- netdev_addr ( netdev ) );
|
|
428
|
+ /* Probe device */
|
|
429
|
+ for_each_table_entry ( driver, NET_DRIVERS ) {
|
|
430
|
+ if ( ( rc = driver->probe ( netdev ) ) != 0 ) {
|
|
431
|
+ DBGC ( netdev, "NETDEV %p could not add %s device: "
|
|
432
|
+ "%s\n", netdev, driver->name, strerror ( rc ) );
|
|
433
|
+ goto err_probe;
|
|
434
|
+ }
|
|
435
|
+ }
|
393
|
436
|
|
394
|
437
|
return 0;
|
|
438
|
+
|
|
439
|
+ err_probe:
|
|
440
|
+ for_each_table_entry_continue_reverse ( driver, NET_DRIVERS )
|
|
441
|
+ driver->remove ( netdev );
|
|
442
|
+ unregister_settings ( netdev_settings ( netdev ) );
|
|
443
|
+ err_register_settings:
|
|
444
|
+ return rc;
|
395
|
445
|
}
|
396
|
446
|
|
397
|
447
|
/**
|
|
@@ -419,6 +469,9 @@ int netdev_open ( struct net_device *netdev ) {
|
419
|
469
|
/* Add to head of open devices list */
|
420
|
470
|
list_add ( &netdev->open_list, &open_net_devices );
|
421
|
471
|
|
|
472
|
+ /* Notify drivers of device state change */
|
|
473
|
+ netdev_notify ( netdev );
|
|
474
|
+
|
422
|
475
|
return 0;
|
423
|
476
|
}
|
424
|
477
|
|
|
@@ -435,18 +488,21 @@ void netdev_close ( struct net_device *netdev ) {
|
435
|
488
|
|
436
|
489
|
DBGC ( netdev, "NETDEV %p closing\n", netdev );
|
437
|
490
|
|
|
491
|
+ /* Remove from open devices list */
|
|
492
|
+ list_del ( &netdev->open_list );
|
|
493
|
+
|
|
494
|
+ /* Mark as closed */
|
|
495
|
+ netdev->state &= ~NETDEV_OPEN;
|
|
496
|
+
|
|
497
|
+ /* Notify drivers of device state change */
|
|
498
|
+ netdev_notify ( netdev );
|
|
499
|
+
|
438
|
500
|
/* Close the device */
|
439
|
501
|
netdev->op->close ( netdev );
|
440
|
502
|
|
441
|
503
|
/* Flush TX and RX queues */
|
442
|
504
|
netdev_tx_flush ( netdev );
|
443
|
505
|
netdev_rx_flush ( netdev );
|
444
|
|
-
|
445
|
|
- /* Mark as closed */
|
446
|
|
- netdev->state &= ~NETDEV_OPEN;
|
447
|
|
-
|
448
|
|
- /* Remove from open devices list */
|
449
|
|
- list_del ( &netdev->open_list );
|
450
|
506
|
}
|
451
|
507
|
|
452
|
508
|
/**
|
|
@@ -457,10 +513,15 @@ void netdev_close ( struct net_device *netdev ) {
|
457
|
513
|
* Removes the network device from the list of network devices.
|
458
|
514
|
*/
|
459
|
515
|
void unregister_netdev ( struct net_device *netdev ) {
|
|
516
|
+ struct net_driver *driver;
|
460
|
517
|
|
461
|
518
|
/* Ensure device is closed */
|
462
|
519
|
netdev_close ( netdev );
|
463
|
520
|
|
|
521
|
+ /* Remove device */
|
|
522
|
+ for_each_table_entry_reverse ( driver, NET_DRIVERS )
|
|
523
|
+ driver->remove ( netdev );
|
|
524
|
+
|
464
|
525
|
/* Unregister per-netdev configuration settings */
|
465
|
526
|
unregister_settings ( netdev_settings ( netdev ) );
|
466
|
527
|
|