+ int (*get_features)(const struct netdev *netdev,
+ enum netdev_features *current,
+ enum netdev_features *advertised,
+ enum netdev_features *supported,
+ enum netdev_features *peer);
+ enum netdev_features dummy[4];
+ int error;
+
+ if (!current) {
+ current = &dummy[0];
+ }
+ if (!advertised) {
+ advertised = &dummy[1];
+ }
+ if (!supported) {
+ supported = &dummy[2];
+ }
+ if (!peer) {
+ peer = &dummy[3];
+ }
+
+ get_features = netdev_get_dev(netdev)->netdev_class->get_features;
+ error = get_features
+ ? get_features(netdev, current, advertised, supported,
+ peer)
+ : EOPNOTSUPP;
+ if (error) {
+ *current = *advertised = *supported = *peer = 0;
+ }
+ return error;
+}
+
+/* Returns the maximum speed of a network connection that has the NETDEV_F_*
+ * bits in 'features', in bits per second. If no bits that indicate a speed
+ * are set in 'features', assumes 100Mbps. */
+uint64_t
+netdev_features_to_bps(enum netdev_features features)
+{
+ enum {
+ F_1000000MB = NETDEV_F_1TB_FD,
+ F_100000MB = NETDEV_F_100GB_FD,
+ F_40000MB = NETDEV_F_40GB_FD,
+ F_10000MB = NETDEV_F_10GB_FD,
+ F_1000MB = NETDEV_F_1GB_HD | NETDEV_F_1GB_FD,
+ F_100MB = NETDEV_F_100MB_HD | NETDEV_F_100MB_FD,
+ F_10MB = NETDEV_F_10MB_HD | NETDEV_F_10MB_FD
+ };
+
+ return ( features & F_1000000MB ? UINT64_C(1000000000000)
+ : features & F_100000MB ? UINT64_C(100000000000)
+ : features & F_40000MB ? UINT64_C(40000000000)
+ : features & F_10000MB ? UINT64_C(10000000000)
+ : features & F_1000MB ? UINT64_C(1000000000)
+ : features & F_100MB ? UINT64_C(100000000)
+ : features & F_10MB ? UINT64_C(10000000)
+ : UINT64_C(100000000));
+}
+
+/* Returns true if any of the NETDEV_F_* bits that indicate a full-duplex link
+ * are set in 'features', otherwise false. */
+bool
+netdev_features_is_full_duplex(enum netdev_features features)
+{
+ return (features & (NETDEV_F_10MB_FD | NETDEV_F_100MB_FD | NETDEV_F_1GB_FD
+ | NETDEV_F_10GB_FD | NETDEV_F_40GB_FD
+ | NETDEV_F_100GB_FD | NETDEV_F_1TB_FD)) != 0;