/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2012 Vincent Bernat * * 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. */ #include #include "../lldpd-structs.h" #include "../compat/compat.h" #include "../marshal.h" #include "../ctl.h" /* connection.c */ struct lldpctl_conn_t { /* the Unix-domain socket to connect to lldpd */ char *ctlname; /* Callback handling */ lldpctl_recv_callback recv; /* Receive callback */ lldpctl_send_callback send; /* Send callback */ void *user_data; /* Callback user data */ /* IO state handling. */ uint8_t *input_buffer; /* Current input/output buffer */ uint8_t *output_buffer; /* Current input/output buffer */ size_t input_buffer_len; size_t output_buffer_len; #define CONN_STATE_IDLE 0 #define CONN_STATE_GET_INTERFACES_SEND 1 #define CONN_STATE_GET_INTERFACES_RECV 2 #define CONN_STATE_GET_PORT_SEND 3 #define CONN_STATE_GET_PORT_RECV 4 #define CONN_STATE_SET_PORT_SEND 5 #define CONN_STATE_SET_PORT_RECV 6 #define CONN_STATE_SET_WATCH_SEND 7 #define CONN_STATE_SET_WATCH_RECV 8 #define CONN_STATE_GET_CONFIG_SEND 9 #define CONN_STATE_GET_CONFIG_RECV 10 #define CONN_STATE_SET_CONFIG_SEND 11 #define CONN_STATE_SET_CONFIG_RECV 12 #define CONN_STATE_GET_CHASSIS_SEND 13 #define CONN_STATE_GET_CHASSIS_RECV 14 #define CONN_STATE_GET_DEFAULT_PORT_SEND 15 #define CONN_STATE_GET_DEFAULT_PORT_RECV 16 #define CONN_STATE_WATCHING 17 #define CONN_STATE_SET_CHASSIS_SEND 18 #define CONN_STATE_SET_CHASSIS_RECV 19 int state; /* Current state */ /* Data attached to the state. It is used to check that we are using the * same data as a previous call until the state machine goes to * CONN_STATE_IDLE. */ char state_data[IFNAMSIZ + 64]; /* Error handling */ lldpctl_error_t error; /* Last error */ /* Handling notifications */ lldpctl_change_callback watch_cb; lldpctl_change_callback2 watch_cb2; void *watch_data; int watch_triggered; }; /* User data for synchronous callbacks. */ struct lldpctl_conn_sync_t { int fd; /* File descriptor to the socket. */ }; ssize_t _lldpctl_needs(lldpctl_conn_t *lldpctl, size_t length); int _lldpctl_do_something(lldpctl_conn_t *conn, int state_send, int state_recv, const char *state_data, enum hmsg_type type, void *to_send, struct marshal_info *mi_send, void **to_recv, struct marshal_info *mi_recv); /* errors.c */ #define SET_ERROR(conn, x) ((conn)->error = x) #define RESET_ERROR(conn) SET_ERROR((conn), LLDPCTL_NO_ERROR) /* atom.c and atom-private.c */ typedef enum { atom_config, atom_interfaces_list, atom_interface, atom_ports_list, atom_port, atom_mgmts_list, atom_mgmt, #ifdef ENABLE_DOT3 atom_dot3_power, #endif #ifdef ENABLE_DOT1 atom_vlans_list, atom_vlan, atom_ppvids_list, atom_ppvid, atom_pis_list, atom_pi, #endif #ifdef ENABLE_LLDPMED atom_med_policies_list, atom_med_policy, atom_med_locations_list, atom_med_location, atom_med_caelements_list, atom_med_caelement, atom_med_power, #endif #ifdef ENABLE_CUSTOM atom_custom_list, atom_custom, #endif atom_chassis, } atom_t; void *_lldpctl_alloc_in_atom(lldpctl_atom_t *, size_t); const char *_lldpctl_dump_in_atom(lldpctl_atom_t *, const uint8_t *, size_t, char, size_t); struct atom_buffer { TAILQ_ENTRY(atom_buffer) next; u_int8_t data[0]; }; struct lldpctl_atom_t { int count; atom_t type; lldpctl_conn_t *conn; TAILQ_HEAD(, atom_buffer) buffers; /* List of buffers */ /* Destructor */ void (*free)(lldpctl_atom_t *); /* Iterators */ lldpctl_atom_iter_t *(*iter)(lldpctl_atom_t *); lldpctl_atom_iter_t *(*next)(lldpctl_atom_t *, lldpctl_atom_iter_t *); lldpctl_atom_t *(*value)(lldpctl_atom_t *, lldpctl_atom_iter_t *); /* Getters */ lldpctl_atom_t *(*get)(lldpctl_atom_t *, lldpctl_key_t); const char *(*get_str)(lldpctl_atom_t *, lldpctl_key_t); const u_int8_t *(*get_buffer)(lldpctl_atom_t *, lldpctl_key_t, size_t *); long int (*get_int)(lldpctl_atom_t *, lldpctl_key_t); /* Setters */ lldpctl_atom_t *(*set)(lldpctl_atom_t *, lldpctl_key_t, lldpctl_atom_t *); lldpctl_atom_t *(*set_str)(lldpctl_atom_t *, lldpctl_key_t, const char *); lldpctl_atom_t *( *set_buffer)(lldpctl_atom_t *, lldpctl_key_t, const u_int8_t *, size_t); lldpctl_atom_t *(*set_int)(lldpctl_atom_t *, lldpctl_key_t, long int); lldpctl_atom_t *(*create)(lldpctl_atom_t *); }; struct _lldpctl_atom_config_t { lldpctl_atom_t base; struct lldpd_config *config; }; struct _lldpctl_atom_interfaces_list_t { lldpctl_atom_t base; struct lldpd_interface_list *ifs; }; struct _lldpctl_atom_interface_t { lldpctl_atom_t base; char *name; }; struct _lldpctl_atom_chassis_t { lldpctl_atom_t base; struct lldpd_chassis *chassis; struct _lldpctl_atom_port_t *parent; /* Optional: parent of this atom (owning our reference) */ int embedded; /* This atom is "embedded" (not refcounted) */ }; struct _lldpctl_atom_port_t { lldpctl_atom_t base; int local; /* Local or remote port? */ struct lldpd_hardware *hardware; /* Local port only (but optional) */ struct lldpd_port *port; /* Local and remote */ struct _lldpctl_atom_port_t *parent; /* Local port if we are a remote port */ lldpctl_atom_t *chassis; /* Internal atom for chassis */ }; /* Can represent any simple list holding just a reference to a port. */ struct _lldpctl_atom_any_list_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; }; struct _lldpctl_atom_mgmts_list_t { lldpctl_atom_t base; lldpctl_atom_t *parent; struct lldpd_chassis *chassis; /* Chassis containing the list of IP addresses */ }; struct _lldpctl_atom_mgmt_t { lldpctl_atom_t base; lldpctl_atom_t *parent; struct lldpd_mgmt *mgmt; }; #ifdef ENABLE_DOT3 struct _lldpctl_atom_dot3_power_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; }; #endif #ifdef ENABLE_DOT1 struct _lldpctl_atom_vlan_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_vlan *vlan; }; struct _lldpctl_atom_ppvid_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_ppvid *ppvid; }; struct _lldpctl_atom_pi_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_pi *pi; }; #endif #ifdef ENABLE_LLDPMED struct _lldpctl_atom_med_policy_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_med_policy *policy; }; struct _lldpctl_atom_med_location_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_med_loc *location; }; /* This list should have the same structure than _llpdctl_atom_any_list_t */ struct _lldpctl_atom_med_caelements_list_t { lldpctl_atom_t base; struct _lldpctl_atom_med_location_t *parent; }; struct _lldpctl_atom_med_caelement_t { lldpctl_atom_t base; struct _lldpctl_atom_med_location_t *parent; int type; uint8_t *value; size_t len; }; struct _lldpctl_atom_med_power_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; }; #endif #ifdef ENABLE_CUSTOM struct _lldpctl_atom_custom_list_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; struct lldpd_custom_list *list; }; struct _lldpctl_atom_custom_t { lldpctl_atom_t base; struct _lldpctl_atom_port_t *parent; int op; struct lldpd_custom *tlv; }; #endif struct lldpctl_atom_t *_lldpctl_new_atom(lldpctl_conn_t *conn, atom_t type, ...); struct atom_map { int key; struct atom_map *next; lldpctl_map_t map[]; }; void atom_map_register(struct atom_map *map, int); void init_atom_map(void); #define ATOM_MAP_REGISTER(NAME, PRIO) \ void init_atom_map_##NAME(void); \ void init_atom_map_##NAME(void) \ { \ atom_map_register(&NAME, PRIO); \ } struct atom_builder { atom_t type; /* Atom type */ size_t size; /* Size of structure to allocate */ int (*init)(lldpctl_atom_t *, va_list); /* Optional additional init steps */ void (*free)(lldpctl_atom_t *); /* Optional deallocation steps */ lldpctl_atom_iter_t *(*iter)( lldpctl_atom_t *); /* Optional, return an iterator for this object */ lldpctl_atom_iter_t *(*next)(lldpctl_atom_t *, lldpctl_atom_iter_t *); /* Return the next object for the provided iterator */ lldpctl_atom_t *(*value)(lldpctl_atom_t *, lldpctl_atom_iter_t *); /* Return the current object for the provided iterator */ lldpctl_atom_t *(*get)(lldpctl_atom_t *, lldpctl_key_t); const char *(*get_str)(lldpctl_atom_t *, lldpctl_key_t); const u_int8_t *(*get_buffer)(lldpctl_atom_t *, lldpctl_key_t, size_t *); long int (*get_int)(lldpctl_atom_t *, lldpctl_key_t); lldpctl_atom_t *(*set)(lldpctl_atom_t *, lldpctl_key_t, lldpctl_atom_t *); lldpctl_atom_t *(*set_str)(lldpctl_atom_t *, lldpctl_key_t, const char *); lldpctl_atom_t *( *set_buffer)(lldpctl_atom_t *, lldpctl_key_t, const u_int8_t *, size_t); lldpctl_atom_t *(*set_int)(lldpctl_atom_t *, lldpctl_key_t, long int); lldpctl_atom_t *(*create)(lldpctl_atom_t *); struct atom_builder *nextb; }; void atom_builder_register(struct atom_builder *builder, int); void init_atom_builder(void); #define ATOM_BUILDER_REGISTER(NAME, PRIO) \ void init_atom_builder_##NAME(void); \ void init_atom_builder_##NAME(void) \ { \ atom_builder_register(&NAME, PRIO); \ }