/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2009 Vincent Bernat * 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 */