eth: fbnic: Update fbnic_tlv_attr_get_string() to work like nla_strscpy()
authorLee Trager <lee@trager.us>
Fri, 28 Feb 2025 19:15:27 +0000 (11:15 -0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 5 Mar 2025 01:03:26 +0000 (17:03 -0800)
Allow fbnic_tlv_attr_get_string() to return an error code. In the event the
source mailbox attribute is missing return -EINVAL. Like nla_strscpy() return
-E2BIG when the source string is larger than the destination string. In this
case the amount of data copied is equal to dstsize.

Signed-off-by: Lee Trager <lee@trager.us>
Link: https://patch.msgid.link/20250228191935.3953712-3-lee@trager.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/meta/fbnic/fbnic_tlv.c
drivers/net/ethernet/meta/fbnic/fbnic_tlv.h

index 2a174ab..400fb6c 100644 (file)
@@ -233,19 +233,40 @@ s64 fbnic_tlv_attr_get_signed(struct fbnic_tlv_msg *attr)
 /**
  * fbnic_tlv_attr_get_string - Retrieve string value from result
  * @attr: Attribute to retrieve data from
- * @str: Pointer to an allocated string to store the data
- * @max_size: The maximum size which can be in str
+ * @dst: Pointer to an allocated string to store the data
+ * @dstsize: The maximum size which can be in dst
  *
- * Return: the size of the string read from firmware
+ * Return: the size of the string read from firmware or negative error.
  **/
-size_t fbnic_tlv_attr_get_string(struct fbnic_tlv_msg *attr, char *str,
-                                size_t max_size)
+ssize_t fbnic_tlv_attr_get_string(struct fbnic_tlv_msg *attr, char *dst,
+                                 size_t dstsize)
 {
-       max_size = min_t(size_t, max_size,
-                        (le16_to_cpu(attr->hdr.len) * 4) - sizeof(*attr));
-       memcpy(str, &attr->value, max_size);
+       size_t srclen, len;
+       ssize_t ret;
 
-       return max_size;
+       if (!attr)
+               return -EINVAL;
+
+       if (dstsize == 0)
+               return -E2BIG;
+
+       srclen = le16_to_cpu(attr->hdr.len) - sizeof(*attr);
+       if (srclen > 0 && attr->value[srclen - 1] == '\0')
+               srclen--;
+
+       if (srclen >= dstsize) {
+               len = dstsize - 1;
+               ret = -E2BIG;
+       } else {
+               len = srclen;
+               ret = len;
+       }
+
+       memcpy(dst, &attr->value, len);
+       /* Zero pad end of dst. */
+       memset(dst + len, 0, dstsize - len);
+
+       return ret;
 }
 
 /**
index 67300ab..b29ed26 100644 (file)
@@ -116,8 +116,8 @@ static inline bool fbnic_tlv_attr_get_bool(struct fbnic_tlv_msg *attr)
 
 u64 fbnic_tlv_attr_get_unsigned(struct fbnic_tlv_msg *attr);
 s64 fbnic_tlv_attr_get_signed(struct fbnic_tlv_msg *attr);
-size_t fbnic_tlv_attr_get_string(struct fbnic_tlv_msg *attr, char *str,
-                                size_t max_size);
+ssize_t fbnic_tlv_attr_get_string(struct fbnic_tlv_msg *attr, char *dst,
+                                 size_t dstsize);
 
 #define get_unsigned_result(id, location) \
 do { \