The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
/*
 * $Id: cdp.h,v 1.3 2005/07/20 13:44:13 mchapman Exp $
 */

#ifndef _CDP_H
#define _CDP_H

#include <stddef.h>
#include <stdint.h>
#include <netinet/in.h>

#ifdef __cplusplus
extern "C" {
#endif

/******************************************************************************/

/*
 * The size of the error buffer to be passed to functions that expect one.
 */
#define CDP_ERRBUF_SIZE 256

/******************************************************************************/

/*
 * Dup and free operators for data stored in linked lists.
 */
typedef void * (*cdp_dup_fn_t)(const void *);
typedef void (*cdp_free_fn_t)(void *);

/*
 * Opaque container for a linked list node.
 */
typedef struct _cdp_llist_item {
	struct _cdp_llist_item *next;
	void *x;
} cdp_llist_item_t;

/*
 * Opaque linked list. Items on a linked list must have a "void *next"
 * member.
 */
typedef struct {
	cdp_dup_fn_t dup_fn;
	cdp_free_fn_t free_fn;
	uint32_t count;
	
	cdp_llist_item_t *head;
	cdp_llist_item_t *tail;
} cdp_llist_t;

/*
 * Linked lists are append-only. This means they only ever grow, and
 * elements will appear in the list in the order in which they were
 * added.
 *
 * The cdp_llist_dup function makes a deep copy of the specified llist
 * using the cdp_dup_fn_t that was provided when the llist was created.
 *
 * Similarly, cdp_llist_free deeply frees the llist using the cdp_free_fn_t
 * provided when the llist was created.
 */
cdp_llist_t * cdp_llist_new(cdp_dup_fn_t, cdp_free_fn_t);
cdp_llist_t * cdp_llist_dup(const cdp_llist_t *);
void cdp_llist_append(cdp_llist_t *, void *);
void cdp_llist_transfer(cdp_llist_t *, cdp_llist_t *);
void cdp_llist_free(cdp_llist_t *);

#define cdp_llist_count(LLIST) ((const uint32_t)((LLIST)->count))

/*
 * Linked list iterator.
 *
 * void frobnicate(item_t *);
 *
 * void frobnicate_all(const cdp_llist_t *llist) {
 *     cdp_llist_iter_t iter;
 * 
 *     for (iter = cdp_llist_iter(llist); iter; iter = cdp_llist_next(iter))
 *         frobnicate(cdp_llist_get(iter));
 * }
 */
typedef const cdp_llist_item_t *cdp_llist_iter_t;
#define cdp_llist_iter(LLIST) ((cdp_llist_iter_t)((LLIST)->head))
#define cdp_llist_get(ITER) ((ITER)->x)
#define cdp_llist_next(ITER) ((ITER)->next)

/******************************************************************************/

/*
 * Get a list of strings representing available ports.
 */
cdp_llist_t * cdp_get_ports(char *);

/*
 * Opaque CDP listener/advertiser object.
 */
typedef struct _cdp cdp_t;

/******************************************************************************/

/*
 * Predefined protocol_type/protocol_length/protocol combinations.
 */
#define CDP_ADDR_PROTO_CLNP      0
#define CDP_ADDR_PROTO_IPV4      1
#define CDP_ADDR_PROTO_IPV6      2
#define CDP_ADDR_PROTO_DECNET    3
#define CDP_ADDR_PROTO_APPLETALK 4
#define CDP_ADDR_PROTO_IPX       5
#define CDP_ADDR_PROTO_VINES     6
#define CDP_ADDR_PROTO_XNS       7
#define CDP_ADDR_PROTO_APOLLO    8

#define CDP_ADDR_PROTO_MAX       CDP_ADDR_PROTO_APOLLO

struct cdp_predef {
	uint8_t protocol_type;
	uint8_t protocol_length;
	void *protocol;
};

extern struct cdp_predef cdp_predefs[];

/*
 * CDP address object.
 */
struct cdp_address {
	uint8_t protocol_type;
	uint8_t protocol_length;
	void *protocol;
	uint16_t address_length;
	void *address;
};

struct cdp_address * cdp_address_new(
	uint8_t, uint8_t, const void *, uint8_t, const void *
);
struct cdp_address * cdp_address_dup(const struct cdp_address *);
void cdp_address_free(struct cdp_address *);

/******************************************************************************/

/*
 * CDP IP Prefix object.
 */
struct cdp_ip_prefix {
	struct in_addr network;
	uint8_t length;
};

struct cdp_ip_prefix * cdp_ip_prefix_new(struct in_addr, uint8_t);
struct cdp_ip_prefix * cdp_ip_prefix_dup(const struct cdp_ip_prefix *);
void cdp_ip_prefix_free(struct cdp_ip_prefix *);

/******************************************************************************/

struct cdp_appliance {
	uint8_t id;
	uint16_t vlan;
};

struct cdp_appliance * cdp_appliance_new(uint8_t, uint16_t);
struct cdp_appliance * cdp_appliance_dup(const struct cdp_appliance *);
void cdp_appliance_free(struct cdp_appliance *);

/******************************************************************************/

/*
 * CDP capabilities.
 */
#define CDP_CAP_ROUTER             0x01
#define CDP_CAP_TRANSPARENT_BRIDGE 0x02
#define CDP_CAP_SOURCE_BRIDGE      0x04
#define CDP_CAP_SWITCH             0x08
#define CDP_CAP_HOST               0x10
#define CDP_CAP_IGMP               0x20
#define CDP_CAP_REPEATER           0x40

/*
 * CDP packet.
 *
 * The packet field must always exist. It is always preallocated with
 * at least BUFSIZ bytes of space -- don't shrink it to less than this.
 *
 * packet_length indicates the number of bytes actually used in packet to
 * represent the CDP packet in encoded form. You don't need to touch this
 * since cdp_packet_update will update it as necessary.
 * 
 * You can fiddle with the fields directly. Any field which is a pointer can
 * also be NULL, indicating that the field does not "exist" in the packet,
 * ie. it wasn't received and it won't be sent.
 *
 * cdp_generate will generate a packet with most values filled out for you.
 * Pass a cdp_t * object in as the first argument to associate the packet with
 * the device used by that object.
 */
struct cdp_packet {
	void *packet;
	uint16_t packet_length;

	uint8_t version;
	uint8_t ttl;
	uint16_t checksum;
	char *device_id;
	cdp_llist_t *addresses;
	char *port_id;
	uint32_t *capabilities;
	char *ios_version;
	char *platform;
	cdp_llist_t *ip_prefixes;
	char *vtp_mgmt_domain;
	uint16_t *native_vlan;
	uint8_t *duplex;
	struct cdp_appliance *appliance;
	struct cdp_appliance *appliance_query;
	uint16_t *power_consumption;
	uint32_t *mtu;
	uint8_t *extended_trust;
	uint8_t *untrusted_cos;
	cdp_llist_t *mgmt_addresses;
};

struct cdp_packet * cdp_packet_generate(const cdp_t *);
struct cdp_packet * cdp_packet_dup(const struct cdp_packet *);
void cdp_packet_free(struct cdp_packet *);

/*
 * Update the packet, packet_length and checksum fields. You'll need to
 * call this before sending the packet, otherwise it will send the old data
 * stored in packet.
 */
int cdp_packet_update(struct cdp_packet *, char *);

/******************************************************************************/

/*
 * cdp_new flags.
 */
#define CDP_PROMISCUOUS        0x01
#define CDP_DISABLE_RECV       0x02
#define CDP_DISABLE_SEND       0x04

/*
 * cdp_recv flags.
 */
#define CDP_RECV_NONBLOCK      0x01
#define CDP_RECV_DECODE_ERRORS 0x02

cdp_t * cdp_new(const char *, int, char *);
void cdp_free(cdp_t *);

const char * cdp_get_port(const cdp_t *);
const cdp_llist_t * cdp_get_addresses(const cdp_t *);
const uint8_t * cdp_get_duplex(const cdp_t *);
int cdp_get_fd(const cdp_t *);

struct cdp_packet * cdp_recv(cdp_t *, int, char *);
int cdp_send(cdp_t *, const struct cdp_packet *, char *);

#ifdef __cplusplus
}
#endif

#endif /* _CDP_H */