From fdb457a0ebb57c99fb987d0e34b2549f10dd4161 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Tue, 12 Oct 2021 16:25:21 +0300 Subject: [PATCH 22/35] netlink: eeprom: Export a function to request an EEPROM page The function will be used by the EEPROM parsing code (e.g., cmis.c) to request a specific page for parsing. All the data buffers used to store EEPROM page contents are stored on a linked list that is flushed on exit. This relieves callers from the need to explicitly free the requested pages. Signed-off-by: Ido Schimmel --- netlink/extapi.h | 11 +++++ netlink/module-eeprom.c | 105 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/netlink/extapi.h b/netlink/extapi.h index 91bf02b5e3be..129e2931d01d 100644 --- a/netlink/extapi.h +++ b/netlink/extapi.h @@ -48,6 +48,9 @@ int nl_getmodule(struct cmd_context *ctx); void nl_monitor_usage(void); +int nl_get_eeprom_page(struct cmd_context *ctx, + struct ethtool_module_eeprom *request); + #else /* ETHTOOL_ENABLE_NETLINK */ static inline void netlink_run_handler(struct cmd_context *ctx __maybe_unused, @@ -73,6 +76,14 @@ static inline void nl_monitor_usage(void) { } +static inline int +nl_get_eeprom_page(struct cmd_context *ctx __maybe_unused, + struct ethtool_module_eeprom *request __maybe_unused) +{ + fprintf(stderr, "Netlink not supported by ethtool.\n"); + return -EOPNOTSUPP; +} + #define nl_gset NULL #define nl_sset NULL #define nl_permaddr NULL diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c index 101d5943c2bc..ee5508840157 100644 --- a/netlink/module-eeprom.c +++ b/netlink/module-eeprom.c @@ -341,6 +341,110 @@ static void decoder_print(void) } #endif +static struct list_head eeprom_page_list = LIST_HEAD_INIT(eeprom_page_list); + +struct eeprom_page_entry { + struct list_head list; /* Member of eeprom_page_list */ + void *data; +}; + +static int eeprom_page_list_add(void *data) +{ + struct eeprom_page_entry *entry; + + entry = malloc(sizeof(*entry)); + if (!entry) + return -ENOMEM; + + entry->data = data; + list_add(&entry->list, &eeprom_page_list); + + return 0; +} + +static void eeprom_page_list_flush(void) +{ + struct eeprom_page_entry *entry; + struct list_head *head, *next; + + list_for_each_safe(head, next, &eeprom_page_list) { + entry = (struct eeprom_page_entry *) head; + free(entry->data); + list_del(head); + free(entry); + } +} + +static int get_eeprom_page_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_DATA + 1] = {}; + struct ethtool_module_eeprom *request = data; + DECLARE_ATTR_TB_INFO(tb); + u8 *eeprom_data; + int ret; + + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + + if (!tb[ETHTOOL_A_MODULE_EEPROM_DATA]) + return MNL_CB_ERROR; + + eeprom_data = mnl_attr_get_payload(tb[ETHTOOL_A_MODULE_EEPROM_DATA]); + request->data = malloc(request->length); + if (!request->data) + return MNL_CB_ERROR; + memcpy(request->data, eeprom_data, request->length); + + ret = eeprom_page_list_add(request->data); + if (ret < 0) + goto err_list_add; + + return MNL_CB_OK; + +err_list_add: + free(request->data); + return MNL_CB_ERROR; +} + +int nl_get_eeprom_page(struct cmd_context *ctx, + struct ethtool_module_eeprom *request) +{ + struct nl_context *nlctx = ctx->nlctx; + struct nl_socket *nlsock; + struct nl_msg_buff *msg; + int ret; + + if (!request || request->i2c_address > ETH_I2C_MAX_ADDRESS) + return -EINVAL; + + nlsock = nlctx->ethnl_socket; + msg = &nlsock->msgbuff; + + ret = nlsock_prep_get_request(nlsock, ETHTOOL_MSG_MODULE_EEPROM_GET, + ETHTOOL_A_MODULE_EEPROM_HEADER, 0); + if (ret < 0) + return ret; + + if (ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH, + request->length) || + ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET, + request->offset) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE, + request->page) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_BANK, + request->bank) || + ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, + request->i2c_address)) + return -EMSGSIZE; + + ret = nlsock_sendmsg(nlsock, NULL); + if (ret < 0) + return ret; + return nlsock_process_reply(nlsock, get_eeprom_page_reply_cb, + (void *)request); +} + int nl_getmodule(struct cmd_context *ctx) { struct cmd_params getmodule_cmd_params = {}; @@ -425,6 +529,7 @@ int nl_getmodule(struct cmd_context *ctx) } cleanup: + eeprom_page_list_flush(); cache_free(); return ret; } -- 2.35.1