summaryrefslogtreecommitdiffstats
path: root/src/lib/atoms/custom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/atoms/custom.c')
-rw-r--r--src/lib/atoms/custom.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/lib/atoms/custom.c b/src/lib/atoms/custom.c
new file mode 100644
index 0000000..ffa5b03
--- /dev/null
+++ b/src/lib/atoms/custom.c
@@ -0,0 +1,226 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ * Copyright (c) 2015 Alexandru Ardelean <ardeleanalex@gmail.com>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#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 */