/* -*- mode: c; c-file-style: "openbsd" -*- */ /* * Copyright (c) 2015 Vincent Bernat * Copyright (c) 2015 Alexandru Ardelean * * 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 #include #include #include "../lldpctl.h" #include "../../log.h" #include "../atom.h" #include "../helpers.h" #ifdef ENABLE_CUSTOM # define min(x, y) ((x > y) ? y : x) static lldpctl_atom_iter_t * _lldpctl_atom_iter_custom_list(lldpctl_atom_t *atom) { struct _lldpctl_atom_custom_list_t *custom = (struct _lldpctl_atom_custom_list_t *)atom; return (lldpctl_atom_iter_t *)TAILQ_FIRST(&custom->parent->port->p_custom_list); } static lldpctl_atom_iter_t * _lldpctl_atom_next_custom_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) { return (lldpctl_atom_iter_t *)TAILQ_NEXT((struct lldpd_custom *)iter, next); } static lldpctl_atom_t * _lldpctl_atom_value_custom_list(lldpctl_atom_t *atom, lldpctl_atom_iter_t *iter) { struct _lldpctl_atom_custom_list_t *custom = (struct _lldpctl_atom_custom_list_t *)atom; struct lldpd_custom *tlv = (struct lldpd_custom *)iter; return _lldpctl_new_atom(atom->conn, atom_custom, custom->parent, tlv); } static lldpctl_atom_t * _lldpctl_atom_create_custom_list(lldpctl_atom_t *atom) { struct _lldpctl_atom_custom_list_t *custom = (struct _lldpctl_atom_custom_list_t *)atom; struct lldpd_custom *tlv; tlv = _lldpctl_alloc_in_atom(atom, sizeof(struct lldpd_custom)); if (!tlv) return NULL; return _lldpctl_new_atom(atom->conn, atom_custom, custom->parent, tlv); } static int _lldpctl_atom_new_custom(lldpctl_atom_t *atom, va_list ap) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; custom->parent = va_arg(ap, struct _lldpctl_atom_port_t *); custom->tlv = va_arg(ap, struct lldpd_custom *); lldpctl_atom_inc_ref((lldpctl_atom_t *)custom->parent); return 1; } static void _lldpctl_atom_free_custom(lldpctl_atom_t *atom) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; lldpctl_atom_dec_ref((lldpctl_atom_t *)custom->parent); } static long int _lldpctl_atom_get_int_custom(lldpctl_atom_t *atom, lldpctl_key_t key) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; switch (key) { case lldpctl_k_custom_tlv_oui_subtype: return custom->tlv->subtype; default: return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); } } static lldpctl_atom_t * _lldpctl_atom_set_str_custom(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; if (!value || !strlen(value)) return NULL; /* Only local port can be modified */ if (!custom->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } switch (key) { case lldpctl_k_custom_tlv_op: if (!strcmp(value, "replace")) custom->op = CUSTOM_TLV_REPLACE; else if (!strcmp(value, "remove")) custom->op = CUSTOM_TLV_REMOVE; else custom->op = CUSTOM_TLV_ADD; return atom; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE); return NULL; } static lldpctl_atom_t * _lldpctl_atom_set_int_custom(lldpctl_atom_t *atom, lldpctl_key_t key, long int value) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; /* Only local port can be modified */ if (!custom->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } switch (key) { case lldpctl_k_custom_tlv_oui_subtype: if (value < 0 || value > 255) goto bad; custom->tlv->subtype = value; return atom; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } bad: SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE); return NULL; } static const uint8_t * _lldpctl_atom_get_buffer_custom(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; switch (key) { case lldpctl_k_custom_tlv_oui: *n = sizeof(custom->tlv->oui); return (const uint8_t *)&custom->tlv->oui; case lldpctl_k_custom_tlv_oui_info_string: *n = custom->tlv->oui_info_len; return (const uint8_t *)custom->tlv->oui_info; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } } static lldpctl_atom_t * _lldpctl_atom_set_buffer_custom(lldpctl_atom_t *atom, lldpctl_key_t key, const u_int8_t *buf, size_t n) { struct _lldpctl_atom_custom_t *custom = (struct _lldpctl_atom_custom_t *)atom; /* Only local port can be modified */ if (!custom->parent->local) { SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } switch (key) { case lldpctl_k_custom_tlv_oui: memcpy(&custom->tlv->oui, buf, min(n, sizeof(custom->tlv->oui))); return atom; case lldpctl_k_custom_tlv_oui_info_string: if (n == 0 || n > LLDP_TLV_ORG_OUI_INFO_MAXLEN) { SET_ERROR(atom->conn, LLDPCTL_ERR_BAD_VALUE); return NULL; } custom->tlv->oui_info_len = n; if (!(custom->tlv->oui_info = _lldpctl_alloc_in_atom(atom, n))) { custom->tlv->oui_info_len = 0; SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM); return NULL; } memcpy(custom->tlv->oui_info, buf, n); return atom; default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; } } static struct atom_builder custom_list = { atom_custom_list, sizeof(struct _lldpctl_atom_any_list_t), .init = _lldpctl_atom_new_any_list, .free = _lldpctl_atom_free_any_list, .iter = _lldpctl_atom_iter_custom_list, .next = _lldpctl_atom_next_custom_list, .value = _lldpctl_atom_value_custom_list, .create = _lldpctl_atom_create_custom_list }; static struct atom_builder custom = { atom_custom, sizeof(struct _lldpctl_atom_custom_t), .init = _lldpctl_atom_new_custom, .free = _lldpctl_atom_free_custom, .get_int = _lldpctl_atom_get_int_custom, .set_int = _lldpctl_atom_set_int_custom, .set_str = _lldpctl_atom_set_str_custom, .get_buffer = _lldpctl_atom_get_buffer_custom, .set_buffer = _lldpctl_atom_set_buffer_custom }; ATOM_BUILDER_REGISTER(custom_list, 22); ATOM_BUILDER_REGISTER(custom, 23); #endif /* ENABLE_CUSTOM */