Ping?

> Le 24 août 2020 à 12:38, Thibaut VARÈNE <ha...@slashdirt.org> a écrit :
> 
> MikroTik recently changed again the way they store wlan calibration data
> on devices. Prior to this change, ERD calibration data for all available
> radios was stored within a single identifier node ("tag" in RouterBoot
> parlance).
> 
> Recent devices have been seen with calibration (and BDF) data stored in
> separate identifiers within LZOR packing for each radio: this patch
> addresses this by:
> 1) ensuring that both variants are properly supported,
> 2) preserving backward compatibility with existing data consumers,
> 3) allowing for more than 2 calibration blobs to be exposed via sysfs.
> 
> Specifically, before this patch, the driver would provide a single sysfs
> file named /sys/firmware/mikrotik/hard_config/wlan_data that contained
> whatever calibration data found on the device's flash. After this patch,
> when executed on a device that uses the old style storage, this behavior
> is unchanged, but when executed on a device that uses new style storage
> (for either traditional "ERD" packing or "LZOR" packing), the driver
> replaces that single file with a folder containing one or more files
> each containing the data encoded within individual identifiers.
> 
> As far as OpenWRT is concerned, this means that for devices which are
> known to exist with both styles of data storage, a suitable hotplug stub
> could look like this for e.g. the second radio:
> 
> wdata="/sys/firmware/mikrotik/hard_config/wlan_data"
> ( [ -f "$wdata" ] && caldata_sysfsload_from_file "$wdata" 0x8000 0x2f20 ) || \
> ( [ -d "$wdata" ] && caldata_sysfsload_from_file "$wdata/data_2" 0x0 0x2f20 )
> 
> This patch has been tested with LZOR old and new style packing on ipq4019,
> and with old style on ath79.
> 
> Tested-by: John Thomson <g...@johnthomson.fastmail.com.au>
> Tested-by: Шебанов Алексей <ad...@ublaze.ru>
> Tested-by: Alen Opačić <subixonf...@gmail.com>
> Signed-off-by: Thibaut VARÈNE <ha...@slashdirt.org>
> ---
> .../drivers/platform/mikrotik/rb_hardconfig.c | 139 +++++++++++++-----
> 1 file changed, 106 insertions(+), 33 deletions(-)
> 
> diff --git 
> a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c 
> b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c
> index 8861814be4..41dea98b5e 100644
> --- a/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c
> +++ b/target/linux/generic/files/drivers/platform/mikrotik/rb_hardconfig.c
> @@ -39,7 +39,7 @@
> 
> #include "routerboot.h"
> 
> -#define RB_HARDCONFIG_VER            "0.05"
> +#define RB_HARDCONFIG_VER            "0.06"
> #define RB_HC_PR_PFX                  "[rb_hardconfig] "
> 
> /* ID values for hardware settings */
> @@ -76,6 +76,17 @@
> #define RB_HW_OPT_HAS_TS_FOR_ADC      BIT(22)
> #define RB_HW_OPT_HAS_PLC             BIT(29)
> 
> +/*
> + * Tag ID values for ERD data.
> + * Mikrotik used to pack all calibration data under a single tag id 0x1, but
> + * recently switched to a new scheme where each radio calibration gets a
> + * separate tag. The new scheme has tag id bit 15 always set and seems to be
> + * mutually exclusive with the old scheme.
> + */
> +#define RB_WLAN_ERD_ID_SOLO          0x0001
> +#define RB_WLAN_ERD_ID_MULTI_8001    0x8001
> +#define RB_WLAN_ERD_ID_MULTI_8201    0x8201
> +
> static struct kobject *hc_kobj;
> static u8 *hc_buf;            // ro buffer after init(): no locking required
> static size_t hc_buflen;
> @@ -351,10 +362,22 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, 
> struct kobject *kobj,
>                                    loff_t off, size_t count);
> 
> static struct hc_wlan_attr {
> +     const u16 erd_tag_id;
>       struct bin_attribute battr;
>       u16 pld_ofs;
>       u16 pld_len;
> -} hc_wlandata_battr = {
> +} hc_wd_multi_battrs[] = {
> +     {
> +             .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8001,
> +             .battr = __BIN_ATTR(data_0, S_IRUSR, hc_wlan_data_bin_read, 
> NULL, 0),
> +     }, {
> +             .erd_tag_id = RB_WLAN_ERD_ID_MULTI_8201,
> +             .battr = __BIN_ATTR(data_2, S_IRUSR, hc_wlan_data_bin_read, 
> NULL, 0),
> +     }
> +};
> +
> +static struct hc_wlan_attr hc_wd_solo_battr = {
> +     .erd_tag_id = RB_WLAN_ERD_ID_SOLO,
>       .battr = __BIN_ATTR(wlan_data, S_IRUSR, hc_wlan_data_bin_read, NULL, 0),
> };
> 
> @@ -426,19 +449,19 @@ static struct hc_attr {
> /*
>  * If the RB_ID_WLAN_DATA payload starts with RB_MAGIC_ERD, then past
>  * that magic number the payload itself contains a routerboot tag node
> - * locating the LZO-compressed calibration data at id 0x1.
> + * locating the LZO-compressed calibration data. So far this scheme is only
> + * known to use a single tag at id 0x1.
>  */
> -static int hc_wlan_data_unpack_erd(const u8 *inbuf, size_t inlen,
> +static int hc_wlan_data_unpack_erd(const u16 tag_id, const u8 *inbuf, size_t 
> inlen,
>                                  void *outbuf, size_t *outlen)
> {
>       u16 lzo_ofs, lzo_len;
>       int ret;
> 
>       /* Find embedded tag */
> -     ret = routerboot_tag_find(inbuf, inlen, 0x1,    // always id 1
> -                               &lzo_ofs, &lzo_len);
> +     ret = routerboot_tag_find(inbuf, inlen, tag_id, &lzo_ofs, &lzo_len);
>       if (ret) {
> -             pr_debug(RB_HC_PR_PFX "ERD data not found\n");
> +             pr_debug(RB_HC_PR_PFX "no ERD data for id 0x%04x\n", tag_id);
>               goto fail;
>       }
> 
> @@ -461,10 +484,10 @@ fail:
>  * that magic number is a payload that must be appended to the hc_lzor_prefix,
>  * the resulting blob is LZO-compressed. In the LZO decompression result,
>  * the RB_MAGIC_ERD magic number (aligned) must be located. Following that
> - * magic, there is a routerboot tag node (id 0x1) locating the RLE-encoded
> + * magic, there is one or more routerboot tag node(s) locating the 
> RLE-encoded
>  * calibration data payload.
>  */
> -static int hc_wlan_data_unpack_lzor(const u8 *inbuf, size_t inlen,
> +static int hc_wlan_data_unpack_lzor(const u16 tag_id, const u8 *inbuf, 
> size_t inlen,
>                                   void *outbuf, size_t *outlen)
> {
>       u16 rle_ofs, rle_len;
> @@ -492,10 +515,8 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, 
> size_t inlen,
>       if (ret) {
>               if (LZO_E_INPUT_NOT_CONSUMED == ret) {
>                       /*
> -                      * The tag length appears to always be aligned (probably
> -                      * because it is the "root" RB_ID_WLAN_DATA tag), thus
> -                      * the LZO payload may be padded, which can trigger a
> -                      * spurious error which we ignore here.
> +                      * The tag length is always aligned thus the LZO 
> payload may be padded,
> +                      * which can trigger a spurious error which we ignore 
> here.
>                        */
>                       pr_debug(RB_HC_PR_PFX "LZOR: LZO EOF before buffer end 
> - this may be harmless\n");
>               } else {
> @@ -520,9 +541,9 @@ static int hc_wlan_data_unpack_lzor(const u8 *inbuf, 
> size_t inlen,
>       templen -= (u8 *)needle - tempbuf;
> 
>       /* Past magic. Look for tag node */
> -     ret = routerboot_tag_find((u8 *)needle, templen, 0x1, &rle_ofs, 
> &rle_len);
> +     ret = routerboot_tag_find((u8 *)needle, templen, tag_id, &rle_ofs, 
> &rle_len);
>       if (ret) {
> -             pr_debug(RB_HC_PR_PFX "LZOR: RLE data not found\n");
> +             pr_debug(RB_HC_PR_PFX "LZOR: no RLE data for id 0x%04x\n", 
> tag_id);
>               goto fail;
>       }
> 
> @@ -542,7 +563,7 @@ fail:
>       return ret;
> }
> 
> -static int hc_wlan_data_unpack(const size_t tofs, size_t tlen,
> +static int hc_wlan_data_unpack(const u16 tag_id, const size_t tofs, size_t 
> tlen,
>                              void *outbuf, size_t *outlen)
> {
>       const u8 *lbuf;
> @@ -562,23 +583,25 @@ static int hc_wlan_data_unpack(const size_t tofs, 
> size_t tlen,
>               /* Skip magic */
>               lbuf += sizeof(magic);
>               tlen -= sizeof(magic);
> -             ret = hc_wlan_data_unpack_lzor(lbuf, tlen, outbuf, outlen);
> +             ret = hc_wlan_data_unpack_lzor(tag_id, lbuf, tlen, outbuf, 
> outlen);
>               break;
>       case RB_MAGIC_ERD:
>               /* Skip magic */
>               lbuf += sizeof(magic);
>               tlen -= sizeof(magic);
> -             ret = hc_wlan_data_unpack_erd(lbuf, tlen, outbuf, outlen);
> +             ret = hc_wlan_data_unpack_erd(tag_id, lbuf, tlen, outbuf, 
> outlen);
>               break;
>       default:
>               /*
>                * If the RB_ID_WLAN_DATA payload doesn't start with a
>                * magic number, the payload itself is the raw RLE-encoded
> -              * calibration data.
> +              * calibration data. Only RB_WLAN_ERD_ID_SOLO makes sense here.
>                */
> -             ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen);
> -             if (ret)
> -                     pr_debug(RB_HC_PR_PFX "RLE decoding error (%d)\n", ret);
> +             if (RB_WLAN_ERD_ID_SOLO == tag_id) {
> +                     ret = routerboot_rle_decode(lbuf, tlen, outbuf, outlen);
> +                     if (ret)
> +                             pr_debug(RB_HC_PR_PFX "RLE decoding error 
> (%d)\n", ret);
> +             }
>               break;
>       }
> 
> @@ -633,7 +656,7 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, 
> struct kobject *kobj,
>       if (!outbuf)
>               return -ENOMEM;
> 
> -     ret = hc_wlan_data_unpack(hc_wattr->pld_ofs, hc_wattr->pld_len, outbuf, 
> &outlen);
> +     ret = hc_wlan_data_unpack(hc_wattr->erd_tag_id, hc_wattr->pld_ofs, 
> hc_wattr->pld_len, outbuf, &outlen);
>       if (ret) {
>               kfree(outbuf);
>               return ret;
> @@ -655,14 +678,17 @@ static ssize_t hc_wlan_data_bin_read(struct file *filp, 
> struct kobject *kobj,
> 
> int __init rb_hardconfig_init(struct kobject *rb_kobj)
> {
> +     struct kobject *hc_wlan_kobj;
>       struct mtd_info *mtd;
> -     size_t bytes_read, buflen;
> +     size_t bytes_read, buflen, outlen;
>       const u8 *buf;
> -     int i, ret;
> +     void *outbuf;
> +     int i, j, ret;
>       u32 magic;
> 
>       hc_buf = NULL;
>       hc_kobj = NULL;
> +     hc_wlan_kobj = NULL;
> 
>       // TODO allow override
>       mtd = get_mtd_device_nm(RB_MTD_HARD_CONFIG);
> @@ -713,15 +739,62 @@ int __init rb_hardconfig_init(struct kobject *rb_kobj)
>               /* Account for skipped magic */
>               hc_attrs[i].pld_ofs += sizeof(magic);
> 
> -             /* Special case RB_ID_WLAN_DATA to prep and create the binary 
> attribute */
> +             /*
> +              * Special case RB_ID_WLAN_DATA to prep and create the binary 
> attribute.
> +              * We first check if the data is "old style" within a single 
> tag (or no tag at all):
> +              * If it is we publish this single blob as a binary attribute 
> child of hc_kobj to
> +              * preserve backward compatibility.
> +              * If it isn't and instead uses multiple ERD tags, we create a 
> subfolder and
> +              * publish the known ones there.
> +              */
>               if ((RB_ID_WLAN_DATA == hc_attrs[i].tag_id) && 
> hc_attrs[i].pld_len) {
> -                     hc_wlandata_battr.pld_ofs = hc_attrs[i].pld_ofs;
> -                     hc_wlandata_battr.pld_len = hc_attrs[i].pld_len;
> -
> -                     ret = sysfs_create_bin_file(hc_kobj, 
> &hc_wlandata_battr.battr);
> -                     if (ret)
> -                             pr_warn(RB_HC_PR_PFX "Could not create %s sysfs 
> entry (%d)\n",
> -                                    hc_wlandata_battr.battr.attr.name, ret);
> +                     outlen = RB_ART_SIZE;
> +                     outbuf = kmalloc(outlen, GFP_KERNEL);
> +                     if (!outbuf) {
> +                             pr_warn(RB_HC_PR_PFX "Out of memory parsing 
> WLAN tag\n");
> +                             continue;
> +                     }
> +
> +                     /* Test ID_SOLO first, if found: done */
> +                     ret = hc_wlan_data_unpack(RB_WLAN_ERD_ID_SOLO, 
> hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen);
> +                     if (!ret) {
> +                             hc_wd_solo_battr.pld_ofs = hc_attrs[i].pld_ofs;
> +                             hc_wd_solo_battr.pld_len = hc_attrs[i].pld_len;
> +
> +                             ret = sysfs_create_bin_file(hc_kobj, 
> &hc_wd_solo_battr.battr);
> +                             if (ret)
> +                                     pr_warn(RB_HC_PR_PFX "Could not create 
> %s sysfs entry (%d)\n",
> +                                             
> hc_wd_solo_battr.battr.attr.name, ret);
> +                     }
> +                     /* Otherwise, create "wlan_data" subtree and publish 
> known data */
> +                     else {
> +                             hc_wlan_kobj = 
> kobject_create_and_add("wlan_data", hc_kobj);
> +                             if (!hc_wlan_kobj) {
> +                                     kfree(outbuf);
> +                                     pr_warn(RB_HC_PR_PFX "Could not create 
> wlan_data sysfs folder\n");
> +                                     continue;
> +                             }
> +
> +                             for (j = 0; j < ARRAY_SIZE(hc_wd_multi_battrs); 
> j++) {
> +                                     outlen = RB_ART_SIZE;
> +                                     ret = 
> hc_wlan_data_unpack(hc_wd_multi_battrs[j].erd_tag_id,
> +                                                               
> hc_attrs[i].pld_ofs, hc_attrs[i].pld_len, outbuf, &outlen);
> +                                     if (ret) {
> +                                             hc_wd_multi_battrs[j].pld_ofs = 
> hc_wd_multi_battrs[j].pld_len = 0;
> +                                             continue;
> +                                     }
> +
> +                                     hc_wd_multi_battrs[j].pld_ofs = 
> hc_attrs[i].pld_ofs;
> +                                     hc_wd_multi_battrs[j].pld_len = 
> hc_attrs[i].pld_len;
> +
> +                                     ret = 
> sysfs_create_bin_file(hc_wlan_kobj, &hc_wd_multi_battrs[j].battr);
> +                                     if (ret)
> +                                             pr_warn(RB_HC_PR_PFX "Could not 
> create wlan_data/%s sysfs entry (%d)\n",
> +                                                     
> hc_wd_multi_battrs[j].battr.attr.name, ret);
> +                             }
> +                     }
> +
> +                     kfree(outbuf);
>               }
>               /* All other tags are published via standard attributes */
>               else {
> -- 
> 2.24.3 (Apple Git-128)
> 


_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to