[PATCH v3 3/6] ethdev: check module EEPROM length before decoding

Roman Khromenok roma55592 at yandex.ru
Tue Sep 29 09:07:31 CEST 2026


The SFF-8079 and SFF-8472 decoders do not receive the buffer length
and assume it is large enough for the module type.
This holds for the telemetry command, which allocates the length
reported by the driver, but not for other callers.

Move the type dispatch into a common internal function which checks
the minimal length for each type before decoding:
- SFF-8079 and SFF-8436/8636 require at least 256 bytes,
- SFF-8472 requires 256 bytes for the base information,
  and the diagnostics (page A2h) are decoded only if 512 bytes
  are available.

Also decode the SFF-8636 thresholds and alarm flags when the data
is longer than 640 bytes, not only when it is exactly 640 bytes.

This is a preparation for exposing the decoders to applications.

Signed-off-by: Roman Khromenok <roma55592 at yandex.ru>
---
v3: SFF-8636 fix moved to patch 1, decode thresholds for length >= 640

 lib/ethdev/sff_8636.c      |  2 +-
 lib/ethdev/sff_common.c    | 31 +++++++++++++++++++++++++++++++
 lib/ethdev/sff_common.h    |  8 ++++++++
 lib/ethdev/sff_telemetry.c | 21 +++++----------------
 4 files changed, 45 insertions(+), 17 deletions(-)

diff --git a/lib/ethdev/sff_8636.c b/lib/ethdev/sff_8636.c
index bbd00cc0ca..40e5404caf 100644
--- a/lib/ethdev/sff_8636.c
+++ b/lib/ethdev/sff_8636.c
@@ -656,7 +656,7 @@ static void sff_8636_show_dom(const uint8_t *data, uint32_t eeprom_len, struct s
 	 * If pagging support exists, then supports_alarms is marked as 1
 	 */
 
-	if (eeprom_len == RTE_ETH_MODULE_SFF_8636_MAX_LEN) {
+	if (eeprom_len >= RTE_ETH_MODULE_SFF_8636_MAX_LEN) {
 		if (!(data[SFF_8636_STATUS_2_OFFSET] &
 					SFF_8636_STATUS_PAGE_3_PRESENT)) {
 			sd.supports_alarms = 1;
diff --git a/lib/ethdev/sff_common.c b/lib/ethdev/sff_common.c
index 1b48c0f6ea..a36bf83026 100644
--- a/lib/ethdev/sff_common.c
+++ b/lib/ethdev/sff_common.c
@@ -4,6 +4,7 @@
  * common utilities for SFF-8436/8636 and SFF-8472/8079
  */
 
+#include <errno.h>
 #include <math.h>
 
 #include "sff_common.h"
@@ -14,6 +15,36 @@ void sff_output_field(struct sff_output *d, const char *name_str,
 	d->field_cb(name_str, value_str, d->arg);
 }
 
+int sff_decode_module_eeprom(uint32_t type, const uint8_t *data, uint32_t length,
+			     struct sff_output *d)
+{
+	switch (type) {
+	case RTE_ETH_MODULE_SFF_8079:
+		if (length < RTE_ETH_MODULE_SFF_8079_LEN)
+			return -EINVAL;
+		sff_8079_show_all(data, d);
+		break;
+	case RTE_ETH_MODULE_SFF_8472:
+		if (length < RTE_ETH_MODULE_SFF_8079_LEN)
+			return -EINVAL;
+		sff_8079_show_all(data, d);
+		/* diagnostics are in the second page (A2h) */
+		if (length >= RTE_ETH_MODULE_SFF_8472_LEN)
+			sff_8472_show_all(data, d);
+		break;
+	case RTE_ETH_MODULE_SFF_8436:
+	case RTE_ETH_MODULE_SFF_8636:
+		if (length < RTE_ETH_MODULE_SFF_8636_LEN)
+			return -EINVAL;
+		sff_8636_show_all(data, length, d);
+		break;
+	default:
+		return -ENOTSUP;
+	}
+
+	return 0;
+}
+
 double sff_convert_mw_to_dbm(double mw)
 {
 	return (10. * log10(mw / 1000.)) + 30.;
diff --git a/lib/ethdev/sff_common.h b/lib/ethdev/sff_common.h
index 06f5a35e8e..6435f4d6f5 100644
--- a/lib/ethdev/sff_common.h
+++ b/lib/ethdev/sff_common.h
@@ -34,6 +34,14 @@ void sff_8472_show_all(const uint8_t *data, struct sff_output *d);
 /* SFF-8636 Optics diagnostics */
 void sff_8636_show_all(const uint8_t *data, uint32_t eeprom_len, struct sff_output *d);
 
+/*
+ * Decode module EEPROM of the given type (RTE_ETH_MODULE_SFF_*).
+ * Returns 0 on success, -EINVAL if the data is too short for the type,
+ * -ENOTSUP if the type is unknown.
+ */
+int sff_decode_module_eeprom(uint32_t type, const uint8_t *data, uint32_t length,
+			     struct sff_output *d);
+
 #define SFF_8024_ID_OFFSET			0x00
 #define SFF_8024_ID_UNKNOWN			0x00
 #define SFF_8024_ID_GBIC			0x01
diff --git a/lib/ethdev/sff_telemetry.c b/lib/ethdev/sff_telemetry.c
index 06a8122367..46533a9fc5 100644
--- a/lib/ethdev/sff_telemetry.c
+++ b/lib/ethdev/sff_telemetry.c
@@ -100,23 +100,12 @@ sff_port_module_eeprom_parse(uint16_t port_id, struct rte_tel_data *d)
 		return;
 	}
 
-	switch (minfo.type) {
-	/* parsing module EEPROM data base on different module type */
-	case RTE_ETH_MODULE_SFF_8079:
-		sff_8079_show_all(einfo.data, &out);
-		break;
-	case RTE_ETH_MODULE_SFF_8472:
-		sff_8079_show_all(einfo.data, &out);
-		sff_8472_show_all(einfo.data, &out);
-		break;
-	case RTE_ETH_MODULE_SFF_8436:
-	case RTE_ETH_MODULE_SFF_8636:
-		sff_8636_show_all(einfo.data, einfo.length, &out);
-		break;
-	default:
+	ret = sff_decode_module_eeprom(minfo.type, einfo.data, einfo.length, &out);
+	if (ret == -ENOTSUP)
 		RTE_ETHDEV_LOG_LINE(NOTICE, "Unsupported module type: %u", minfo.type);
-		break;
-	}
+	else if (ret != 0)
+		RTE_ETHDEV_LOG_LINE(ERR, "Port %u module EEPROM is too short: %u bytes",
+			port_id, einfo.length);
 
 	free(einfo.data);
 }
-- 
2.47.3



More information about the dev mailing list