2 * QEMU rocker switch emulation - TLV parsing and composing
4 * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
17 #ifndef _ROCKER_TLV_H_
18 #define _ROCKER_TLV_H_
20 #define ROCKER_TLV_ALIGNTO 8U
21 #define ROCKER_TLV_ALIGN(len) \
22 (((len) + ROCKER_TLV_ALIGNTO - 1) & ~(ROCKER_TLV_ALIGNTO - 1))
23 #define ROCKER_TLV_HDRLEN ROCKER_TLV_ALIGN(sizeof(RockerTlv))
26 * <------- ROCKER_TLV_HDRLEN -------> <--- ROCKER_TLV_ALIGN(payload) --->
27 * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
28 * | Header | Pad | Payload | Pad |
29 * | (RockerTlv) | ing | | ing |
30 * +-----------------------------+- - -+- - - - - - - - - - - - - - -+- - -+
31 * <--------------------------- tlv->len -------------------------->
34 static inline RockerTlv
*rocker_tlv_next(const RockerTlv
*tlv
, int *remaining
)
36 int totlen
= ROCKER_TLV_ALIGN(le16_to_cpu(tlv
->len
));
39 return (RockerTlv
*) ((char *) tlv
+ totlen
);
42 static inline int rocker_tlv_ok(const RockerTlv
*tlv
, int remaining
)
44 return remaining
>= (int) ROCKER_TLV_HDRLEN
&&
45 le16_to_cpu(tlv
->len
) >= ROCKER_TLV_HDRLEN
&&
46 le16_to_cpu(tlv
->len
) <= remaining
;
49 #define rocker_tlv_for_each(pos, head, len, rem) \
50 for (pos = head, rem = len; \
51 rocker_tlv_ok(pos, rem); \
52 pos = rocker_tlv_next(pos, &(rem)))
54 #define rocker_tlv_for_each_nested(pos, tlv, rem) \
55 rocker_tlv_for_each(pos, rocker_tlv_data(tlv), rocker_tlv_len(tlv), rem)
57 static inline int rocker_tlv_size(int payload
)
59 return ROCKER_TLV_HDRLEN
+ payload
;
62 static inline int rocker_tlv_total_size(int payload
)
64 return ROCKER_TLV_ALIGN(rocker_tlv_size(payload
));
67 static inline int rocker_tlv_padlen(int payload
)
69 return rocker_tlv_total_size(payload
) - rocker_tlv_size(payload
);
72 static inline int rocker_tlv_type(const RockerTlv
*tlv
)
74 return le32_to_cpu(tlv
->type
);
77 static inline void *rocker_tlv_data(const RockerTlv
*tlv
)
79 return (char *) tlv
+ ROCKER_TLV_HDRLEN
;
82 static inline int rocker_tlv_len(const RockerTlv
*tlv
)
84 return le16_to_cpu(tlv
->len
) - ROCKER_TLV_HDRLEN
;
87 static inline uint8_t rocker_tlv_get_u8(const RockerTlv
*tlv
)
89 return *(uint8_t *) rocker_tlv_data(tlv
);
92 static inline uint16_t rocker_tlv_get_u16(const RockerTlv
*tlv
)
94 return *(uint16_t *) rocker_tlv_data(tlv
);
97 static inline uint32_t rocker_tlv_get_u32(const RockerTlv
*tlv
)
99 return *(uint32_t *) rocker_tlv_data(tlv
);
102 static inline uint64_t rocker_tlv_get_u64(const RockerTlv
*tlv
)
104 return *(uint64_t *) rocker_tlv_data(tlv
);
107 static inline uint16_t rocker_tlv_get_le16(const RockerTlv
*tlv
)
109 return le16_to_cpup((uint16_t *) rocker_tlv_data(tlv
));
112 static inline uint32_t rocker_tlv_get_le32(const RockerTlv
*tlv
)
114 return le32_to_cpup((uint32_t *) rocker_tlv_data(tlv
));
117 static inline uint64_t rocker_tlv_get_le64(const RockerTlv
*tlv
)
119 return le64_to_cpup((uint64_t *) rocker_tlv_data(tlv
));
122 static inline void rocker_tlv_parse(RockerTlv
**tb
, int maxtype
,
123 const char *buf
, int buf_len
)
125 const RockerTlv
*tlv
;
126 const RockerTlv
*head
= (const RockerTlv
*) buf
;
129 memset(tb
, 0, sizeof(RockerTlv
*) * (maxtype
+ 1));
131 rocker_tlv_for_each(tlv
, head
, buf_len
, rem
) {
132 uint32_t type
= rocker_tlv_type(tlv
);
134 if (type
> 0 && type
<= maxtype
) {
135 tb
[type
] = (RockerTlv
*) tlv
;
140 static inline void rocker_tlv_parse_nested(RockerTlv
**tb
, int maxtype
,
141 const RockerTlv
*tlv
)
143 rocker_tlv_parse(tb
, maxtype
, rocker_tlv_data(tlv
), rocker_tlv_len(tlv
));
146 static inline RockerTlv
*rocker_tlv_start(char *buf
, int buf_pos
)
148 return (RockerTlv
*) (buf
+ buf_pos
);
151 static inline void rocker_tlv_put_iov(char *buf
, int *buf_pos
,
152 int type
, const struct iovec
*iov
,
153 const unsigned int iovcnt
)
155 size_t len
= iov_size(iov
, iovcnt
);
156 int total_size
= rocker_tlv_total_size(len
);
159 tlv
= rocker_tlv_start(buf
, *buf_pos
);
160 *buf_pos
+= total_size
;
161 tlv
->type
= cpu_to_le32(type
);
162 tlv
->len
= cpu_to_le16(rocker_tlv_size(len
));
163 iov_to_buf(iov
, iovcnt
, 0, rocker_tlv_data(tlv
), len
);
164 memset((char *) tlv
+ le16_to_cpu(tlv
->len
), 0, rocker_tlv_padlen(len
));
167 static inline void rocker_tlv_put(char *buf
, int *buf_pos
,
168 int type
, int len
, void *data
)
175 rocker_tlv_put_iov(buf
, buf_pos
, type
, &iov
, 1);
178 static inline void rocker_tlv_put_u8(char *buf
, int *buf_pos
,
179 int type
, uint8_t value
)
181 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint8_t), &value
);
184 static inline void rocker_tlv_put_u16(char *buf
, int *buf_pos
,
185 int type
, uint16_t value
)
187 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint16_t), &value
);
190 static inline void rocker_tlv_put_u32(char *buf
, int *buf_pos
,
191 int type
, uint32_t value
)
193 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint32_t), &value
);
196 static inline void rocker_tlv_put_u64(char *buf
, int *buf_pos
,
197 int type
, uint64_t value
)
199 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint64_t), &value
);
202 static inline void rocker_tlv_put_le16(char *buf
, int *buf_pos
,
203 int type
, uint16_t value
)
205 value
= cpu_to_le16(value
);
206 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint16_t), &value
);
209 static inline void rocker_tlv_put_le32(char *buf
, int *buf_pos
,
210 int type
, uint32_t value
)
212 value
= cpu_to_le32(value
);
213 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint32_t), &value
);
216 static inline void rocker_tlv_put_le64(char *buf
, int *buf_pos
,
217 int type
, uint64_t value
)
219 value
= cpu_to_le64(value
);
220 rocker_tlv_put(buf
, buf_pos
, type
, sizeof(uint64_t), &value
);
223 static inline RockerTlv
*rocker_tlv_nest_start(char *buf
, int *buf_pos
,
226 RockerTlv
*start
= rocker_tlv_start(buf
, *buf_pos
);
228 rocker_tlv_put(buf
, buf_pos
, type
, 0, NULL
);
232 static inline void rocker_tlv_nest_end(char *buf
, int *buf_pos
,
235 start
->len
= (char *) rocker_tlv_start(buf
, *buf_pos
) - (char *) start
;
238 static inline void rocker_tlv_nest_cancel(char *buf
, int *buf_pos
,
241 *buf_pos
= (char *) start
- buf
;