Re: [PATCH] can: etas_es58x: report the firmware version through ethtool

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri 4 nov. 2022 at 21:06, Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> wrote:
> On 04.11.2022 16:36:59, Vincent Mailhol wrote:
> > ES58x devices report below information in their usb product info
> > string:
> >
> >   * the firmware version
> >   * the bootloader version
> >   * the hardware revision
> >
> > Report the firmware version through ethtool_drvinfo::fw_version.
> > Because struct ethtool_drvinfo has no fields to report the boatloader
> > version nor the hardware revision, continue to print these in the
> > kernel log (c.f. es58x_print_product_info()).
> >
> > While doing so, bump up copyright year of each modified files.
> >
> > Signed-off-by: Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
> > ---
> >  drivers/net/can/usb/etas_es58x/es581_4.c    |   5 +-
> >  drivers/net/can/usb/etas_es58x/es58x_core.c | 140 +++++++++++++-------
> >  drivers/net/can/usb/etas_es58x/es58x_core.h |  11 +-
> >  drivers/net/can/usb/etas_es58x/es58x_fd.c   |   5 +-
> >  4 files changed, 108 insertions(+), 53 deletions(-)
> >
> > diff --git a/drivers/net/can/usb/etas_es58x/es581_4.c b/drivers/net/can/usb/etas_es58x/es581_4.c
> > index 1bcdcece5ec7..1d6ae7b279cf 100644
> > --- a/drivers/net/can/usb/etas_es58x/es581_4.c
> > +++ b/drivers/net/can/usb/etas_es58x/es581_4.c
> > @@ -6,7 +6,7 @@
> >   *
> >   * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
> >   * Copyright (c) 2020 ETAS K.K.. All rights reserved.
> > - * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
> > + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
> >   */
> >
> >  #include <linux/kernel.h>
> > @@ -492,7 +492,8 @@ const struct es58x_parameters es581_4_param = {
> >       .tx_bulk_max = ES581_4_TX_BULK_MAX,
> >       .urb_cmd_header_len = ES581_4_URB_CMD_HEADER_LEN,
> >       .rx_urb_max = ES58X_RX_URBS_MAX,
> > -     .tx_urb_max = ES58X_TX_URBS_MAX
> > +     .tx_urb_max = ES58X_TX_URBS_MAX,
> > +     .prod_info_delim = ','
>
> Nitpick: you can add a trailing "," here, makes the diff smaller on the
> next change :)

ACK.

