0001
0002
0003
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) {
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) {
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) {
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