libibmad: updated based on merge feedback
[mirror/winof/.git] / ulp / libibmad / src / fields.c
1 /*
2  * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  *
32  */
33
34 #if HAVE_CONFIG_H
35 #  include <config.h>
36 #endif /* HAVE_CONFIG_H */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include <mad.h>
43
44 /*
45  * BITSOFFS and BE_OFFS are required due the fact that the bit offsets are inconsistently
46  * encoded in the IB spec - IB headers are encoded such that the bit offsets
47  * are in big endian convention (BE_OFFS), while the SMI/GSI queries data fields bit
48  * offsets are specified using real bit offset (?!)
49  * The following macros normalize everything to big endian offsets.
50  */
51 #define BITSOFFS(o, w)  (((o) & ~31) | ((32 - ((o) & 31) - (w)))), (w)
52 #define BE_OFFS(o, w)   (o), (w)
53 #define BE_TO_BITSOFFS(o, w)    (((o) & ~31) | ((32 - ((o) & 31) - (w))))
54
55 ib_field_t ib_mad_f [] = {\r
56         {0, 0},         /* IB_NO_FIELD - reserved as invalid */\r
57 \r
58         {0, 64, "GidPrefix", mad_dump_rhex},\r
59         {64, 64, "GidGuid", mad_dump_rhex},\r
60 \r
61         /*\r
62          * MAD: common MAD fields (IB spec 13.4.2)\r
63          * SMP: Subnet Management packets - lid routed (IB spec 14.2.1.1)\r
64          * DSMP: Subnet Management packets - direct route (IB spec 14.2.1.2)\r
65          * SA: Subnet Administration packets (IB spec 15.2.1.1)\r
66          */\r
67 \r
68         /* first MAD word (0-3 bytes) */\r
69         {BE_OFFS(0, 7), "MadMethod", mad_dump_hex}, /* TODO: add dumper */\r
70         {BE_OFFS(7, 1), "MadIsResponse", mad_dump_uint}, /* TODO: add dumper */\r
71         {BE_OFFS(8, 8), "MadClassVersion", mad_dump_uint},\r
72         {BE_OFFS(16, 8), "MadMgmtClass", mad_dump_uint},  /* TODO: add dumper */\r
73         {BE_OFFS(24, 8), "MadBaseVersion", mad_dump_uint},\r
74 \r
75         /* second MAD word (4-7 bytes) */\r
76         {BE_OFFS(48, 16), "MadStatus", mad_dump_hex}, /* TODO: add dumper */\r
77 \r
78         /* DR SMP only */\r
79         {BE_OFFS(32, 8), "DrSmpHopCnt", mad_dump_uint},\r
80         {BE_OFFS(40, 8), "DrSmpHopPtr", mad_dump_uint},\r
81         {BE_OFFS(48, 15), "DrSmpStatus", mad_dump_hex}, /* TODO: add dumper */\r
82         {BE_OFFS(63, 1), "DrSmpDirection", mad_dump_uint}, /* TODO: add dumper */\r
83 \r
84         /* words 3,4,5,6 (8-23 bytes) */\r
85         {64, 64, "MadTRID", mad_dump_hex},\r
86         {BE_OFFS(144, 16), "MadAttr", mad_dump_hex}, /* TODO: add dumper */\r
87         {160, 32, "MadModifier", mad_dump_hex}, /* TODO: add dumper */\r
88 \r
89         /* word 7,8 (24-31 bytes) */\r
90         {196, 64, "MadMkey", mad_dump_hex},\r
91 \r
92         /* word 9 (32-37 bytes) */\r
93         {BE_OFFS(256, 16), "DrSmpDLID", mad_dump_hex},\r
94         {BE_OFFS(272, 16), "DrSmpSLID", mad_dump_hex},\r
95 \r
96         /* word 10,11 (36-43 bytes) */\r
97         {0, 0},         /* IB_SA_MKEY_F - reserved as invalid */\r
98 \r
99         /* word 12 (44-47 bytes) */\r
100         {BE_OFFS(46*8, 16), "SaAttrOffs", mad_dump_uint},\r
101 \r
102         /* word 13,14 (48-55 bytes) */\r
103         {48*8, 64, "SaCompMask", mad_dump_hex},\r
104 \r
105         /* word 13,14 (56-255 bytes) */\r
106         {56*8, (256-56)*8, "SaData", mad_dump_hex},\r
107 \r
108         /* bytes 64 - 127 */\r
109         {0, 0},         /* IB_SM_DATA_F - reserved as invalid */\r
110         \r
111         /* bytes 64 - 256 */\r
112         {64*8, (256-64) * 8, "GsData", mad_dump_hex},\r
113         \r
114         /* bytes 128 - 191 */\r
115         {1024, 512, "DrSmpPath", mad_dump_hex},\r
116         \r
117         /* bytes 192 - 255 */\r
118         {1536, 512, "DrSmpRetPath", mad_dump_hex},\r
119         \r
120         /*\r
121          * PortInfo fields:\r
122          */\r
123         {0, 64, "Mkey", mad_dump_hex},\r
124         {64, 64, "GidPrefix", mad_dump_hex},\r
125         {BITSOFFS(128, 16), "Lid", mad_dump_hex},\r
126         {BITSOFFS(144, 16), "SMLid", mad_dump_hex},\r
127         {160, 32, "CapMask", mad_dump_portcapmask},\r
128         {BITSOFFS(192, 16), "DiagCode", mad_dump_hex},\r
129         {BITSOFFS(208, 16), "MkeyLeasePeriod", mad_dump_uint},\r
130         {BITSOFFS(224, 8), "LocalPort", mad_dump_uint},\r
131         {BITSOFFS(232, 8), "LinkWidthEnabled", mad_dump_linkwidthen},\r
132         {BITSOFFS(240, 8), "LinkWidthSupported", mad_dump_linkwidthsup},\r
133         {BITSOFFS(248, 8), "LinkWidthActive", mad_dump_linkwidth},\r
134         {BITSOFFS(256, 4), "LinkSpeedSupported", mad_dump_linkspeedsup},\r
135         {BITSOFFS(260, 4), "LinkState", mad_dump_portstate},\r
136         {BITSOFFS(264, 4), "PhysLinkState", mad_dump_physportstate},\r
137         {BITSOFFS(268, 4), "LinkDownDefState", mad_dump_linkdowndefstate},\r
138         {BITSOFFS(272, 2), "ProtectBits", mad_dump_uint},\r
139         {BITSOFFS(277, 3), "LMC", mad_dump_uint},\r
140         {BITSOFFS(280, 4), "LinkSpeedActive", mad_dump_linkspeed},\r
141         {BITSOFFS(284, 4), "LinkSpeedEnabled", mad_dump_linkspeeden},\r
142         {BITSOFFS(288, 4), "NeighborMTU", mad_dump_mtu},\r
143         {BITSOFFS(292, 4), "SMSL", mad_dump_uint},\r
144         {BITSOFFS(296, 4), "VLCap", mad_dump_vlcap},\r
145         {BITSOFFS(300, 4), "InitType", mad_dump_hex},\r
146         {BITSOFFS(304, 8), "VLHighLimit", mad_dump_uint},\r
147         {BITSOFFS(312, 8), "VLArbHighCap", mad_dump_uint},\r
148         {BITSOFFS(320, 8), "VLArbLowCap", mad_dump_uint},\r
149         {BITSOFFS(328, 4), "InitReply", mad_dump_hex},\r
150         {BITSOFFS(332, 4), "MtuCap", mad_dump_mtu},\r
151         {BITSOFFS(336, 3), "VLStallCount", mad_dump_uint},\r
152         {BITSOFFS(339, 5), "HoqLife", mad_dump_uint},\r
153         {BITSOFFS(344, 4), "OperVLs", mad_dump_opervls},\r
154         {BITSOFFS(348, 1), "PartEnforceInb", mad_dump_uint},\r
155         {BITSOFFS(349, 1), "PartEnforceOutb", mad_dump_uint},\r
156         {BITSOFFS(350, 1), "FilterRawInb", mad_dump_uint},\r
157         {BITSOFFS(351, 1), "FilterRawOutb", mad_dump_uint},\r
158         {BITSOFFS(352, 16), "MkeyViolations", mad_dump_uint},\r
159         {BITSOFFS(368, 16), "PkeyViolations", mad_dump_uint},\r
160         {BITSOFFS(384, 16), "QkeyViolations", mad_dump_uint},\r
161         {BITSOFFS(400, 8), "GuidCap", mad_dump_uint},\r
162         {BITSOFFS(408, 1), "ClientReregister", mad_dump_uint},\r
163         {BITSOFFS(411, 5), "SubnetTimeout", mad_dump_uint},\r
164         {BITSOFFS(419, 5), "RespTimeVal", mad_dump_uint},\r
165         {BITSOFFS(424, 4), "LocalPhysErr", mad_dump_uint},\r
166         {BITSOFFS(428, 4), "OverrunErr", mad_dump_uint},\r
167         {BITSOFFS(432, 16), "MaxCreditHint", mad_dump_uint},\r
168         {BITSOFFS(456, 24), "RoundTrip", mad_dump_uint},\r
169         {0, 0},         /* IB_PORT_LAST_F */\r
170 \r
171         /*\r
172          * NodeInfo fields:\r
173          */\r
174         {BITSOFFS(0,8), "BaseVers", mad_dump_uint},\r
175         {BITSOFFS(8,8), "ClassVers", mad_dump_uint},\r
176         {BITSOFFS(16,8), "NodeType", mad_dump_node_type},\r
177         {BITSOFFS(24,8), "NumPorts", mad_dump_uint},\r
178         {32, 64, "SystemGuid", mad_dump_hex},\r
179         {96, 64, "Guid", mad_dump_hex},\r
180         {160, 64, "PortGuid", mad_dump_hex},\r
181         {BITSOFFS(224,16), "PartCap", mad_dump_uint},\r
182         {BITSOFFS(240,16), "DevId", mad_dump_hex},\r
183         {256, 32, "Revision", mad_dump_hex},\r
184         {BITSOFFS(288,8), "LocalPort", mad_dump_uint},\r
185         {BITSOFFS(296,24), "VendorId", mad_dump_hex},\r
186         {0, 0},         /* IB_NODE_LAST_F */\r
187 \r
188 \r
189         /*\r
190          * SwitchInfo fields:\r
191          */\r
192         {BITSOFFS(0, 16), "LinearFdbCap", mad_dump_uint},\r
193         {BITSOFFS(16, 16), "RandomFdbCap", mad_dump_uint},\r
194         {BITSOFFS(32, 16), "McastFdbCap", mad_dump_uint},\r
195         {BITSOFFS(48, 16), "LinearFdbTop", mad_dump_uint},\r
196         {BITSOFFS(64, 8), "DefPort", mad_dump_uint},\r
197         {BITSOFFS(72, 8), "DefMcastPrimPort", mad_dump_uint},\r
198         {BITSOFFS(80, 8), "DefMcastNotPrimPort", mad_dump_uint},\r
199         {BITSOFFS(88, 5), "LifeTime", mad_dump_uint},\r
200         {BITSOFFS(93, 1), "StateChange", mad_dump_uint},\r
201         {BITSOFFS(96,16), "LidsPerPort", mad_dump_uint},\r
202         {BITSOFFS(112, 16), "PartEnforceCap", mad_dump_uint},\r
203         {BITSOFFS(128, 1), "InboundPartEnf", mad_dump_uint},\r
204         {BITSOFFS(129, 1), "OutboundPartEnf", mad_dump_uint},\r
205         {BITSOFFS(130, 1), "FilterRawInbound", mad_dump_uint},\r
206         {BITSOFFS(131, 1), "FilterRawOutbound", mad_dump_uint},\r
207         {BITSOFFS(132, 1), "EnhancedPort0", mad_dump_uint},\r
208         {0, 0},         /* IB_SW_LAST_F */\r
209 \r
210         /*\r
211          * SwitchLinearForwardingTable fields:\r
212          */\r
213         {0, 512, "LinearForwTbl", mad_dump_array},\r
214 \r
215         /*\r
216          * SwitchMulticastForwardingTable fields:\r
217          */\r
218         {0, 512, "MulticastForwTbl", mad_dump_array},\r
219 \r
220         /*\r
221          * NodeDescription fields:\r
222          */\r
223         {0, 64*8, "NodeDesc", mad_dump_string},\r
224 \r
225         /*\r
226          * Notice/Trap fields\r
227          */\r
228         {BITSOFFS(0, 1), "NoticeIsGeneric", mad_dump_uint},\r
229         {BITSOFFS(1, 7), "NoticeType", mad_dump_uint},\r
230         {BITSOFFS(8, 24), "NoticeProducerType", mad_dump_node_type},\r
231         {BITSOFFS(32, 16), "NoticeTrapNumber", mad_dump_uint},\r
232         {BITSOFFS(48, 16), "NoticeIssuerLID", mad_dump_uint},\r
233         {BITSOFFS(64, 1), "NoticeToggle", mad_dump_uint},\r
234         {BITSOFFS(65, 15), "NoticeCount", mad_dump_uint},\r
235         {80, 432, "NoticeDataDetails", mad_dump_array},\r
236         {BITSOFFS(80, 16), "NoticeDataLID", mad_dump_uint},\r
237         {BITSOFFS(96, 16), "NoticeDataTrap144LID", mad_dump_uint},\r
238         {BITSOFFS(128, 32), "NoticeDataTrap144CapMask", mad_dump_uint},\r
239 \r
240         /*\r
241          * Port counters\r
242          */\r
243         {BITSOFFS(8, 8), "PortSelect", mad_dump_uint},\r
244         {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex},\r
245         {BITSOFFS(32, 16), "SymbolErrors", mad_dump_uint},\r
246         {BITSOFFS(48, 8), "LinkRecovers", mad_dump_uint},\r
247         {BITSOFFS(56, 8), "LinkDowned", mad_dump_uint},\r
248         {BITSOFFS(64, 16), "RcvErrors", mad_dump_uint},\r
249         {BITSOFFS(80, 16), "RcvRemotePhysErrors", mad_dump_uint},\r
250         {BITSOFFS(96, 16), "RcvSwRelayErrors", mad_dump_uint},\r
251         {BITSOFFS(112, 16), "XmtDiscards", mad_dump_uint},\r
252         {BITSOFFS(128, 8), "XmtConstraintErrors", mad_dump_uint},\r
253         {BITSOFFS(136, 8), "RcvConstraintErrors", mad_dump_uint},\r
254         {BITSOFFS(152, 4), "LinkIntegrityErrors", mad_dump_uint},\r
255         {BITSOFFS(156, 4), "ExcBufOverrunErrors", mad_dump_uint},\r
256         {BITSOFFS(176, 16), "VL15Dropped", mad_dump_uint},\r
257         {192, 32, "XmtData", mad_dump_uint},\r
258         {224, 32, "RcvData", mad_dump_uint},\r
259         {256, 32, "XmtPkts", mad_dump_uint},\r
260         {288, 32, "RcvPkts", mad_dump_uint},\r
261         {0, 0},         /* IB_PC_LAST_F */\r
262 \r
263         /*\r
264          * SMInfo\r
265          */\r
266         {0, 64, "SmInfoGuid", mad_dump_hex},\r
267         {64, 64, "SmInfoKey", mad_dump_hex},\r
268         {128, 32, "SmActivity", mad_dump_uint},\r
269         {BITSOFFS(160, 4), "SmPriority", mad_dump_uint},\r
270         {BITSOFFS(164, 4), "SmState", mad_dump_uint},\r
271 \r
272         /*\r
273          * SA RMPP\r
274          */\r
275         {BE_OFFS(24*8+24, 8), "RmppVers", mad_dump_uint},\r
276         {BE_OFFS(24*8+16, 8), "RmppType", mad_dump_uint},\r
277         {BE_OFFS(24*8+11, 5), "RmppResp", mad_dump_uint},\r
278         {BE_OFFS(24*8+8, 3), "RmppFlags", mad_dump_hex},\r
279         {BE_OFFS(24*8+0, 8), "RmppStatus", mad_dump_hex},\r
280 \r
281         /* data1 */\r
282         {28*8, 32, "RmppData1", mad_dump_hex},\r
283         {28*8, 32, "RmppSegNum", mad_dump_uint},\r
284         /* data2 */\r
285         {32*8, 32, "RmppData2", mad_dump_hex},\r
286         {32*8, 32, "RmppPayload", mad_dump_uint},\r
287         {32*8, 32, "RmppNewWin", mad_dump_uint},\r
288         \r
289         /*\r
290          * SA Get Multi Path\r
291          */\r
292         {BITSOFFS(41,7), "MultiPathNumPath", mad_dump_uint},\r
293         {BITSOFFS(120,8), "MultiPathNumSrc", mad_dump_uint},\r
294         {BITSOFFS(128,8), "MultiPathNumDest", mad_dump_uint},\r
295         {192, 128, "MultiPathGid", mad_dump_array},\r
296 \r
297         /*\r
298          * SA Path rec\r
299          */\r
300         {64, 128, "PathRecDGid", mad_dump_array},\r
301         {192, 128, "PathRecSGid", mad_dump_array},\r
302         {BITSOFFS(320,16), "PathRecDLid", mad_dump_hex},\r
303         {BITSOFFS(336,16), "PathRecSLid", mad_dump_hex},\r
304         {BITSOFFS(393,7), "PathRecNumPath", mad_dump_uint},\r
305 \r
306         /*\r
307          * MC Member rec\r
308          */\r
309         {0, 128, "McastMemMGid", mad_dump_array},\r
310         {128, 128, "McastMemPortGid", mad_dump_array},\r
311         {256, 32, "McastMemQkey", mad_dump_hex},\r
312         {BITSOFFS(288, 16), "McastMemMLid", mad_dump_hex},\r
313         {BITSOFFS(352, 4), "McastMemSL", mad_dump_uint},\r
314         {BITSOFFS(306, 6), "McastMemMTU", mad_dump_uint},\r
315         {BITSOFFS(338, 6), "McastMemRate", mad_dump_uint},\r
316         {BITSOFFS(312, 8), "McastMemTClass", mad_dump_uint},\r
317         {BITSOFFS(320, 16), "McastMemPkey", mad_dump_uint},\r
318         {BITSOFFS(356, 20), "McastMemFlowLbl", mad_dump_uint},\r
319         {BITSOFFS(388, 4), "McastMemJoinState", mad_dump_uint},\r
320         {BITSOFFS(392, 1), "McastMemProxyJoin", mad_dump_uint},\r
321 \r
322         /*\r
323          * Service record\r
324          */\r
325         {0, 64, "ServRecID", mad_dump_hex},\r
326         {64, 128, "ServRecGid", mad_dump_array},\r
327         {BITSOFFS(192, 16), "ServRecPkey", mad_dump_hex},\r
328         {224, 32, "ServRecLease", mad_dump_hex},\r
329         {256, 128, "ServRecKey", mad_dump_hex},\r
330         {384, 512, "ServRecName", mad_dump_string},\r
331         {896, 512, "ServRecData", mad_dump_array},      /* ATS for example */\r
332 \r
333         /*\r
334          * ATS SM record - within SA_SR_DATA\r
335          */\r
336         {12*8, 32, "ATSNodeAddr", mad_dump_hex},\r
337         {BITSOFFS(16*8, 16), "ATSMagicKey", mad_dump_hex},\r
338         {BITSOFFS(18*8, 16), "ATSNodeType", mad_dump_hex},\r
339         {32*8, 32*8, "ATSNodeName", mad_dump_string},\r
340 \r
341         /*\r
342          * SLTOVL MAPPING TABLE\r
343          */\r
344         {0, 64, "SLToVLMap", mad_dump_hex},\r
345 \r
346         /*\r
347          * VL ARBITRATION TABLE\r
348          */\r
349         {0, 512, "VLArbTbl", mad_dump_array},\r
350 \r
351         /*\r
352          * IB vendor classes range 2\r
353          */\r
354         {BE_OFFS(36*8, 24), "OUI", mad_dump_array},\r
355         {40*8, (256-40)*8, "Vendor2Data", mad_dump_array},\r
356 \r
357         /*\r
358          * Extended port counters\r
359          */\r
360         {BITSOFFS(8, 8), "PortSelect", mad_dump_uint},\r
361         {BITSOFFS(16, 16), "CounterSelect", mad_dump_hex},\r
362         {64, 64, "PortXmitData", mad_dump_uint},\r
363         {128, 64, "PortRcvData", mad_dump_uint},\r
364         {192, 64, "PortXmitPkts", mad_dump_uint},\r
365         {256, 64, "PortRcvPkts", mad_dump_uint},\r
366         {320, 64, "PortUnicastXmitPkts", mad_dump_uint},\r
367         {384, 64, "PortUnicastRcvPkts", mad_dump_uint},\r
368         {448, 64, "PortMulticastXmitPkts", mad_dump_uint},\r
369         {512, 64, "PortMulticastRcvPkts", mad_dump_uint},\r
370         {0, 0},         /* IB_PC_EXT_LAST_F */\r
371 \r
372         /*\r
373          * GUIDInfo fields\r
374          */\r
375         {0, 64, "GUID0", mad_dump_hex},\r
376         {0, 0}          /* IB_FIELD_LAST_ */\r
377 \r
378 };
379
380 static void _set_field64(void *buf, int base_offs, const ib_field_t *f, uint64_t val)
381 {
382         uint64_t nval;
383
384         nval = htonll(val);
385         memcpy((char *)buf + base_offs + f->bitoffs / 8, &nval, sizeof(uint64_t));
386 }
387
388 static uint64_t _get_field64(void *buf, int base_offs, const ib_field_t *f)
389 {
390         uint64_t val;
391         memcpy(&val, ((char *)buf + base_offs + f->bitoffs / 8), sizeof(uint64_t));
392         return ntohll(val);
393 }
394
395 static void _set_field(void *buf, int base_offs, const ib_field_t *f, uint32_t val)
396 {
397         int prebits = (8 - (f->bitoffs & 7)) & 7;
398         int postbits = (f->bitoffs + f->bitlen) & 7;
399         int bytelen = f->bitlen / 8;
400         unsigned idx = base_offs + f->bitoffs / 8;
401         char *p = (char *)buf;
402
403         if (!bytelen && (f->bitoffs & 7) + f->bitlen < 8) {
404                 p[3^idx] &= ~((((1 << f->bitlen) - 1)) << (f->bitoffs & 7));
405                 p[3^idx] |= (val & ((1 << f->bitlen) - 1)) << (f->bitoffs & 7);
406                 return;
407         }
408
409         if (prebits) {  /* val lsb in byte msb */
410                 p[3^idx] &= (1 << (8 - prebits)) - 1;
411                 p[3^idx++] |= (val & ((1 << prebits) - 1)) << (8 - prebits);
412                 val >>= prebits;
413         }
414
415         /* BIG endian byte order */
416         for (; bytelen--; val >>= 8)
417                 p[3^idx++] = val & 0xff;
418
419         if (postbits) { /* val msb in byte lsb */
420                 p[3^idx] &= ~((1 << postbits) - 1);
421                 p[3^idx] |= val;
422         }
423 }
424
425 static uint32_t _get_field(void *buf, int base_offs, const ib_field_t *f)
426 {
427         int prebits = (8 - (f->bitoffs & 7)) & 7;
428         int postbits = (f->bitoffs + f->bitlen) & 7;
429         int bytelen = f->bitlen / 8;
430         unsigned idx = base_offs + f->bitoffs / 8;
431         uint8_t *p = (uint8_t *)buf;
432         uint32_t val = 0, v = 0, i;
433
434         if (!bytelen && (f->bitoffs & 7) + f->bitlen < 8)
435                 return (p[3^idx] >> (f->bitoffs & 7)) & ((1 << f->bitlen) - 1);
436
437         if (prebits)    /* val lsb from byte msb */
438                 v = p[3^idx++] >> (8 - prebits);
439
440         if (postbits) { /* val msb from byte lsb */
441                 i = base_offs + (f->bitoffs + f->bitlen) / 8;
442                 val = (p[3^i] & ((1 << postbits) - 1));
443         }
444
445         /* BIG endian byte order */
446         for (idx += bytelen - 1; bytelen--; idx--)
447                 val = (val << 8) | p[3^idx];
448
449         return (val << prebits) | v;
450 }
451
452 /* field must be byte aligned */
453 static void _set_array(void *buf, int base_offs, const ib_field_t *f, void *val)
454 {
455         int bitoffs = f->bitoffs;
456
457         if (f->bitlen < 32)
458                 bitoffs = BE_TO_BITSOFFS(bitoffs, f->bitlen);
459
460         memcpy((uint8_t *)buf + base_offs + bitoffs / 8, val, f->bitlen / 8);
461 }
462
463 static void _get_array(void *buf, int base_offs, const ib_field_t *f, void *val)
464 {
465         int bitoffs = f->bitoffs;
466
467         if (f->bitlen < 32)
468                 bitoffs = BE_TO_BITSOFFS(bitoffs, f->bitlen);
469
470         memcpy(val, (uint8_t *)buf + base_offs + bitoffs / 8, f->bitlen / 8);
471 }
472
473 uint32_t mad_get_field(void *buf, int base_offs, int field)
474 {
475         return _get_field(buf, base_offs, ib_mad_f + field);
476 }
477
478 void mad_set_field(void *buf, int base_offs, int field, uint32_t val)
479 {
480         _set_field(buf, base_offs, ib_mad_f + field, val);
481 }
482
483 uint64_t mad_get_field64(void *buf, int base_offs, int field)
484 {
485         return _get_field64(buf, base_offs, ib_mad_f + field);
486 }
487
488 void mad_set_field64(void *buf, int base_offs, int field, uint64_t val)
489 {
490         _set_field64(buf, base_offs, ib_mad_f + field, val);
491 }
492
493 void mad_set_array(void *buf, int base_offs, int field, void *val)
494 {
495         _set_array(buf, base_offs, ib_mad_f + field, val);
496 }
497
498 void mad_get_array(void *buf, int base_offs, int field, void *val)
499 {
500         _get_array(buf, base_offs, ib_mad_f + field, val);
501 }
502
503 void mad_decode_field(uint8_t *buf, int field, void *val)
504 {
505         const ib_field_t *f = ib_mad_f + field;
506
507         if (!field) {
508                 *(int *)val = *(int *)buf;
509                 return;
510         }
511         if (f->bitlen <= 32) {
512                 *(uint32_t *)val = _get_field(buf, 0, f);
513                 return;
514         }
515         if (f->bitlen == 64) {
516                 *(uint64_t *)val = _get_field64(buf, 0, f);
517                 return;
518         }
519         _get_array(buf, 0, f, val);
520 }
521
522 void mad_encode_field(uint8_t *buf, int field, void *val)
523 {
524         const ib_field_t *f = ib_mad_f + field;
525
526         if (!field) {
527                 *(int *)buf = *(int *)val;
528                 return;
529         }
530         if (f->bitlen <= 32) {
531                 _set_field(buf, 0, f, *(uint32_t *)val);
532                 return;
533         }
534         if (f->bitlen == 64) {
535                 _set_field64(buf, 0, f, *(uint64_t *)val);
536                 return;
537         }
538         _set_array(buf, 0, f, val);
539 }
540
541 /************************/
542
543 static char *_mad_dump_val(const ib_field_t *f, char *buf, int bufsz, void *val)
544 {
545         f->def_dump_fn(buf, bufsz, val, ALIGN(f->bitlen, 8) / 8);
546         buf[bufsz - 1] = 0;
547
548         return buf;
549 }
550
551 static char *_mad_dump_field(const ib_field_t *f, const char *name, char *buf, int bufsz, void *val)
552 {
553         char dots[128];
554         int l, n;
555
556         if (bufsz <= 32)
557                 return 0;               /* buf too small */
558
559         if (!name)
560                 name = f->name;
561
562         l = strlen(name);
563         if (l < 32) {
564                 memset(dots, '.', 32 - l);
565                 dots[32 - l] = 0;
566         }
567
568         n = snprintf(buf, bufsz, "%s:%s", name, dots);
569         _mad_dump_val(f, buf + n, bufsz - n, val);
570         buf[bufsz - 1] = 0;
571
572         return buf;
573 }
574
575 static int _mad_dump(ib_mad_dump_fn *fn, const char *name, void *val, int valsz)
576 {
577         ib_field_t f;
578         char buf[512];
579
580         f.def_dump_fn = fn;
581         f.bitlen = valsz * 8;
582
583         return printf("%s\n", _mad_dump_field(&f, name, buf, sizeof buf, val));
584 }
585
586 static int _mad_print_field(const ib_field_t *f, const char *name, void *val, int valsz)
587 {
588         return _mad_dump(f->def_dump_fn, name ? name : f->name, val, valsz ? valsz : ALIGN(f->bitlen, 8) / 8);
589 }
590
591 int mad_print_field(int field, const char *name, void *val)
592 {
593         if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_)
594                 return -1;
595         return _mad_print_field(ib_mad_f + field, name, val, 0);
596 }
597
598 char *mad_dump_field(int field, char *buf, int bufsz, void *val)
599 {
600         if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_)
601                 return 0;
602         return _mad_dump_field(ib_mad_f + field, 0, buf, bufsz, val);
603 }
604
605 char *mad_dump_val(int field, char *buf, int bufsz, void *val)
606 {
607         if (field <= IB_NO_FIELD || field >= IB_FIELD_LAST_)
608                 return 0;
609         return _mad_dump_val(ib_mad_f + field, buf, bufsz, val);
610 }