2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41 #include <netinet/icmp6.h>
53 #include "pathnames.h"
58 #include "control_server.h"
61 static char *do_reload_ifname;
63 static int do_shutdown;
65 void set_do_reload(int sig __unused) { do_reload = 1; }
66 void set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
67 void set_do_shutdown(int sig __unused) { do_shutdown = 1; }
68 void reset_do_reload(void) { do_reload = 0; do_reload_ifname = NULL; }
69 void reset_do_shutdown(void) { do_shutdown = 0; }
70 int is_do_reload(void) { return (do_reload); }
71 int is_do_shutdown(void) { return (do_shutdown); }
72 char *reload_ifname(void) { return (do_reload_ifname); }
74 #define DEF_PL_HANDLER(key) { #key, cm_getprop_##key }
76 static int cm_getprop_echo(struct ctrl_msg_pl *);
77 static int cm_getprop_version(struct ctrl_msg_pl *);
78 static int cm_getprop_ifilist(struct ctrl_msg_pl *);
79 static int cm_getprop_ifi(struct ctrl_msg_pl *);
80 static int cm_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
81 static int cm_getprop_rai(struct ctrl_msg_pl *);
82 static int cm_getprop_pfx(struct ctrl_msg_pl *);
83 static int cm_getprop_rdnss(struct ctrl_msg_pl *);
84 static int cm_getprop_dnssl(struct ctrl_msg_pl *);
85 static int cm_getprop_rti(struct ctrl_msg_pl *);
87 static int cm_setprop_reload(struct ctrl_msg_pl *);
88 static int cm_setprop_enable(struct ctrl_msg_pl *);
89 static int cm_setprop_disable(struct ctrl_msg_pl *);
91 static struct dispatch_table {
93 int (*dt_act)(struct ctrl_msg_pl *cp);
94 } getprop_dtable[] = {
95 { "", cm_getprop_echo },
97 DEF_PL_HANDLER(version),
98 DEF_PL_HANDLER(ifilist),
100 DEF_PL_HANDLER(ifi_ra_timer),
104 DEF_PL_HANDLER(rdnss),
105 DEF_PL_HANDLER(dnssl),
109 cm_getprop_echo(struct ctrl_msg_pl *cp)
112 syslog(LOG_DEBUG, "<%s> enter", __func__);
113 cp->cp_val = strdup("");
114 cp->cp_val_len = strlen(cp->cp_val) + 1;
120 cm_getprop_version(struct ctrl_msg_pl *cp)
123 syslog(LOG_DEBUG, "<%s> enter", __func__);
124 cp->cp_val = strdup(CM_VERSION_STR);
125 cp->cp_val_len = strlen(cp->cp_val) + 1;
131 cm_getprop_ifilist(struct ctrl_msg_pl *cp)
137 syslog(LOG_DEBUG, "<%s> enter", __func__);
140 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
141 len += strlen(ifi->ifi_ifname) + 1;
144 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
153 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
154 syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
155 __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
156 strcpy(p, ifi->ifi_ifname);
157 p += strlen(ifi->ifi_ifname) + 1;
159 cp->cp_val_len = p - cp->cp_val;
165 cm_getprop_ifi(struct ctrl_msg_pl *cp)
171 syslog(LOG_DEBUG, "<%s> enter", __func__);
173 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
174 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
178 syslog(LOG_ERR, "<%s> %s not found", __func__,
183 p = malloc(sizeof(*ifi));
186 len = cm_str2bin(p, ifi, sizeof(*ifi));
188 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
194 cp->cp_val_len = len;
200 cm_getprop_rai(struct ctrl_msg_pl *cp)
207 syslog(LOG_DEBUG, "<%s> enter", __func__);
209 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
210 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
214 syslog(LOG_ERR, "<%s> %s not found", __func__,
218 if ((rai = ifi->ifi_rainfo) == NULL) {
219 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
224 p = malloc(sizeof(*rai));
227 len = cm_str2bin(p, rai, sizeof(*rai));
229 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
235 cp->cp_val_len = len;
241 cm_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
245 struct rtadvd_timer *rtimer;
249 syslog(LOG_DEBUG, "<%s> enter", __func__);
251 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
252 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
256 syslog(LOG_ERR, "<%s> %s not found", __func__,
260 if ((rai = ifi->ifi_rainfo) == NULL) {
261 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
265 if ((rtimer = ifi->ifi_ra_timer) == NULL) {
266 syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
270 p = malloc(sizeof(*rtimer));
273 len = cm_str2bin(p, rtimer, sizeof(*rtimer));
275 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
281 cp->cp_val_len = len;
287 cm_getprop_rti(struct ctrl_msg_pl *cp)
295 syslog(LOG_DEBUG, "<%s> enter", __func__);
298 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
299 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
303 syslog(LOG_ERR, "<%s> %s not found", __func__,
307 if (ifi->ifi_rainfo == NULL) {
308 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
312 rai = ifi->ifi_rainfo;
313 TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
317 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
326 TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
327 memcpy(p, rti, sizeof(*rti));
330 cp->cp_val_len = p - cp->cp_val;
336 cm_getprop_pfx(struct ctrl_msg_pl *cp)
344 syslog(LOG_DEBUG, "<%s> enter", __func__);
347 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
348 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
352 syslog(LOG_ERR, "<%s> %s not found", __func__,
356 if (ifi->ifi_rainfo == NULL) {
357 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
361 rai = ifi->ifi_rainfo;
362 TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
366 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
375 TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
376 memcpy(p, pfx, sizeof(*pfx));
379 cp->cp_val_len = p - cp->cp_val;
385 cm_getprop_rdnss(struct ctrl_msg_pl *cp)
390 struct rdnss_addr *rda;
396 syslog(LOG_DEBUG, "<%s> enter", __func__);
399 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
400 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
404 syslog(LOG_ERR, "<%s> %s not found", __func__,
408 if (ifi->ifi_rainfo == NULL) {
409 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
413 rai = ifi->ifi_rainfo;
415 len = sizeof(*rdn_cnt);
416 TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
418 len += sizeof(*rda_cnt);
419 TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
424 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
432 rdn_cnt = (uint16_t *)p;
433 p += sizeof(*rdn_cnt);
434 TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
436 memcpy(p, rdn, sizeof(*rdn));
439 rda_cnt = (uint16_t *)p;
440 p += sizeof(*rda_cnt);
441 TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
443 memcpy(p, rda, sizeof(*rda));
447 syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
448 cp->cp_val_len = p - cp->cp_val;
454 cm_getprop_dnssl(struct ctrl_msg_pl *cp)
459 struct dnssl_addr *dna;
465 syslog(LOG_DEBUG, "<%s> enter", __func__);
468 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
469 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
473 syslog(LOG_ERR, "<%s> %s not found", __func__,
477 if (ifi->ifi_rainfo == NULL) {
478 syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
482 rai = ifi->ifi_rainfo;
484 len = sizeof(*dns_cnt);
485 TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
487 len += sizeof(*dna_cnt);
488 TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
493 syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
501 dns_cnt = (uint16_t *)cp->cp_val;
502 p += sizeof(*dns_cnt);
503 TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
505 memcpy(p, dns, sizeof(*dns));
508 dna_cnt = (uint16_t *)p;
509 p += sizeof(*dna_cnt);
510 TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
512 memcpy(p, dna, sizeof(*dna));
516 cp->cp_val_len = p - cp->cp_val;
522 cm_getprop(struct ctrl_msg_pl *cp)
526 syslog(LOG_DEBUG, "<%s> enter", __func__);
532 i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
534 if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
535 return (getprop_dtable[i].dt_act(cp));
541 cm_setprop(struct ctrl_msg_pl *cp)
543 syslog(LOG_DEBUG, "<%s> enter", __func__);
545 if (cp == NULL || cp->cp_key == NULL)
548 if (strncmp(cp->cp_key, "reload", sizeof("reload")) == 0)
549 cm_setprop_reload(cp);
550 else if (strncmp(cp->cp_key, "shutdown", sizeof("shutdown")) == 0)
552 else if (strncmp(cp->cp_key, "enable", sizeof("enable")) == 0)
553 cm_setprop_enable(cp);
554 else if (strncmp(cp->cp_key, "disable", sizeof("disable")) == 0)
555 cm_setprop_disable(cp);
556 else if (strncmp(cp->cp_key, "echo", 8) == 0)
565 cm_setprop_reload(struct ctrl_msg_pl *cp)
568 syslog(LOG_DEBUG, "<%s> enter", __func__);
570 set_do_reload_ifname(cp->cp_ifname);
577 cm_setprop_enable(struct ctrl_msg_pl *cp)
581 syslog(LOG_DEBUG, "<%s> enter", __func__);
583 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
584 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
588 syslog(LOG_ERR, "<%s> %s not found", __func__,
593 ifi->ifi_persist = 1;
594 set_do_reload_ifname(ifi->ifi_ifname);
601 cm_setprop_disable(struct ctrl_msg_pl *cp)
605 syslog(LOG_DEBUG, "<%s> enter", __func__);
607 TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
608 if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
612 syslog(LOG_ERR, "<%s> %s not found", __func__,
617 if (ifi->ifi_persist == 1) {
618 ifi->ifi_persist = 0;
621 /* MC leaving needed here */
622 sock_mc_leave(&sock, ifi->ifi_ifindex);
624 set_do_reload_ifname(ifi->ifi_ifname);
632 cm_handler_server(int fd)
636 struct ctrl_msg_hdr *cm;
637 struct ctrl_msg_pl cp;
638 char buf[CM_MSG_MAXLEN];
639 char pbuf[CM_MSG_MAXLEN];
642 syslog(LOG_DEBUG, "<%s> enter", __func__);
644 memset(buf, 0, sizeof(buf));
645 memset(pbuf, 0, sizeof(pbuf));
646 cm = (struct ctrl_msg_hdr *)buf;
647 msg = (char *)buf + sizeof(*cm);
649 state = CM_STATE_INIT;
650 while (state != CM_STATE_EOM) {
651 syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
655 state = CM_STATE_MSG_RECV;
657 case CM_STATE_MSG_DISPATCH:
658 cm->cm_version = CM_VERSION;
659 error = cm_send(fd, buf);
662 "<%s> cm_send()", __func__);
663 state = CM_STATE_EOM;
665 case CM_STATE_ACK_WAIT:
666 error = cm_recv(fd, buf);
669 "<%s> cm_recv()", __func__);
674 switch (cm->cm_type) {
679 "<%s> CM_TYPE_ERR", __func__);
684 "<%s> unknown status", __func__);
688 state = CM_STATE_EOM;
690 case CM_STATE_MSG_RECV:
691 error = cm_recv(fd, buf);
695 "<%s> cm_recv()", __func__);
699 memset(&cp, 0, sizeof(cp));
702 "<%s> cm->cm_type = %d", __func__, cm->cm_type);
704 "<%s> cm->cm_len = %zu", __func__, cm->cm_len);
706 switch (cm->cm_type) {
708 state = CM_STATE_EOM;
710 cm->cm_type = CM_TYPE_ACK;
711 cm->cm_len = sizeof(*cm);
713 case CM_TYPE_REQ_GET_PROP:
715 error = cm_getprop(&cp);
717 cm->cm_type = CM_TYPE_ERR;
718 cm->cm_len = sizeof(*cm);
720 cm->cm_type = CM_TYPE_ACK;
721 cm->cm_len = sizeof(*cm);
722 cm->cm_len += cm_pl2bin(msg, &cp);
724 if (cp.cp_val != NULL)
727 case CM_TYPE_REQ_SET_PROP:
729 error = cm_setprop(&cp);
731 cm->cm_type = CM_TYPE_ERR;
732 cm->cm_len = sizeof(*cm);
734 cm->cm_type = CM_TYPE_ACK;
735 cm->cm_len = sizeof(*cm);
739 cm->cm_type = CM_TYPE_ERR;
740 cm->cm_len = sizeof(*cm);
743 switch (cm->cm_type) {
746 state = CM_STATE_MSG_DISPATCH;
751 syslog(LOG_DEBUG, "<%s> leave", __func__);