summaryrefslogtreecommitdiffstats
path: root/src/lib/atoms/config.c
blob: 8a4af2e8d1cd85e84cb3b826c127284ce954a583 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
/* -*- mode: c; c-file-style: "openbsd" -*- */
/*
 * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
 *
 * 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"

static struct atom_map bond_slave_src_mac_map = {
	.key = lldpctl_k_config_bond_slave_src_mac_type,
	.map = {
		{ LLDP_BOND_SLAVE_SRC_MAC_TYPE_REAL,   "real"},
		{ LLDP_BOND_SLAVE_SRC_MAC_TYPE_ZERO,   "zero"},
		{ LLDP_BOND_SLAVE_SRC_MAC_TYPE_FIXED,  "fixed"},
		{ LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED, "local" },
		{ LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN, NULL},
	},
};

static struct atom_map lldp_portid_map = {
	.key = lldpctl_k_config_lldp_portid_type,
	.map = {
		{ LLDP_PORTID_SUBTYPE_IFNAME,   "ifname"},
		{ LLDP_PORTID_SUBTYPE_LLADDR,   "macaddress"},
		{ LLDP_PORTID_SUBTYPE_LOCAL,    "local"},
		{ LLDP_PORTID_SUBTYPE_UNKNOWN,  NULL},
	},
};

static struct atom_map lldp_agent_map = {
	.key = lldpctl_k_config_lldp_agent_type,
	.map = {
		{ LLDP_AGENT_TYPE_NEAREST_BRIDGE,          "nearest bridge"},
		{ LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE,  "nearest non-TPMR bridge"},
		{ LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE, "nearest customer bridge"},
		{ LLDP_AGENT_TYPE_UNKNOWN, NULL},
	},
};

ATOM_MAP_REGISTER(bond_slave_src_mac_map, 1);
ATOM_MAP_REGISTER(lldp_portid_map, 2);
ATOM_MAP_REGISTER(lldp_agent_map, 3);

static int
_lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap)
{
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	c->config = va_arg(ap, struct lldpd_config *);
	return 1;
}

static void
_lldpctl_atom_free_config(lldpctl_atom_t *atom)
{
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	lldpd_config_cleanup(c->config);
	free(c->config);
}

static const char *
_lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key)
{
	char *res = NULL;
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	switch (key) {
	case lldpctl_k_config_mgmt_pattern:
		res = c->config->c_mgmt_pattern;
		break;
	case lldpctl_k_config_iface_pattern:
		res = c->config->c_iface_pattern;
		break;
	case lldpctl_k_config_perm_iface_pattern:
		res = c->config->c_perm_ifaces;
		break;
	case lldpctl_k_config_cid_pattern:
		res = c->config->c_cid_pattern;
		break;
	case lldpctl_k_config_cid_string:
		res = c->config->c_cid_string;
		break;
	case lldpctl_k_config_description:
		res = c->config->c_description;
		break;
	case lldpctl_k_config_platform:
		res = c->config->c_platform;
		break;
	case lldpctl_k_config_hostname:
		res = c->config->c_hostname;
		break;
	case lldpctl_k_config_bond_slave_src_mac_type:
		return map_lookup(bond_slave_src_mac_map.map,
		    c->config->c_bond_slave_src_mac_type);
	case lldpctl_k_config_lldp_portid_type:
		return map_lookup(lldp_portid_map.map, c->config->c_lldp_portid_type);
	case lldpctl_k_config_lldp_agent_type:
		return map_lookup(lldp_agent_map.map, c->config->c_lldp_agent_type);
	default:
		SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
		return NULL;
	}
	return res ? res : "";
}

static struct _lldpctl_atom_config_t *
__lldpctl_atom_set_str_config(struct _lldpctl_atom_config_t *c, char **local,
    char **global, const char *value)
{
	if (value) {
		char *aval = NULL;
		size_t len = strlen(value) + 1;
		aval = _lldpctl_alloc_in_atom((lldpctl_atom_t *)c, len);
		if (!aval) return NULL;
		memcpy(aval, value, len);
		*local = aval;
		free(*global);
		*global = strdup(aval);
	} else {
		free(*global);
		*local = *global = NULL;
	}
	return c;
}

static lldpctl_atom_t *
_lldpctl_atom_set_str_config(lldpctl_atom_t *atom, lldpctl_key_t key, const char *value)
{
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	struct lldpd_config config;
	memcpy(&config, c->config, sizeof(struct lldpd_config));
	char *canary = NULL;
	int rc;

	switch (key) {
	case lldpctl_k_config_perm_iface_pattern:
		if (!__lldpctl_atom_set_str_config(c, &config.c_perm_ifaces,
			&c->config->c_perm_ifaces, value))
			return NULL;
		break;
	case lldpctl_k_config_iface_pattern:
		if (!__lldpctl_atom_set_str_config(c, &config.c_iface_pattern,
			&c->config->c_iface_pattern, value))
			return NULL;
		break;
	case lldpctl_k_config_mgmt_pattern:
		if (!__lldpctl_atom_set_str_config(c, &config.c_mgmt_pattern,
			&c->config->c_mgmt_pattern, value))
			return NULL;
		break;
	case lldpctl_k_config_cid_string:
		if (!__lldpctl_atom_set_str_config(c, &config.c_cid_string,
			&c->config->c_cid_string, value))
			return NULL;
		break;
	case lldpctl_k_config_description:
		if (!__lldpctl_atom_set_str_config(c, &config.c_description,
			&c->config->c_description, value))
			return NULL;
		break;
	case lldpctl_k_config_platform:
		if (!__lldpctl_atom_set_str_config(c, &config.c_platform,
			&c->config->c_platform, value))
			return NULL;
		break;
	case lldpctl_k_config_hostname:
		if (!__lldpctl_atom_set_str_config(c, &config.c_hostname,
			&c->config->c_hostname, value))
			return NULL;
		break;
	default:
		SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
		return NULL;
	}

	if (asprintf(&canary, "%d%s", key, value ? value : "(NULL)") == -1) {
		SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
		return NULL;
	}
	rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND,
	    CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config,
	    &MARSHAL_INFO(lldpd_config), NULL, NULL);
	free(canary);
	if (rc == 0) return atom;

#undef SET_STR

	return NULL;
}

static long int
_lldpctl_atom_get_int_config(lldpctl_atom_t *atom, lldpctl_key_t key)
{
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	switch (key) {
	case lldpctl_k_config_paused:
		return c->config->c_paused;
	case lldpctl_k_config_tx_interval:
		return (c->config->c_tx_interval + 999) / 1000; /* s units */
	case lldpctl_k_config_tx_interval_ms:
		return c->config->c_tx_interval; /* ms units */
	case lldpctl_k_config_receiveonly:
		return c->config->c_receiveonly;
	case lldpctl_k_config_advertise_version:
		return c->config->c_advertise_version;
	case lldpctl_k_config_ifdescr_update:
		return c->config->c_set_ifdescr;
	case lldpctl_k_config_iface_promisc:
		return c->config->c_promisc;
	case lldpctl_k_config_chassis_cap_advertise:
		return c->config->c_cap_advertise;
	case lldpctl_k_config_chassis_cap_override:
		return c->config->c_cap_override;
	case lldpctl_k_config_chassis_mgmt_advertise:
		return c->config->c_mgmt_advertise;
