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