The SFF decoders assume the buffer is large enough for the module
type: SFF-8079 and SFF-8472 do not receive the length at all,
and SFF-8636 reads the alarm and warning thresholds from page 03h
even when only 256 bytes are available.
If a driver reports a length shorter than the type requires,
the decoders read past the end of the buffer.

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.
In the SFF-8636 decoder, read the thresholds only if page 03h
is available, as it is already done when printing them.

This is a preparation for exposing the decoders to applications,
which may pass buffers of arbitrary length.

Signed-off-by: Roman Khromenok <[email protected]>
---
v2: do not read SFF-8636 thresholds when page 03h is not available

 lib/ethdev/sff_8636.c      | 52 ++++++++++++++++++++------------------
 lib/ethdev/sff_telemetry.c | 37 +++++++++++++++++++++------
 lib/ethdev/sff_telemetry.h |  8 ++++++
 3 files changed, 64 insertions(+), 33 deletions(-)

diff --git a/lib/ethdev/sff_8636.c b/lib/ethdev/sff_8636.c
index 17058d4bfd..ac55c8e0b6 100644
--- a/lib/ethdev/sff_8636.c
+++ b/lib/ethdev/sff_8636.c
@@ -600,34 +600,36 @@ static void sff_8636_dom_parse(const uint8_t *data, 
struct sff_diags *sd)
 {
        int i = 0;
 
-       /* Monitoring Thresholds for Alarms and Warnings */
        sd->sfp_voltage[SFF_MCURR] = SFF_OFFSET_TO_U16(SFF_8636_VCC_CURR);
-       sd->sfp_voltage[SFF_HALRM] = SFF_OFFSET_TO_U16(SFF_8636_VCC_HALRM);
-       sd->sfp_voltage[SFF_LALRM] = SFF_OFFSET_TO_U16(SFF_8636_VCC_LALRM);
-       sd->sfp_voltage[SFF_HWARN] = SFF_OFFSET_TO_U16(SFF_8636_VCC_HWARN);
-       sd->sfp_voltage[SFF_LWARN] = SFF_OFFSET_TO_U16(SFF_8636_VCC_LWARN);
-
        sd->sfp_temp[SFF_MCURR] = SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_CURR);
-       sd->sfp_temp[SFF_HALRM] = SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_HALRM);
-       sd->sfp_temp[SFF_LALRM] = SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_LALRM);
-       sd->sfp_temp[SFF_HWARN] = SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_HWARN);
-       sd->sfp_temp[SFF_LWARN] = SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_LWARN);
-
-       sd->bias_cur[SFF_HALRM] = SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_HALRM);
-       sd->bias_cur[SFF_LALRM] = SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_LALRM);
-       sd->bias_cur[SFF_HWARN] = SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_HWARN);
-       sd->bias_cur[SFF_LWARN] = SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_LWARN);
-
-       sd->tx_power[SFF_HALRM] = SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_HALRM);
-       sd->tx_power[SFF_LALRM] = SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_LALRM);
-       sd->tx_power[SFF_HWARN] = SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_HWARN);
-       sd->tx_power[SFF_LWARN] = SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_LWARN);
-
-       sd->rx_power[SFF_HALRM] = SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_HALRM);
-       sd->rx_power[SFF_LALRM] = SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_LALRM);
-       sd->rx_power[SFF_HWARN] = SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_HWARN);
-       sd->rx_power[SFF_LWARN] = SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_LWARN);
 
+       /* Monitoring Thresholds for Alarms and Warnings are in page 03h */
+       if (sd->supports_alarms) {
+               sd->sfp_voltage[SFF_HALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_VCC_HALRM);
+               sd->sfp_voltage[SFF_LALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_VCC_LALRM);
+               sd->sfp_voltage[SFF_HWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_VCC_HWARN);
+               sd->sfp_voltage[SFF_LWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_VCC_LWARN);
+
+               sd->sfp_temp[SFF_HALRM] = 
SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_HALRM);
+               sd->sfp_temp[SFF_LALRM] = 
SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_LALRM);
+               sd->sfp_temp[SFF_HWARN] = 
SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_HWARN);
+               sd->sfp_temp[SFF_LWARN] = 
SFF_8636_OFFSET_TO_TEMP(SFF_8636_TEMP_LWARN);
+
+               sd->bias_cur[SFF_HALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_HALRM);
+               sd->bias_cur[SFF_LALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_LALRM);
+               sd->bias_cur[SFF_HWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_HWARN);
+               sd->bias_cur[SFF_LWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_BIAS_LWARN);
+
+               sd->tx_power[SFF_HALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_HALRM);
+               sd->tx_power[SFF_LALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_LALRM);
+               sd->tx_power[SFF_HWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_HWARN);
+               sd->tx_power[SFF_LWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_TX_PWR_LWARN);
+
+               sd->rx_power[SFF_HALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_HALRM);
+               sd->rx_power[SFF_LALRM] = 
SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_LALRM);
+               sd->rx_power[SFF_HWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_HWARN);
+               sd->rx_power[SFF_LWARN] = 
SFF_OFFSET_TO_U16(SFF_8636_RX_PWR_LWARN);
+       }
 
        /* Channel Specific Data */
        for (i = 0; i < SFF_MAX_CHANNEL_NUM; i++) {
diff --git a/lib/ethdev/sff_telemetry.c b/lib/ethdev/sff_telemetry.c
index 8c8e95affe..72d55322b6 100644
--- a/lib/ethdev/sff_telemetry.c
+++ b/lib/ethdev/sff_telemetry.c
@@ -99,25 +99,46 @@ sff_port_module_eeprom_parse(uint16_t port_id, struct 
rte_tel_data *d)
                return;
        }
 
-       switch (minfo.type) {
+       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);
+       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);
+}
+
+int
+sff_decode_module_eeprom(uint32_t type, const uint8_t *data, uint32_t length,
+                        struct sff_output *d)
+{
+       switch (type) {
        /* parsing module EEPROM data base on different module type */
        case RTE_ETH_MODULE_SFF_8079:
-               sff_8079_show_all(einfo.data, &out);
+               if (length < RTE_ETH_MODULE_SFF_8079_LEN)
+                       return -EINVAL;
+               sff_8079_show_all(data, d);
                break;
        case RTE_ETH_MODULE_SFF_8472:
-               sff_8079_show_all(einfo.data, &out);
-               sff_8472_show_all(einfo.data, &out);
+               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:
-               sff_8636_show_all(einfo.data, einfo.length, &out);
+               if (length < RTE_ETH_MODULE_SFF_8636_LEN)
+                       return -EINVAL;
+               sff_8636_show_all(data, length, d);
                break;
        default:
-               RTE_ETHDEV_LOG_LINE(NOTICE, "Unsupported module type: %u", 
minfo.type);
-               break;
+               return -ENOTSUP;
        }
 
-       free(einfo.data);
+       return 0;
 }
 
 void
diff --git a/lib/ethdev/sff_telemetry.h b/lib/ethdev/sff_telemetry.h
index 2a6d79a9c1..1d2c8fd444 100644
--- a/lib/ethdev/sff_telemetry.h
+++ b/lib/ethdev/sff_telemetry.h
@@ -25,6 +25,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);
+
 int eth_dev_handle_port_module_eeprom(const char *cmd __rte_unused,
                                      const char *params,
                                      struct rte_tel_data *d);
-- 
2.47.3

Reply via email to