> >  };
> >
> >  const struct es58x_operators es581_4_ops = {
> > diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
> > index 51294b717040..7c20a73169f3 100644
> > --- a/drivers/net/can/usb/etas_es58x/es58x_core.c
> > +++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
> > @@ -7,7 +7,7 @@
> >   *
> >   * Copyright (c) 2019 Robert Bosch Engineering and Business Solutions. All rights reserved.
> >   * Copyright (c) 2020 ETAS K.K.. All rights reserved.
> > - * Copyright (c) 2020, 2021 Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
> > + * Copyright (c) 2020-2022 Vincent Mailhol <mailhol.vincent@xxxxxxxxxx>
> >   */
> >
> >  #include <linux/ethtool.h>
> > @@ -1978,10 +1978,6 @@ static const struct net_device_ops es58x_netdev_ops = {
> >       .ndo_eth_ioctl = can_eth_ioctl_hwts,
> >  };
> >
> > -static const struct ethtool_ops es58x_ethtool_ops = {
> > -     .get_ts_info = can_ethtool_op_get_ts_info_hwts,
> > -};
> > -
> >  /**
> >   * es58x_set_mode() - Change network device mode.
> >   * @netdev: CAN network device.
> > @@ -2062,6 +2058,96 @@ static void es58x_init_priv(struct es58x_device *es58x_dev,
> >       can->do_set_mode = es58x_set_mode;
> >  }
> >
> > +/**
> > + * es58x_get_product_info() - Get the product information.
> > + * @es58x_dev: ES58X device.
> > + * @prod_info: Buffer where to store the product information.
> > + * @prod_info_len: Length of @prod_info.
> > + *
> > + * Do a synchronous call to get the product information.
> > + *
> > + * Return: zero on success, errno when any error occurs.
> > + */
> > +static int es58x_get_product_info(struct es58x_device *es58x_dev,
> > +                               char *prod_info, size_t prod_info_len)
> > +{
> > +     struct usb_device *udev = es58x_dev->udev;
> > +     const int es58x_prod_info_idx = 6;
> > +     int ret;
> > +
> > +     ret = usb_string(udev, es58x_prod_info_idx, prod_info, prod_info_len);
> > +     if (ret < 0) {
> > +             dev_err(es58x_dev->dev,
> > +                     "%s: Could not read the product info: %pe\n",
> > +                     __func__, ERR_PTR(ret));
> > +             return ret;
> > +     }
> > +     if (ret >= prod_info_len - 1) {
> > +             dev_warn(es58x_dev->dev,
> > +                      "%s: Buffer is too small, result might be truncated\n",
> > +                      __func__);
> > +     }
>
> You can use usb_cache_string() that puts the requested string into a
> kmalloc()ed buffer:
>
> | https://elixir.bootlin.com/linux/v6.0/source/drivers/usb/core/message.c#L1018
>
> ...and avoids having the large stack frame.

I saw that one a long time ago, before I started sending patches on
the mailing list, but couldn't use it because it is not
EXPORT_SYMBOL_GPLed. I was also too shy to send a patch to change
it...

I guess I will add the export and use it.

> > +
> > +     return 0;
> > +}
> > +
> > +/**
> > + * es58x_print_product_info() - Print the product information.
> > + * @es58x_dev: ES58X device.
> > + *
> > + * Return: zero on success, errno when any error occurs.
> > + */
> > +static int es58x_print_product_info(struct es58x_device *es58x_dev)
> > +{
> > +     char prod_info[ES58X_USB_STRING_SIZE];
>
> Stack size in the kernel is limited.

'make checkstack' tels me:
  0x00000000000008300 es58x_get_drvinfo []:        448
  0x00000000000003ae0 es58x_print_product_info []:    448

My understanding is that anything under 512 is still acceptable. c.f.
  https://www.kernel.org/doc/html/v4.12/process/submit-checklist.html

Regardless, I agree that using usb_cache_string() is better.

> > +     int ret;
> > +
> > +     ret = es58x_get_product_info(es58x_dev, prod_info, sizeof(prod_info));
> > +     if (ret == 0)
> > +             dev_info(es58x_dev->dev, "Product info: %s\n", prod_info);
> > +
> > +     return ret;
> > +}
> > +
> > +/**
> > + * es58x_get_drvinfo() - Get the driver name and firmware version.
> > + * @netdev: CAN network device.
> > + * @drvinfo: Driver information.
> > + *
> > + * Populate @drvinfo with the driver name and the firwmware version.
> > + */
> > +static void es58x_get_drvinfo(struct net_device *netdev,
> > +                           struct ethtool_drvinfo *drvinfo)
> > +{
> > +     struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
> > +     char prod_info[ES58X_USB_STRING_SIZE];
> > +     char *start, *end;
> > +
> > +     strscpy(drvinfo->driver, KBUILD_MODNAME, sizeof(drvinfo->driver));
> > +
> > +     if (es58x_get_product_info(es58x_dev, prod_info, sizeof(prod_info)) < 0)
> > +             return;
> > +
> > +     /* The firmware prefix is either "FW_V" or "FW:" */
> > +     start = strstr(prod_info, "FW");
> > +     if (!start)
> > +             return;
> > +     /* Go to first digit */
> > +     while (!isdigit(*start))
> > +             start++;
>
> Don't trust the input. Check for end of string before accessing it.

You are right. Now I feel ashamed of making this mistake.

> > +
> > +     end = strchr(start, es58x_dev->param->prod_info_delim);
> > +     if (!end || end - start >= sizeof(drvinfo->fw_version))
> > +             return;
> > +
> > +     strscpy(drvinfo->fw_version, start, end - start + 1);
>
> Are you misusing strscpy() here? The last parameter should be the size
> of the dest buffer, not the src buffer.

Indeed, the documentation clearly specifies that it should be the size
of the destination. I will use strncpy() instead. I already checked
that (end - start) is strictly smaller than the destination size above
so it will be fine.

Yours sincerely,
Vincent Mailhol



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux