Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2019 Broadcom
0004  */
0005 
0006 #include <asm/unaligned.h>
0007 
0008 #include <linux/math.h>
0009 #include <linux/string.h>
0010 #include <linux/bug.h>
0011 
0012 #include "xtlv.h"
0013 
0014 static int brcmf_xtlv_header_size(u16 opts)
0015 {
0016     int len = (int)offsetof(struct brcmf_xtlv, data);
0017 
0018     if (opts & BRCMF_XTLV_OPTION_IDU8)
0019         --len;
0020     if (opts & BRCMF_XTLV_OPTION_LENU8)
0021         --len;
0022 
0023     return len;
0024 }
0025 
0026 int brcmf_xtlv_data_size(int dlen, u16 opts)
0027 {
0028     int hsz;
0029 
0030     hsz = brcmf_xtlv_header_size(opts);
0031     if (opts & BRCMF_XTLV_OPTION_ALIGN32)
0032         return roundup(dlen + hsz, 4);
0033 
0034     return dlen + hsz;
0035 }
0036 
0037 void brcmf_xtlv_pack_header(struct brcmf_xtlv *xtlv, u16 id, u16 len,
0038                 const u8 *data, u16 opts)
0039 {
0040     u8 *data_buf;
0041     u16 mask = BRCMF_XTLV_OPTION_IDU8 | BRCMF_XTLV_OPTION_LENU8;
0042 
0043     if (!(opts & mask)) {
0044         u8 *idp = (u8 *)xtlv;
0045         u8 *lenp = idp + sizeof(xtlv->id);
0046 
0047         put_unaligned_le16(id, idp);
0048         put_unaligned_le16(len, lenp);
0049         data_buf = lenp + sizeof(u16);
0050     } else if ((opts & mask) == mask) { /* u8 id and u8 len */
0051         u8 *idp = (u8 *)xtlv;
0052         u8 *lenp = idp + 1;
0053 
0054         *idp = (u8)id;
0055         *lenp = (u8)len;
0056         data_buf = lenp + sizeof(u8);
0057     } else if (opts & BRCMF_XTLV_OPTION_IDU8) { /* u8 id, u16 len */
0058         u8 *idp = (u8 *)xtlv;
0059         u8 *lenp = idp + 1;
0060 
0061         *idp = (u8)id;
0062         put_unaligned_le16(len, lenp);
0063         data_buf = lenp + sizeof(u16);
0064     } else if (opts & BRCMF_XTLV_OPTION_LENU8) { /* u16 id, u8 len */
0065         u8 *idp = (u8 *)xtlv;
0066         u8 *lenp = idp + sizeof(u16);
0067 
0068         put_unaligned_le16(id, idp);
0069         *lenp = (u8)len;
0070         data_buf = lenp + sizeof(u8);
0071     } else {
0072         WARN(true, "Unexpected xtlv option");
0073         return;
0074     }
0075 
0076     if (opts & BRCMF_XTLV_OPTION_LENU8) {
0077         WARN_ON(len > 0x00ff);
0078         len &= 0xff;
0079     }
0080 
0081     if (data)
0082         memcpy(data_buf, data, len);
0083 }
0084