diff --git a/netlink/settings.c b/netlink/settings.c
index 35ba2f5..2f5875d 100644
--- a/netlink/settings.c
+++ b/netlink/settings.c
@@ -604,6 +604,149 @@ int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 	return MNL_CB_OK;
 }
 
+static const char *get_enum_string(const char *const *string_table, unsigned int n_string_table,
+				   unsigned int val)
+{
+	if (val >= n_string_table || !string_table[val])
+		return NULL;
+	else
+		return string_table[val];
+}
+
+static const char *const names_link_ext_state[] = {
+	[ETHTOOL_LINK_EXT_STATE_AUTONEG]		= "Autoneg",
+	[ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE]	= "Link training failure",
+	[ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH]	= "Logical mismatch",
+	[ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY]	= "Bad signal integrity",
+	[ETHTOOL_LINK_EXT_STATE_NO_CABLE]		= "No cable",
+	[ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE]		= "Cable issue",
+	[ETHTOOL_LINK_EXT_STATE_EEPROM_ISSUE]		= "EEPROM issue",
+	[ETHTOOL_LINK_EXT_STATE_CALIBRATION_FAILURE]	= "Calibration failure",
+	[ETHTOOL_LINK_EXT_STATE_POWER_BUDGET_EXCEEDED]	= "Power budget exceeded",
+	[ETHTOOL_LINK_EXT_STATE_OVERHEAT]		= "Overheat",
+};
+
+static const char *const names_autoneg_link_ext_substate[] = {
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED]		=
+		"No partner detected",
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_ACK_NOT_RECEIVED]			=
+		"Ack not received",
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NEXT_PAGE_EXCHANGE_FAILED]	=
+		"Next page exchange failed",
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_PARTNER_DETECTED_FORCE_MODE]	=
+		"No partner detected during force mode",
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_FEC_MISMATCH_DURING_OVERRIDE]	=
+		"FEC mismatch during override",
+	[ETHTOOL_LINK_EXT_SUBSTATE_AN_NO_HCD]				=
+		"No HCD",
+};
+
+static const char *const names_link_training_link_ext_substate[] = {
+	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_FRAME_LOCK_NOT_ACQUIRED]			=
+		"KR frame lock not acquired",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_INHIBIT_TIMEOUT]				=
+		"KR link inhibit timeout",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LT_KR_LINK_PARTNER_DID_NOT_SET_RECEIVER_READY]	=
+		"KR Link partner did not set receiver ready",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LT_REMOTE_FAULT]					=
+		"Remote side is not ready yet",
+};
+
+static const char *const names_link_logical_mismatch_link_ext_substate[] = {
+	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_BLOCK_LOCK]	=
+		"PCS did not acquire block lock",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_ACQUIRE_AM_LOCK]	=
+		"PCS did not acquire AM lock",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_PCS_DID_NOT_GET_ALIGN_STATUS]	=
+		"PCS did not get align_status",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_FC_FEC_IS_NOT_LOCKED]		=
+		"FC FEC is not locked",
+	[ETHTOOL_LINK_EXT_SUBSTATE_LLM_RS_FEC_IS_NOT_LOCKED]		=
+		"RS FEC is not locked",
+};
+
+static const char *const names_bad_signal_integrity_link_ext_substate[] = {
+	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_LARGE_NUMBER_OF_PHYSICAL_ERRORS]	=
+		"Large number of physical errors",
+	[ETHTOOL_LINK_EXT_SUBSTATE_BSI_UNSUPPORTED_RATE]		=
+		"Unsupported rate",
+};
+
+static const char *const names_cable_issue_link_ext_substate[] = {
+	[ETHTOOL_LINK_EXT_SUBSTATE_CI_UNSUPPORTED_CABLE]	=
+		"Unsupported cable",
+	[ETHTOOL_LINK_EXT_SUBSTATE_CI_CABLE_TEST_FAILURE]	=
+		"Cable test failure",
+};
+
+static const char *link_ext_substate_get(uint8_t link_ext_state_val, uint8_t link_ext_substate_val)
+{
+	switch (link_ext_state_val) {
+	case ETHTOOL_LINK_EXT_STATE_AUTONEG:
+		return get_enum_string(names_autoneg_link_ext_substate,
+				       ARRAY_SIZE(names_autoneg_link_ext_substate),
+				       link_ext_substate_val);
+	case ETHTOOL_LINK_EXT_STATE_LINK_TRAINING_FAILURE:
+		return get_enum_string(names_link_training_link_ext_substate,
+				       ARRAY_SIZE(names_link_training_link_ext_substate),
+				       link_ext_substate_val);
+	case ETHTOOL_LINK_EXT_STATE_LINK_LOGICAL_MISMATCH:
+		return get_enum_string(names_link_logical_mismatch_link_ext_substate,
+				       ARRAY_SIZE(names_link_logical_mismatch_link_ext_substate),
+				       link_ext_substate_val);
+	case ETHTOOL_LINK_EXT_STATE_BAD_SIGNAL_INTEGRITY:
+		return get_enum_string(names_bad_signal_integrity_link_ext_substate,
+				       ARRAY_SIZE(names_bad_signal_integrity_link_ext_substate),
+				       link_ext_substate_val);
+	case ETHTOOL_LINK_EXT_STATE_CABLE_ISSUE:
+		return get_enum_string(names_cable_issue_link_ext_substate,
+				       ARRAY_SIZE(names_cable_issue_link_ext_substate),
+				       link_ext_substate_val);
+	default:
+		return NULL;
+	}
+}
+
+static void linkstate_link_ext_substate_print(const struct nlattr *tb[], struct nl_context *nlctx,
+					      uint8_t link_ext_state_val)
+{
+	uint8_t link_ext_substate_val;
+	const char *link_ext_substate_str;
+
+	if (!tb[ETHTOOL_A_LINKSTATE_EXT_SUBSTATE])
+		return;
+
+	link_ext_substate_val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_EXT_SUBSTATE]);
+
+	link_ext_substate_str = link_ext_substate_get(link_ext_state_val, link_ext_substate_val);
+	if (!link_ext_substate_str)
+		printf(", %u", link_ext_substate_val);
+	else
+		printf(", %s", link_ext_substate_str);
+}
+
+static void linkstate_link_ext_state_print(const struct nlattr *tb[], struct nl_context *nlctx)
+{
+	uint8_t link_ext_state_val;
+	const char *link_ext_state_str;
+
+	if (!tb[ETHTOOL_A_LINKSTATE_EXT_STATE])
+		return;
+
+	link_ext_state_val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_EXT_STATE]);
+
+	link_ext_state_str = get_enum_string(names_link_ext_state,
+					     ARRAY_SIZE(names_link_ext_state),
+					     link_ext_state_val);
+	if (!link_ext_state_str)
+		printf(" (%u", link_ext_state_val);
+	else
+		printf(" (%s", link_ext_state_str);
+
+	linkstate_link_ext_substate_print(tb, nlctx, link_ext_state_val);
+	printf(")");
+}
+
 int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 {
 	const struct nlattr *tb[ETHTOOL_A_LINKSTATE_MAX + 1] = {};
@@ -624,7 +767,9 @@ int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data)
 		uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_LINK]);
 
 		print_banner(nlctx);
-		printf("\tLink detected: %s\n", val ? "yes" : "no");
+		printf("\tLink detected: %s", val ? "yes" : "no");
+		linkstate_link_ext_state_print(tb, nlctx);
+		printf("\n");
 	}
 
 	if (tb[ETHTOOL_A_LINKSTATE_SQI]) {