#ifdef ENABLE_LLDPMED
	case lldpctl_k_config_lldpmed_noinventory:
		return c->config->c_noinventory;
	case lldpctl_k_config_fast_start_enabled:
		return c->config->c_enable_fast_start;
	case lldpctl_k_config_fast_start_interval:
		return c->config->c_tx_fast_interval;
#endif
	case lldpctl_k_config_tx_hold:
		return c->config->c_tx_hold;
	case lldpctl_k_config_max_neighbors:
		return c->config->c_max_neighbors;
	default:
		return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
	}
}

static lldpctl_atom_t *
_lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key, long int value)
{
	int rc;
	char *canary = NULL;
	struct _lldpctl_atom_config_t *c = (struct _lldpctl_atom_config_t *)atom;
	struct lldpd_config config;
	memcpy(&config, c->config, sizeof(struct lldpd_config));

	switch (key) {
	case lldpctl_k_config_paused:
		config.c_paused = c->config->c_paused = value;
		break;
	case lldpctl_k_config_tx_interval:
		config.c_tx_interval = value * 1000;
		if (value > 0) c->config->c_tx_interval = value * 1000;
		break;
	case lldpctl_k_config_tx_interval_ms:
		config.c_tx_interval = value;
		if (value > 0) c->config->c_tx_interval = value;
		break;
	case lldpctl_k_config_ifdescr_update:
		config.c_set_ifdescr = c->config->c_set_ifdescr = value;
		break;
	case lldpctl_k_config_iface_promisc:
		config.c_promisc = c->config->c_promisc = value;
		break;
	case lldpctl_k_config_chassis_cap_advertise:
		config.c_cap_advertise = c->config->c_cap_advertise = value;
		break;
	case lldpctl_k_config_chassis_cap_override:
		config.c_cap_override = c->config->c_cap_override = value;
		break;
	case lldpctl_k_config_chassis_mgmt_advertise:
		config.c_mgmt_advertise = c->config->c_mgmt_advertise = value;
		break;
#ifdef ENABLE_LLDPMED
	case lldpctl_k_config_fast_start_enabled:
		config.c_enable_fast_start = c->config->c_enable_fast_start = value;
		break;
	case lldpctl_k_config_fast_start_interval:
		config.c_tx_fast_interval = c->config->c_tx_fast_interval = value;
		break;
#endif
	case lldpctl_k_config_tx_hold:
		config.c_tx_hold = value;
		if (value > 0) c->config->c_tx_hold = value;
		break;
	case lldpctl_k_config_max_neighbors:
		config.c_max_neighbors = value;
		if (value > 0) c->config->c_max_neighbors = value;
		break;
	case lldpctl_k_config_bond_slave_src_mac_type:
		config.c_bond_slave_src_mac_type = value;
		c->config->c_bond_slave_src_mac_type = value;
		break;
	case lldpctl_k_config_lldp_portid_type:
		config.c_lldp_portid_type = value;
		c->config->c_lldp_portid_type = value;
		break;
	case lldpctl_k_config_lldp_agent_type:
		config.c_lldp_agent_type = value;
		c->config->c_lldp_agent_type = value;
		break;
	default:
		SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
		return NULL;
	}

	if (asprintf(&canary, "%d%ld", key, value) == -1) {
		SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
		return NULL;
	}
	rc = _lldpctl_do_something(atom->conn, CONN_STATE_SET_CONFIG_SEND,
	    CONN_STATE_SET_CONFIG_RECV, canary, SET_CONFIG, &config,
	    &MARSHAL_INFO(lldpd_config), NULL, NULL);
	free(canary);
	if (rc == 0) return atom;
	return NULL;
}

static struct atom_builder config = { atom_config,
	sizeof(struct _lldpctl_atom_config_t), .init = _lldpctl_atom_new_config,
	.free = _lldpctl_atom_free_config, .get_str = _lldpctl_atom_get_str_config,
	.set_str = _lldpctl_atom_set_str_config,
	.get_int = _lldpctl_atom_get_int_config,
	.set_int = _lldpctl_atom_set_int_config };

ATOM_BUILDER_REGISTER(config, 1);