1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3  * Copyright (c) 2013 Vincent Bernat <bernat@luffy.cx>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <unistd.h>
19 #include <string.h>
20 #include <sys/utsname.h>
21 
22 #include "client.h"
23 #include "../log.h"
24 
25 static int
cmd_iface_pattern(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)26 cmd_iface_pattern(struct lldpctl_conn_t *conn, struct writer *w,
27     struct cmd_env *env, void *arg)
28 {
29 	log_debug("lldpctl", "set iface pattern");
30 
31 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
32 	if (config == NULL) {
33 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
34 		    lldpctl_last_strerror(conn));
35 		return 0;
36 	}
37 
38 	const char *value = cmdenv_get(env, "iface-pattern");
39 	if (lldpctl_atom_set_str(config,
40 		lldpctl_k_config_iface_pattern,
41 		value) == NULL) {
42 		log_warnx("lldpctl", "unable to set iface-pattern. %s",
43 		    lldpctl_last_strerror(conn));
44 		lldpctl_atom_dec_ref(config);
45 		return 0;
46 	}
47 	log_info("lldpctl", "iface-pattern set to new value %s",
48 	    value?value:"(none)");
49 	lldpctl_atom_dec_ref(config);
50 	return 1;
51 }
52 
53 static int
cmd_perm_iface_pattern(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)54 cmd_perm_iface_pattern(struct lldpctl_conn_t *conn, struct writer *w,
55     struct cmd_env *env, void *arg)
56 {
57 	log_debug("lldpctl", "set permanent iface pattern");
58 
59 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
60 	if (config == NULL) {
61 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
62 		    lldpctl_last_strerror(conn));
63 		return 0;
64 	}
65 
66 	const char *value = cmdenv_get(env, "iface-pattern");
67 	if (lldpctl_atom_set_str(config,
68 		lldpctl_k_config_perm_iface_pattern,
69 		value) == NULL) {
70 		log_warnx("lldpctl", "unable to set permanent iface pattern. %s",
71 		    lldpctl_last_strerror(conn));
72 		lldpctl_atom_dec_ref(config);
73 		return 0;
74 	}
75 	log_info("lldpctl", "permanent iface pattern set to new value %s",
76 	    value?value:"(none)");
77 	lldpctl_atom_dec_ref(config);
78 	return 1;
79 }
80 
81 static int
cmd_iface_promisc(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)82 cmd_iface_promisc(struct lldpctl_conn_t *conn, struct writer *w,
83     struct cmd_env *env, void *arg)
84 {
85 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
86 	if (config == NULL) {
87 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
88 		    lldpctl_last_strerror(conn));
89 		return 0;
90 	}
91 	if (lldpctl_atom_set_int(config,
92 		lldpctl_k_config_iface_promisc,
93 		arg?1:0) == NULL) {
94 		log_warnx("lldpctl", "unable to %s promiscuous mode: %s",
95 		    arg?"enable":"disable",
96 		    lldpctl_last_strerror(conn));
97 		lldpctl_atom_dec_ref(config);
98 		return 0;
99 	}
100 	log_info("lldpctl", "interface promiscuous mode %s",
101 	    arg?"enabled":"disabled");
102 	lldpctl_atom_dec_ref(config);
103 	return 1;
104 }
105 
106 static int
cmd_system_description(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)107 cmd_system_description(struct lldpctl_conn_t *conn, struct writer *w,
108     struct cmd_env *env, void *arg)
109 {
110 	int platform = 0;
111 	const char *what = arg;
112 	const char *value;
113 	if (!strcmp(what, "system")) {
114 		value = cmdenv_get(env, "description");
115 	} else {
116 		value = cmdenv_get(env, "platform");
117 		platform = 1;
118 	}
119 	log_debug("lldpctl", "set %s description", what);
120 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
121 	if (config == NULL) {
122 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
123 		    lldpctl_last_strerror(conn));
124 		return 0;
125 	}
126 	if (lldpctl_atom_set_str(config,
127 		platform?lldpctl_k_config_platform:lldpctl_k_config_description,
128 		value) == NULL) {
129 		log_warnx("lldpctl", "unable to set description. %s",
130 		    lldpctl_last_strerror(conn));
131 		lldpctl_atom_dec_ref(config);
132 		return 0;
133 	}
134 	log_info("lldpctl", "description set to new value %s",
135 	    value?value:"(none)");
136 	lldpctl_atom_dec_ref(config);
137 	return 1;
138 }
139 
140 static int
cmd_system_chassisid(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)141 cmd_system_chassisid(struct lldpctl_conn_t *conn, struct writer *w,
142     struct cmd_env *env, void *arg)
143 {
144 	const char *value;
145 	value = cmdenv_get(env, "description");
146 	log_debug("lldpctl", "set chassis ID");
147 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
148 	if (config == NULL) {
149 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
150 		    lldpctl_last_strerror(conn));
151 		return 0;
152 	}
153 	if (lldpctl_atom_set_str(config,
154 	    lldpctl_k_config_cid_string,
155 	    value) == NULL) {
156 		log_warnx("lldpctl", "unable to set chassis ID. %s",
157 		    lldpctl_last_strerror(conn));
158 		lldpctl_atom_dec_ref(config);
159 		return 0;
160 	}
161 	log_info("lldpctl", "chassis ID set to new value %s",
162 	    value?value:"(none)");
163 	lldpctl_atom_dec_ref(config);
164 	return 1;
165 }
166 
167 static int
cmd_management(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)168 cmd_management(struct lldpctl_conn_t *conn, struct writer *w,
169     struct cmd_env *env, void *arg)
170 {
171 	log_debug("lldpctl", "set management pattern");
172 
173 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
174 	if (config == NULL) {
175 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
176 		    lldpctl_last_strerror(conn));
177 		return 0;
178 	}
179 
180 	const char *value = cmdenv_get(env, "management-pattern");
181 	if (lldpctl_atom_set_str(config,
182 		lldpctl_k_config_mgmt_pattern, value) == NULL) {
183 		log_warnx("lldpctl", "unable to set management pattern. %s",
184 		    lldpctl_last_strerror(conn));
185 		lldpctl_atom_dec_ref(config);
186 		return 0;
187 	}
188 	log_info("lldpctl", "management pattern set to new value %s",
189 	    value?value:"(none)");
190 	lldpctl_atom_dec_ref(config);
191 	return 1;
192 }
193 
194 static int
cmd_hostname(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)195 cmd_hostname(struct lldpctl_conn_t *conn, struct writer *w,
196     struct cmd_env *env, void *arg)
197 {
198 	struct utsname un;
199 	log_debug("lldpctl", "set system name");
200 
201 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
202 	if (config == NULL) {
203 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
204 		    lldpctl_last_strerror(conn));
205 		return 0;
206 	}
207 
208 	const char *value = cmdenv_get(env, "hostname");
209 	if (value && strlen(value) == 1 && value[0] == '.') {
210 		if (uname(&un) < 0) {
211 			log_warn("lldpctl", "cannot get node name");
212 			return 0;
213 		}
214 		value = un.nodename;
215 	}
216 	if (lldpctl_atom_set_str(config,
217 		lldpctl_k_config_hostname, value) == NULL) {
218 		log_warnx("lldpctl", "unable to set system name. %s",
219 		    lldpctl_last_strerror(conn));
220 		lldpctl_atom_dec_ref(config);
221 		return 0;
222 	}
223 	log_info("lldpctl", "system name set to new value %s",
224 	    value?value:"(none)");
225 	lldpctl_atom_dec_ref(config);
226 	return 1;
227 }
228 
229 static int
cmd_update_descriptions(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)230 cmd_update_descriptions(struct lldpctl_conn_t *conn, struct writer *w,
231     struct cmd_env *env, void *arg)
232 {
233 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
234 	if (config == NULL) {
235 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
236 		    lldpctl_last_strerror(conn));
237 		return 0;
238 	}
239 	if (lldpctl_atom_set_int(config,
240 		lldpctl_k_config_ifdescr_update,
241 		arg?1:0) == NULL) {
242 		log_warnx("lldpctl", "unable to %s interface description update: %s",
243 		    arg?"enable":"disable",
244 		    lldpctl_last_strerror(conn));
245 		lldpctl_atom_dec_ref(config);
246 		return 0;
247 	}
248 	log_info("lldpctl", "interface description update %s",
249 	    arg?"enabled":"disabled");
250 	lldpctl_atom_dec_ref(config);
251 	return 1;
252 }
253 
254 static int
cmd_bondslave_srcmac_type(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)255 cmd_bondslave_srcmac_type(struct lldpctl_conn_t *conn, struct writer *w,
256     struct cmd_env *env, void *arg)
257 {
258 	char *value_str;
259 	int value = -1;
260 
261 	log_debug("lldpctl", "bond slave src mac");
262 
263 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
264 	if (config == NULL) {
265 		log_warnx("lldpctl",
266 			"unable to get configuration from lldpd. %s",
267 			lldpctl_last_strerror(conn));
268 		return 0;
269 	}
270 
271 	value_str = arg;
272 	for (lldpctl_map_t *b_map =
273 		lldpctl_key_get_map(lldpctl_k_config_bond_slave_src_mac_type);
274 		b_map->string; b_map++) {
275 		if (!strcmp(b_map->string, value_str)) {
276 			value = b_map->value;
277 			break;
278 		}
279 	}
280 
281 	if (value == -1) {
282 		log_warnx("lldpctl", "invalid value");
283 		return 0;
284 	}
285 
286 	if (lldpctl_atom_set_int(config,
287 		lldpctl_k_config_bond_slave_src_mac_type, value) == NULL) {
288 		log_warnx("lldpctl", "unable to set bond slave src mac type."
289 			" %s", lldpctl_last_strerror(conn));
290 		lldpctl_atom_dec_ref(config);
291 		return 0;
292 	}
293 
294 	log_info("lldpctl", "bond slave src mac set to new value: %s",
295 	    value_str);
296 	lldpctl_atom_dec_ref(config);
297 
298 	return 1;
299 }
300 
301 static int
cmd_maxneighs(struct lldpctl_conn_t * conn,struct writer * w,struct cmd_env * env,void * arg)302 cmd_maxneighs(struct lldpctl_conn_t *conn, struct writer *w,
303     struct cmd_env *env, void *arg)
304 {
305 	log_debug("lldpctl", "set maximum neighbors");
306 
307 	lldpctl_atom_t *config = lldpctl_get_configuration(conn);
308 	if (config == NULL) {
309 		log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
310 		    lldpctl_last_strerror(conn));
311 		return 0;
312 	}
313 	if (lldpctl_atom_set_str(config,
314 		lldpctl_k_config_max_neighbors, cmdenv_get(env, "max-neighbors")) == NULL) {
315 		log_warnx("lldpctl", "unable to set maximum of neighbors. %s",
316 		    lldpctl_last_strerror(conn));
317 		lldpctl_atom_dec_ref(config);
318 		return 0;
319 	}
320 	log_info("lldpctl", "maximum neighbors set to new value %s", cmdenv_get(env, "max-neighbors"));
321 	lldpctl_atom_dec_ref(config);
322 	return 1;
323 }
324 
325 /**
326  * Register `configure system bond-slave-src-mac-type`
327  */
328 static void
register_commands_srcmac_type(struct cmd_node * configure)329 register_commands_srcmac_type(struct cmd_node *configure)
330 {
331 	struct cmd_node *bond_slave_src_mac_type =
332 		commands_new(configure,
333 			"bond-slave-src-mac-type",
334 			"Set LLDP bond slave source MAC type",
335 			NULL, NULL, NULL);
336 
337 	for (lldpctl_map_t *b_map =
338 		lldpctl_key_get_map(lldpctl_k_config_bond_slave_src_mac_type);
339 		b_map->string; b_map++) {
340 		if (!strcmp(b_map->string, "real")) {
341 			commands_new(
342 				commands_new(bond_slave_src_mac_type,
343 					b_map->string, "Real mac",
344 					NULL, NULL, NULL),
345 					NEWLINE, NULL,
346 					NULL, cmd_bondslave_srcmac_type,
347 					b_map->string);
348 		} else if (!strcmp(b_map->string, "zero")) {
349 			commands_new(
350 				commands_new(bond_slave_src_mac_type,
351 					b_map->string, "All zero mac",
352 					NULL, NULL, NULL),
353 					NEWLINE, NULL,
354 					NULL, cmd_bondslave_srcmac_type,
355 					b_map->string);
356 		} else if (!strcmp(b_map->string, "fixed")) {
357 			commands_new(
358 				commands_new(bond_slave_src_mac_type,
359 					b_map->string, "Fixed value (3Com card)",
360 					NULL, NULL, NULL),
361 					NEWLINE, NULL,
362 					NULL, cmd_bondslave_srcmac_type,
363 					b_map->string);
364 		} else if (!strcmp(b_map->string, "local")) {
365 			commands_new(
366 				commands_new(bond_slave_src_mac_type,
367 					b_map->string, "Real Mac with locally "
368 					"administered bit set",
369 					NULL, NULL, NULL),
370 					NEWLINE, NULL,
371 					NULL, cmd_bondslave_srcmac_type,
372 					b_map->string);
373 		}
374 	}
375 }
376 
377 /**
378  * Register `configure system` commands.
379  *
380  * Those are the commands to configure protocol-independant stuff.
381  */
382 void
register_commands_configure_system(struct cmd_node * configure,struct cmd_node * unconfigure)383 register_commands_configure_system(struct cmd_node *configure,
384     struct cmd_node *unconfigure)
385 {
386 	struct cmd_node *configure_system = commands_new(
387 		configure,
388 		"system", "System configuration",
389 		cmd_check_no_env, NULL, "ports");
390 	struct cmd_node *unconfigure_system = commands_new(
391 		unconfigure,
392 		"system", "System configuration",
393 		cmd_check_no_env, NULL, "ports");
394 	struct cmd_node *configure_interface = commands_new(
395 		configure_system,
396 		"interface", "Interface related items",
397 		NULL, NULL, NULL);
398 	struct cmd_node *unconfigure_interface = commands_new(
399 		unconfigure_system,
400 		"interface", "Interface related items",
401 		NULL, NULL, NULL);
402 
403 	commands_new(
404 		commands_new(
405 			commands_new(configure_system,
406 			    "description", "Override chassis description",
407 			    NULL, NULL, NULL),
408 			NULL, "Chassis description",
409 			NULL, cmd_store_env_value, "description"),
410 		NEWLINE, "Override chassis description",
411 		NULL, cmd_system_description, "system");
412 	commands_new(
413 		commands_new(unconfigure_system,
414 		    "description", "Don't override chassis description",
415 		    NULL, NULL, NULL),
416 		NEWLINE, "Don't override chassis description",
417 		NULL, cmd_system_description, "system");
418 
419 	commands_new(
420 		commands_new(
421 			commands_new(configure_system,
422 			    "chassisid", "Override chassis ID",
423 			    NULL, NULL, NULL),
424 			NULL, "Chassis ID",
425 			NULL, cmd_store_env_value, "description"),
426 		NEWLINE, "Override chassis ID",
427 		NULL, cmd_system_chassisid, "system");
428 	commands_new(
429 		commands_new(unconfigure_system,
430 		    "chassisid", "Don't override chassis ID",
431 		    NULL, NULL, NULL),
432 		NEWLINE, "Don't override chassis ID",
433 		NULL, cmd_system_chassisid, "system");
434 
435 	commands_new(
436 		commands_new(
437 			commands_new(configure_system,
438 			    "platform", "Override platform description",
439 			    NULL, NULL, NULL),
440 			NULL, "Platform description (CDP)",
441 			NULL, cmd_store_env_value, "platform"),
442 		NEWLINE, "Override platform description",
443 		NULL, cmd_system_description, "platform");
444 	commands_new(
445 		commands_new(unconfigure_system,
446 		    "platform", "Don't override platform description",
447 		    NULL, NULL, NULL),
448 		NEWLINE, "Don't override platform description",
449 		NULL, cmd_system_description, "platform");
450 
451 	commands_new(
452 		commands_new(
453 			commands_new(configure_system,
454 			    "hostname", "Override system name",
455 			    NULL, NULL, NULL),
456 			NULL, "System name",
457 			NULL, cmd_store_env_value, "hostname"),
458 		NEWLINE, "Override system name",
459 		NULL, cmd_hostname, NULL);
460 	commands_new(
461 		commands_new(unconfigure_system,
462 		    "hostname", "Don't override system name",
463 		    NULL, NULL, NULL),
464 		NEWLINE, "Don't override system name",
465 		NULL, cmd_hostname, NULL);
466 
467         commands_new(
468 		commands_new(
469 			commands_new(configure_system,
470 			    "max-neighbors", "Set maximum number of neighbors per port",
471 			    cmd_check_no_env, NULL, "ports"),
472 			NULL, "Maximum number of neighbors",
473 			NULL, cmd_store_env_value, "max-neighbors"),
474 		NEWLINE, "Set maximum number of neighbors per port",
475 		NULL, cmd_maxneighs, NULL);
476 
477 	commands_new(
478 		commands_new(
479 			commands_new(
480 				commands_new(
481 					commands_new(configure_system,
482 					    "ip", "IP related options",
483 					    NULL, NULL, NULL),
484 					"management", "IP management related options",
485 					NULL, NULL, NULL),
486 				"pattern", "Set IP management pattern",
487 				NULL, NULL, NULL),
488 			NULL, "IP management pattern (comma-separated list of wildcards)",
489 			NULL, cmd_store_env_value, "management-pattern"),
490 		NEWLINE, "Set IP management pattern",
491 		NULL, cmd_management, NULL);
492 	commands_new(
493 		commands_new(
494 			commands_new(
495 				commands_new(unconfigure_system,
496 				    "ip", "IP related options",
497 				    NULL, NULL, NULL),
498 				"management", "IP management related options",
499 				NULL, NULL, NULL),
500 			"pattern", "Delete any IP management pattern",
501 			NULL, NULL, NULL),
502 		NEWLINE, "Delete any IP management pattern",
503 		NULL, cmd_management, NULL);
504 
505         commands_new(
506 		commands_new(
507 			commands_new(configure_interface,
508 			    "pattern", "Set active interface pattern",
509 			    NULL, NULL, NULL),
510 			NULL, "Interface pattern (comma-separated list of wildcards)",
511 			NULL, cmd_store_env_value, "iface-pattern"),
512 		NEWLINE, "Set active interface pattern",
513 		NULL, cmd_iface_pattern, NULL);
514         commands_new(
515 		commands_new(unconfigure_interface,
516 		    "pattern", "Delete any interface pattern",
517 		    NULL, NULL, NULL),
518 		NEWLINE, "Clear interface pattern",
519 		NULL, cmd_iface_pattern, NULL);
520 
521         commands_new(
522 		commands_new(
523 			commands_new(configure_interface,
524 			    "permanent", "Set permanent interface pattern",
525 			    NULL, NULL, NULL),
526 			NULL, "Permanent interface pattern (comma-separated list of wildcards)",
527 			NULL, cmd_store_env_value, "iface-pattern"),
528 		NEWLINE, "Set permanent interface pattern",
529 		NULL, cmd_perm_iface_pattern, NULL);
530         commands_new(
531 		commands_new(unconfigure_interface,
532 		    "permanent", "Clear permanent interface pattern",
533 		    NULL, NULL, NULL),
534 		NEWLINE, "Delete any interface pattern",
535 		NULL, cmd_perm_iface_pattern, NULL);
536 
537 	commands_new(
538 		commands_new(configure_interface,
539 		    "description", "Update interface descriptions with neighbor name",
540 		    NULL, NULL, NULL),
541 		NEWLINE, "Update interface descriptions with neighbor name",
542 		NULL, cmd_update_descriptions, "enable");
543 	commands_new(
544 		commands_new(unconfigure_interface,
545 		    "description", "Don't update interface descriptions with neighbor name",
546 		    NULL, NULL, NULL),
547 		NEWLINE, "Don't update interface descriptions with neighbor name",
548 		NULL, cmd_update_descriptions, NULL);
549 
550 	commands_new(
551 		commands_new(configure_interface,
552 		    "promiscuous", "Enable promiscuous mode on managed interfaces",
553 		    NULL, NULL, NULL),
554 		NEWLINE, "Enable promiscuous mode on managed interfaces",
555 		NULL, cmd_iface_promisc, "enable");
556 	commands_new(
557 		commands_new(unconfigure_interface,
558 		    "promiscuous", "Don't enable promiscuous mode on managed interfaces",
559 		    NULL, NULL, NULL),
560 		NEWLINE, "Don't enable promiscuous mode on managed interfaces",
561 		NULL, cmd_iface_promisc, NULL);
562 
563 	register_commands_srcmac_type(configure_system);
564 }
565 
566