1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2009 Vincent Bernat <bernat@luffy.cx>
4  * Copyright (c) 2014 Michael Chapman
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifndef _FRAME_H
20 #define _FRAME_H
21 
22 static union {
23 	uint8_t f_uint8;
24 	uint16_t f_uint16;
25 	uint32_t f_uint32;
26 } types;
27 
28 /* This set of macro are used to build packets. The current position in buffer
29  * is `pos'. The length of the remaining space in buffer is `length'. `type'
30  * should be a member of `types'.
31  *
32  * This was stolen from ladvd which was adapted from Net::CDP. The original
33  * author of those macros, Michael Chapman, has relicensed those macros under
34  * the ISC license. */
35 
36 #define POKE(value, type, func)			  \
37         ((length >= sizeof(type)) &&		  \
38             (					  \
39 		type = func(value),		  \
40                 memcpy(pos, &type, sizeof(type)), \
41 		length -= sizeof(type),		  \
42 		pos += sizeof(type),		  \
43 		1				  \
44 	    ))
45 #define POKE_UINT8(value) POKE(value, types.f_uint8, )
46 #define POKE_UINT16(value) POKE(value, types.f_uint16, htons)
47 #define POKE_UINT32(value) POKE(value, types.f_uint32, htonl)
48 #define POKE_BYTES(value, bytes)			       \
49         ((length >= (bytes)) &&				       \
50             (						       \
51 		memcpy(pos, value, bytes),		       \
52 		length -= (bytes),			       \
53 		pos += (bytes),				       \
54 		1					       \
55             ))
56 #define POKE_SAVE(where)			\
57 	(where = pos, 1)
58 #define POKE_RESTORE(where)			\
59 	do {					\
60 	if ((where) > pos)			\
61 		length -= ((where) - pos);	\
62 	else					\
63 		length += (pos - (where));	\
64 	pos = (where);				\
65 	} while(0)
66 
67 /* This set of macro are used to parse packets. The same variable as for POKE_*
68  * are used. There is no check on boundaries. */
69 
70 #define PEEK(type, func)				\
71 	(						\
72 		memcpy(&type, pos, sizeof(type)),	\
73 		length -= sizeof(type),			\
74 		pos += sizeof(type),			\
75 		func(type)				\
76 	)
77 #define PEEK_UINT8 PEEK(types.f_uint8, )
78 #define PEEK_UINT16 PEEK(types.f_uint16, ntohs)
79 #define PEEK_UINT32 PEEK(types.f_uint32, ntohl)
80 #define PEEK_BYTES(value, bytes)			       \
81         do {						       \
82 		memcpy(value, pos, bytes);		       \
83 		length -= (bytes);			       \
84 		pos += (bytes);				       \
85 	} while (0)
86 #define PEEK_DISCARD(bytes)			\
87 	do {					\
88 		length -= (bytes);		\
89 		pos += (bytes);			\
90 	} while (0)
91 #define PEEK_DISCARD_UINT8 PEEK_DISCARD(1)
92 #define PEEK_DISCARD_UINT16 PEEK_DISCARD(2)
93 #define PEEK_DISCARD_UINT32 PEEK_DISCARD(4)
94 #define PEEK_CMP(value, bytes)			\
95 	(length -= (bytes),			\
96 	 pos += (bytes),			\
97 	 memcmp(pos-bytes, value, bytes))
98 #define PEEK_SAVE POKE_SAVE
99 #define PEEK_RESTORE POKE_RESTORE
100 
101 /* LLDP specific. We need a `tlv' pointer. */
102 #define POKE_START_LLDP_TLV(type)  \
103         (			   \
104 	 tlv = pos,		   \
105 	 POKE_UINT16(type << 9)	   \
106 	)
107 #define POKE_END_LLDP_TLV				       \
108         (						       \
109 	 memcpy(&types.f_uint16, tlv, sizeof(uint16_t)),	       \
110 	 types.f_uint16 |= htons((pos - (tlv + 2)) & 0x01ff),    \
111 	 memcpy(tlv, &types.f_uint16, sizeof(uint16_t)),	       \
112 	 1						       \
113 	)
114 
115 /* Same for CDP */
116 #define POKE_START_CDP_TLV(type)  \
117         (			   \
118 	 (void)POKE_UINT16(type),  \
119 	 tlv = pos,		   \
120 	 POKE_UINT16(0)		   \
121 	)
122 #define POKE_END_CDP_TLV				       \
123         (						       \
124 	 types.f_uint16 = htons(pos - tlv + 2),		       \
125 	 memcpy(tlv, &types.f_uint16, sizeof(uint16_t)),	       \
126 	 1						       \
127 	)
128 
129 /* Same for EDP */
130 #define POKE_START_EDP_TLV(type)	   \
131         (				   \
132 	 (void)POKE_UINT8(EDP_TLV_MARKER), \
133 	 (void)POKE_UINT8(type),	   \
134 	 tlv = pos,			   \
135 	 POKE_UINT16(0)			   \
136 	)
137 #define POKE_END_EDP_TLV POKE_END_CDP_TLV
138 
139 #endif /* _FRAME_H */
140