|
@@ -54,6 +54,16 @@ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
|
54
|
54
|
#define EINFO_EUNKNOWN_LINK_STATUS \
|
55
|
55
|
__einfo_uniqify ( EINFO_EINPROGRESS, 0x01, "Unknown" )
|
56
|
56
|
|
|
57
|
+/** Default not-yet-attempted-configuration status code */
|
|
58
|
+#define EUNUSED_CONFIG __einfo_error ( EINFO_EUNUSED_CONFIG )
|
|
59
|
+#define EINFO_EUNUSED_CONFIG \
|
|
60
|
+ __einfo_uniqify ( EINFO_EINPROGRESS, 0x02, "Unused" )
|
|
61
|
+
|
|
62
|
+/** Default configuration-in-progress status code */
|
|
63
|
+#define EINPROGRESS_CONFIG __einfo_error ( EINFO_EINPROGRESS_CONFIG )
|
|
64
|
+#define EINFO_EINPROGRESS_CONFIG \
|
|
65
|
+ __einfo_uniqify ( EINFO_EINPROGRESS, 0x03, "Incomplete" )
|
|
66
|
+
|
57
|
67
|
/** Default link-down status code */
|
58
|
68
|
#define ENOTCONN_LINK_DOWN __einfo_error ( EINFO_ENOTCONN_LINK_DOWN )
|
59
|
69
|
#define EINFO_ENOTCONN_LINK_DOWN \
|
|
@@ -63,6 +73,8 @@ static struct list_head open_net_devices = LIST_HEAD_INIT ( open_net_devices );
|
63
|
73
|
struct errortab netdev_errors[] __errortab = {
|
64
|
74
|
__einfo_errortab ( EINFO_EUNKNOWN_LINK_STATUS ),
|
65
|
75
|
__einfo_errortab ( EINFO_ENOTCONN_LINK_DOWN ),
|
|
76
|
+ __einfo_errortab ( EINFO_EUNUSED_CONFIG ),
|
|
77
|
+ __einfo_errortab ( EINFO_EINPROGRESS_CONFIG ),
|
66
|
78
|
};
|
67
|
79
|
|
68
|
80
|
/**
|
|
@@ -443,6 +455,41 @@ static void netdev_rx_flush ( struct net_device *netdev ) {
|
443
|
455
|
}
|
444
|
456
|
}
|
445
|
457
|
|
|
458
|
+/**
|
|
459
|
+ * Finish network device configuration
|
|
460
|
+ *
|
|
461
|
+ * @v config Network device configuration
|
|
462
|
+ * @v rc Reason for completion
|
|
463
|
+ */
|
|
464
|
+static void netdev_config_close ( struct net_device_configuration *config,
|
|
465
|
+ int rc ) {
|
|
466
|
+ struct net_device_configurator *configurator = config->configurator;
|
|
467
|
+ struct net_device *netdev = config->netdev;
|
|
468
|
+
|
|
469
|
+ /* Restart interface */
|
|
470
|
+ intf_restart ( &config->job, rc );
|
|
471
|
+
|
|
472
|
+ /* Record configuration result */
|
|
473
|
+ config->rc = rc;
|
|
474
|
+ if ( rc == 0 ) {
|
|
475
|
+ DBGC ( netdev, "NETDEV %s configured via %s\n",
|
|
476
|
+ netdev->name, configurator->name );
|
|
477
|
+ } else {
|
|
478
|
+ DBGC ( netdev, "NETDEV %s configuration via %s failed: %s\n",
|
|
479
|
+ netdev->name, configurator->name, strerror ( rc ) );
|
|
480
|
+ }
|
|
481
|
+}
|
|
482
|
+
|
|
483
|
+/** Network device configuration interface operations */
|
|
484
|
+static struct interface_operation netdev_config_ops[] = {
|
|
485
|
+ INTF_OP ( intf_close, struct net_device_configuration *,
|
|
486
|
+ netdev_config_close ),
|
|
487
|
+};
|
|
488
|
+
|
|
489
|
+/** Network device configuration interface descriptor */
|
|
490
|
+static struct interface_descriptor netdev_config_desc =
|
|
491
|
+ INTF_DESC ( struct net_device_configuration, job, netdev_config_ops );
|
|
492
|
+
|
446
|
493
|
/**
|
447
|
494
|
* Free network device
|
448
|
495
|
*
|
|
@@ -461,16 +508,22 @@ static void free_netdev ( struct refcnt *refcnt ) {
|
461
|
508
|
/**
|
462
|
509
|
* Allocate network device
|
463
|
510
|
*
|
464
|
|
- * @v priv_size Size of private data area (net_device::priv)
|
|
511
|
+ * @v priv_len Length of private data area (net_device::priv)
|
465
|
512
|
* @ret netdev Network device, or NULL
|
466
|
513
|
*
|
467
|
514
|
* Allocates space for a network device and its private data area.
|
468
|
515
|
*/
|
469
|
|
-struct net_device * alloc_netdev ( size_t priv_size ) {
|
|
516
|
+struct net_device * alloc_netdev ( size_t priv_len ) {
|
470
|
517
|
struct net_device *netdev;
|
|
518
|
+ struct net_device_configurator *configurator;
|
|
519
|
+ struct net_device_configuration *config;
|
|
520
|
+ unsigned int num_configs;
|
|
521
|
+ size_t confs_len;
|
471
|
522
|
size_t total_len;
|
472
|
523
|
|
473
|
|
- total_len = ( sizeof ( *netdev ) + priv_size );
|
|
524
|
+ num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
|
|
525
|
+ confs_len = ( num_configs * sizeof ( netdev->configs[0] ) );
|
|
526
|
+ total_len = ( sizeof ( *netdev ) + confs_len + priv_len );
|
474
|
527
|
netdev = zalloc ( total_len );
|
475
|
528
|
if ( netdev ) {
|
476
|
529
|
ref_init ( &netdev->refcnt, free_netdev );
|
|
@@ -479,7 +532,17 @@ struct net_device * alloc_netdev ( size_t priv_size ) {
|
479
|
532
|
INIT_LIST_HEAD ( &netdev->tx_deferred );
|
480
|
533
|
INIT_LIST_HEAD ( &netdev->rx_queue );
|
481
|
534
|
netdev_settings_init ( netdev );
|
482
|
|
- netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) );
|
|
535
|
+ config = netdev->configs;
|
|
536
|
+ for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ){
|
|
537
|
+ config->netdev = netdev;
|
|
538
|
+ config->configurator = configurator;
|
|
539
|
+ config->rc = -EUNUSED_CONFIG;
|
|
540
|
+ intf_init ( &config->job, &netdev_config_desc,
|
|
541
|
+ &netdev->refcnt );
|
|
542
|
+ config++;
|
|
543
|
+ }
|
|
544
|
+ netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) +
|
|
545
|
+ confs_len );
|
483
|
546
|
}
|
484
|
547
|
return netdev;
|
485
|
548
|
}
|
|
@@ -595,6 +658,8 @@ int netdev_open ( struct net_device *netdev ) {
|
595
|
658
|
* @v netdev Network device
|
596
|
659
|
*/
|
597
|
660
|
void netdev_close ( struct net_device *netdev ) {
|
|
661
|
+ unsigned int num_configs;
|
|
662
|
+ unsigned int i;
|
598
|
663
|
|
599
|
664
|
/* Do nothing if device is already closed */
|
600
|
665
|
if ( ! ( netdev->state & NETDEV_OPEN ) )
|
|
@@ -602,6 +667,15 @@ void netdev_close ( struct net_device *netdev ) {
|
602
|
667
|
|
603
|
668
|
DBGC ( netdev, "NETDEV %s closing\n", netdev->name );
|
604
|
669
|
|
|
670
|
+ /* Terminate any ongoing configurations. Use intf_close()
|
|
671
|
+ * rather than intf_restart() to allow the cancellation to be
|
|
672
|
+ * reported back to us if a configuration is actually in
|
|
673
|
+ * progress.
|
|
674
|
+ */
|
|
675
|
+ num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
|
|
676
|
+ for ( i = 0 ; i < num_configs ; i++ )
|
|
677
|
+ intf_close ( &netdev->configs[i].job, -ECANCELED );
|
|
678
|
+
|
605
|
679
|
/* Remove from open devices list */
|
606
|
680
|
list_del ( &netdev->open_list );
|
607
|
681
|
|
|
@@ -643,9 +717,9 @@ void unregister_netdev ( struct net_device *netdev ) {
|
643
|
717
|
unregister_settings ( netdev_settings ( netdev ) );
|
644
|
718
|
|
645
|
719
|
/* Remove from device list */
|
|
720
|
+ DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
|
646
|
721
|
list_del ( &netdev->list );
|
647
|
722
|
netdev_put ( netdev );
|
648
|
|
- DBGC ( netdev, "NETDEV %s unregistered\n", netdev->name );
|
649
|
723
|
}
|
650
|
724
|
|
651
|
725
|
/** Enable or disable interrupts
|
|
@@ -931,3 +1005,127 @@ static unsigned int net_discard ( void ) {
|
931
|
1005
|
struct cache_discarder net_discarder __cache_discarder ( CACHE_NORMAL ) = {
|
932
|
1006
|
.discard = net_discard,
|
933
|
1007
|
};
|
|
1008
|
+
|
|
1009
|
+/**
|
|
1010
|
+ * Find network device configurator
|
|
1011
|
+ *
|
|
1012
|
+ * @v name Name
|
|
1013
|
+ * @ret configurator Network device configurator, or NULL
|
|
1014
|
+ */
|
|
1015
|
+struct net_device_configurator * find_netdev_configurator ( const char *name ) {
|
|
1016
|
+ struct net_device_configurator *configurator;
|
|
1017
|
+
|
|
1018
|
+ for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) {
|
|
1019
|
+ if ( strcmp ( configurator->name, name ) == 0 )
|
|
1020
|
+ return configurator;
|
|
1021
|
+ }
|
|
1022
|
+ return NULL;
|
|
1023
|
+}
|
|
1024
|
+
|
|
1025
|
+/**
|
|
1026
|
+ * Start network device configuration
|
|
1027
|
+ *
|
|
1028
|
+ * @v netdev Network device
|
|
1029
|
+ * @v configurator Network device configurator
|
|
1030
|
+ * @ret rc Return status code
|
|
1031
|
+ */
|
|
1032
|
+int netdev_configure ( struct net_device *netdev,
|
|
1033
|
+ struct net_device_configurator *configurator ) {
|
|
1034
|
+ struct net_device_configuration *config =
|
|
1035
|
+ netdev_configuration ( netdev, configurator );
|
|
1036
|
+ int rc;
|
|
1037
|
+
|
|
1038
|
+ /* Check applicability of configurator */
|
|
1039
|
+ if ( ! netdev_configurator_applies ( netdev, configurator ) ) {
|
|
1040
|
+ DBGC ( netdev, "NETDEV %s does not support configuration via "
|
|
1041
|
+ "%s\n", netdev->name, configurator->name );
|
|
1042
|
+ return -ENOTSUP;
|
|
1043
|
+ }
|
|
1044
|
+
|
|
1045
|
+ /* Terminate any ongoing configuration */
|
|
1046
|
+ intf_restart ( &config->job, -ECANCELED );
|
|
1047
|
+
|
|
1048
|
+ /* Mark configuration as being in progress */
|
|
1049
|
+ config->rc = -EINPROGRESS_CONFIG;
|
|
1050
|
+
|
|
1051
|
+ DBGC ( netdev, "NETDEV %s starting configuration via %s\n",
|
|
1052
|
+ netdev->name, configurator->name );
|
|
1053
|
+
|
|
1054
|
+ /* Start configuration */
|
|
1055
|
+ if ( ( rc = configurator->start ( &config->job, netdev ) ) != 0 ) {
|
|
1056
|
+ DBGC ( netdev, "NETDEV %s could not start configuration via "
|
|
1057
|
+ "%s: %s\n", netdev->name, configurator->name,
|
|
1058
|
+ strerror ( rc ) );
|
|
1059
|
+ config->rc = rc;
|
|
1060
|
+ return rc;
|
|
1061
|
+ }
|
|
1062
|
+
|
|
1063
|
+ return 0;
|
|
1064
|
+}
|
|
1065
|
+
|
|
1066
|
+/**
|
|
1067
|
+ * Start network device configuration via all supported configurators
|
|
1068
|
+ *
|
|
1069
|
+ * @v netdev Network device
|
|
1070
|
+ * @ret rc Return status code
|
|
1071
|
+ */
|
|
1072
|
+int netdev_configure_all ( struct net_device *netdev ) {
|
|
1073
|
+ struct net_device_configurator *configurator;
|
|
1074
|
+ int rc;
|
|
1075
|
+
|
|
1076
|
+ /* Start configuration for each configurator */
|
|
1077
|
+ for_each_table_entry ( configurator, NET_DEVICE_CONFIGURATORS ) {
|
|
1078
|
+
|
|
1079
|
+ /* Skip any inapplicable configurators */
|
|
1080
|
+ if ( ! netdev_configurator_applies ( netdev, configurator ) )
|
|
1081
|
+ continue;
|
|
1082
|
+
|
|
1083
|
+ /* Start configuration */
|
|
1084
|
+ if ( ( rc = netdev_configure ( netdev, configurator ) ) != 0 )
|
|
1085
|
+ return rc;
|
|
1086
|
+ }
|
|
1087
|
+
|
|
1088
|
+ return 0;
|
|
1089
|
+}
|
|
1090
|
+
|
|
1091
|
+/**
|
|
1092
|
+ * Check if network device has a configuration with a specified status code
|
|
1093
|
+ *
|
|
1094
|
+ * @v netdev Network device
|
|
1095
|
+ * @v rc Status code
|
|
1096
|
+ * @ret has_rc Network device has a configuration with this status code
|
|
1097
|
+ */
|
|
1098
|
+static int netdev_has_configuration_rc ( struct net_device *netdev, int rc ) {
|
|
1099
|
+ unsigned int num_configs;
|
|
1100
|
+ unsigned int i;
|
|
1101
|
+
|
|
1102
|
+ num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS );
|
|
1103
|
+ for ( i = 0 ; i < num_configs ; i++ ) {
|
|
1104
|
+ if ( netdev->configs[i].rc == rc )
|
|
1105
|
+ return 1;
|
|
1106
|
+ }
|
|
1107
|
+ return 0;
|
|
1108
|
+}
|
|
1109
|
+
|
|
1110
|
+/**
|
|
1111
|
+ * Check if network device configuration is in progress
|
|
1112
|
+ *
|
|
1113
|
+ * @v netdev Network device
|
|
1114
|
+ * @ret is_in_progress Network device configuration is in progress
|
|
1115
|
+ */
|
|
1116
|
+int netdev_configuration_in_progress ( struct net_device *netdev ) {
|
|
1117
|
+
|
|
1118
|
+ return netdev_has_configuration_rc ( netdev, -EINPROGRESS_CONFIG );
|
|
1119
|
+}
|
|
1120
|
+
|
|
1121
|
+/**
|
|
1122
|
+ * Check if network device has at least one successful configuration
|
|
1123
|
+ *
|
|
1124
|
+ * @v netdev Network device
|
|
1125
|
+ * @v configurator Configurator
|
|
1126
|
+ * @ret rc Return status code
|
|
1127
|
+ */
|
|
1128
|
+int netdev_configuration_ok ( struct net_device *netdev ) {
|
|
1129
|
+
|
|
1130
|
+ return netdev_has_configuration_rc ( netdev, 0 );
|
|
1131
|
+}
|