2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: stable/10/usr.sbin/rtadvd/control_server.c 225519 2011-09-12 23:52:55Z hrs $
30 #include <sys/queue.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
37 #include <net/if_dl.h>
38 #include <netinet/in.h>
39 #include <netinet/icmp6.h>
51 #include "pathnames.h"
56 #include "control_server.h"
59 static char *do_reload_ifname
;
61 static int do_shutdown
;
63 void set_do_reload(int sig __unused
) { do_reload
= 1; }
64 void set_do_reload_ifname(char *ifname
){ do_reload_ifname
= ifname
; }
65 void set_do_shutdown(int sig __unused
) { do_shutdown
= 1; }
66 void reset_do_reload(void) { do_reload
= 0; do_reload_ifname
= NULL
; }
67 void reset_do_shutdown(void) { do_shutdown
= 0; }
68 int is_do_reload(void) { return (do_reload
); }
69 int is_do_shutdown(void) { return (do_shutdown
); }
70 char *reload_ifname(void) { return (do_reload_ifname
); }
72 #define DEF_PL_HANDLER(key) { #key, cm_getprop_##key }
74 static int cm_getprop_echo(struct ctrl_msg_pl
*);
75 static int cm_getprop_version(struct ctrl_msg_pl
*);
76 static int cm_getprop_ifilist(struct ctrl_msg_pl
*);
77 static int cm_getprop_ifi(struct ctrl_msg_pl
*);
78 static int cm_getprop_ifi_ra_timer(struct ctrl_msg_pl
*);
79 static int cm_getprop_rai(struct ctrl_msg_pl
*);
80 static int cm_getprop_pfx(struct ctrl_msg_pl
*);
81 static int cm_getprop_rdnss(struct ctrl_msg_pl
*);
82 static int cm_getprop_dnssl(struct ctrl_msg_pl
*);
83 static int cm_getprop_rti(struct ctrl_msg_pl
*);
85 static int cm_setprop_reload(struct ctrl_msg_pl
*);
86 static int cm_setprop_enable(struct ctrl_msg_pl
*);
87 static int cm_setprop_disable(struct ctrl_msg_pl
*);
89 static struct dispatch_table
{
91 int (*dt_act
)(struct ctrl_msg_pl
*cp
);
92 } getprop_dtable
[] = {
93 { "", cm_getprop_echo
},
95 DEF_PL_HANDLER(version
),
96 DEF_PL_HANDLER(ifilist
),
98 DEF_PL_HANDLER(ifi_ra_timer
),
102 DEF_PL_HANDLER(rdnss
),
103 DEF_PL_HANDLER(dnssl
),
107 cm_getprop_echo(struct ctrl_msg_pl
*cp
)
110 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
111 cp
->cp_val
= strdup("");
112 cp
->cp_val_len
= strlen(cp
->cp_val
) + 1;
118 cm_getprop_version(struct ctrl_msg_pl
*cp
)
121 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
122 cp
->cp_val
= strdup(CM_VERSION_STR
);
123 cp
->cp_val_len
= strlen(cp
->cp_val
) + 1;
129 cm_getprop_ifilist(struct ctrl_msg_pl
*cp
)
135 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
138 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
139 len
+= strlen(ifi
->ifi_ifname
) + 1;
142 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
151 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
152 syslog(LOG_DEBUG
, "<%s> add ifname=%s(%d)",
153 __func__
, ifi
->ifi_ifname
, ifi
->ifi_ifindex
);
154 strcpy(p
, ifi
->ifi_ifname
);
155 p
+= strlen(ifi
->ifi_ifname
) + 1;
157 cp
->cp_val_len
= p
- cp
->cp_val
;
163 cm_getprop_ifi(struct ctrl_msg_pl
*cp
)
169 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
171 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
172 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
176 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
181 p
= malloc(sizeof(*ifi
));
184 len
= cm_str2bin(p
, ifi
, sizeof(*ifi
));
186 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
192 cp
->cp_val_len
= len
;
198 cm_getprop_rai(struct ctrl_msg_pl
*cp
)
205 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
207 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
208 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
212 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
216 if ((rai
= ifi
->ifi_rainfo
) == NULL
) {
217 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
222 p
= malloc(sizeof(*rai
));
225 len
= cm_str2bin(p
, rai
, sizeof(*rai
));
227 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
233 cp
->cp_val_len
= len
;
239 cm_getprop_ifi_ra_timer(struct ctrl_msg_pl
*cp
)
243 struct rtadvd_timer
*rtimer
;
247 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
249 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
250 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
254 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
258 if ((rai
= ifi
->ifi_rainfo
) == NULL
) {
259 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
263 if ((rtimer
= ifi
->ifi_ra_timer
) == NULL
) {
264 syslog(LOG_ERR
, "<%s> %s has no ifi_ra_timer", __func__
,
268 p
= malloc(sizeof(*rtimer
));
271 len
= cm_str2bin(p
, rtimer
, sizeof(*rtimer
));
273 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
279 cp
->cp_val_len
= len
;
285 cm_getprop_rti(struct ctrl_msg_pl
*cp
)
293 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
296 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
297 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
301 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
305 if (ifi
->ifi_rainfo
== NULL
) {
306 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
310 rai
= ifi
->ifi_rainfo
;
311 TAILQ_FOREACH(rti
, &rai
->rai_route
, rti_next
) {
315 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
324 TAILQ_FOREACH(rti
, &rai
->rai_route
, rti_next
) {
325 memcpy(p
, rti
, sizeof(*rti
));
328 cp
->cp_val_len
= p
- cp
->cp_val
;
334 cm_getprop_pfx(struct ctrl_msg_pl
*cp
)
342 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
345 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
346 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
350 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
354 if (ifi
->ifi_rainfo
== NULL
) {
355 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
359 rai
= ifi
->ifi_rainfo
;
360 TAILQ_FOREACH(pfx
, &rai
->rai_prefix
, pfx_next
) {
364 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
373 TAILQ_FOREACH(pfx
, &rai
->rai_prefix
, pfx_next
) {
374 memcpy(p
, pfx
, sizeof(*pfx
));
377 cp
->cp_val_len
= p
- cp
->cp_val
;
383 cm_getprop_rdnss(struct ctrl_msg_pl
*cp
)
388 struct rdnss_addr
*rda
;
394 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
397 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
398 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
402 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
406 if (ifi
->ifi_rainfo
== NULL
) {
407 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
411 rai
= ifi
->ifi_rainfo
;
413 len
= sizeof(*rdn_cnt
);
414 TAILQ_FOREACH(rdn
, &rai
->rai_rdnss
, rd_next
) {
416 len
+= sizeof(*rda_cnt
);
417 TAILQ_FOREACH(rda
, &rdn
->rd_list
, ra_next
) {
422 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
430 rdn_cnt
= (uint16_t *)p
;
431 p
+= sizeof(*rdn_cnt
);
432 TAILQ_FOREACH(rdn
, &rai
->rai_rdnss
, rd_next
) {
434 memcpy(p
, rdn
, sizeof(*rdn
));
437 rda_cnt
= (uint16_t *)p
;
438 p
+= sizeof(*rda_cnt
);
439 TAILQ_FOREACH(rda
, &rdn
->rd_list
, ra_next
) {
441 memcpy(p
, rda
, sizeof(*rda
));
445 syslog(LOG_DEBUG
, "<%s> rdn_cnt = %d", __func__
, *rdn_cnt
);
446 cp
->cp_val_len
= p
- cp
->cp_val
;
452 cm_getprop_dnssl(struct ctrl_msg_pl
*cp
)
457 struct dnssl_addr
*dna
;
463 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
466 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
467 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
471 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
475 if (ifi
->ifi_rainfo
== NULL
) {
476 syslog(LOG_ERR
, "<%s> %s has no rainfo", __func__
,
480 rai
= ifi
->ifi_rainfo
;
482 len
= sizeof(*dns_cnt
);
483 TAILQ_FOREACH(dns
, &rai
->rai_dnssl
, dn_next
) {
485 len
+= sizeof(*dna_cnt
);
486 TAILQ_FOREACH(dna
, &dns
->dn_list
, da_next
) {
491 syslog(LOG_DEBUG
, "<%s> len = %zu", __func__
, len
);
499 dns_cnt
= (uint16_t *)cp
->cp_val
;
500 p
+= sizeof(*dns_cnt
);
501 TAILQ_FOREACH(dns
, &rai
->rai_dnssl
, dn_next
) {
503 memcpy(p
, dns
, sizeof(*dns
));
506 dna_cnt
= (uint16_t *)p
;
507 p
+= sizeof(*dna_cnt
);
508 TAILQ_FOREACH(dna
, &dns
->dn_list
, da_next
) {
510 memcpy(p
, dna
, sizeof(*dna
));
514 cp
->cp_val_len
= p
- cp
->cp_val
;
520 cm_getprop(struct ctrl_msg_pl
*cp
)
524 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
530 i
< sizeof(getprop_dtable
) / sizeof(getprop_dtable
[0]);
532 if (strcmp(cp
->cp_key
, getprop_dtable
[i
].dt_comm
) == 0)
533 return (getprop_dtable
[i
].dt_act(cp
));
539 cm_setprop(struct ctrl_msg_pl
*cp
)
541 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
543 if (cp
== NULL
|| cp
->cp_key
== NULL
)
546 if (strncmp(cp
->cp_key
, "reload", sizeof("reload")) == 0)
547 cm_setprop_reload(cp
);
548 else if (strncmp(cp
->cp_key
, "shutdown", sizeof("shutdown")) == 0)
550 else if (strncmp(cp
->cp_key
, "enable", sizeof("enable")) == 0)
551 cm_setprop_enable(cp
);
552 else if (strncmp(cp
->cp_key
, "disable", sizeof("disable")) == 0)
553 cm_setprop_disable(cp
);
554 else if (strncmp(cp
->cp_key
, "echo", 8) == 0)
563 cm_setprop_reload(struct ctrl_msg_pl
*cp
)
566 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
568 set_do_reload_ifname(cp
->cp_ifname
);
575 cm_setprop_enable(struct ctrl_msg_pl
*cp
)
579 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
581 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
582 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
586 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
591 ifi
->ifi_persist
= 1;
592 set_do_reload_ifname(ifi
->ifi_ifname
);
599 cm_setprop_disable(struct ctrl_msg_pl
*cp
)
603 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
605 TAILQ_FOREACH(ifi
, &ifilist
, ifi_next
) {
606 if (strcmp(cp
->cp_ifname
, ifi
->ifi_ifname
) == 0)
610 syslog(LOG_ERR
, "<%s> %s not found", __func__
,
615 if (ifi
->ifi_persist
== 1) {
616 ifi
->ifi_persist
= 0;
619 /* MC leaving needed here */
620 sock_mc_leave(&sock
, ifi
->ifi_ifindex
);
622 set_do_reload_ifname(ifi
->ifi_ifname
);
630 cm_handler_server(int fd
)
634 struct ctrl_msg_hdr
*cm
;
635 struct ctrl_msg_pl cp
;
636 char buf
[CM_MSG_MAXLEN
];
637 char pbuf
[CM_MSG_MAXLEN
];
640 syslog(LOG_DEBUG
, "<%s> enter", __func__
);
642 memset(buf
, 0, sizeof(buf
));
643 memset(pbuf
, 0, sizeof(pbuf
));
644 cm
= (struct ctrl_msg_hdr
*)buf
;
645 msg
= (char *)buf
+ sizeof(*cm
);
647 state
= CM_STATE_INIT
;
648 while (state
!= CM_STATE_EOM
) {
649 syslog(LOG_DEBUG
, "<%s> state = %d", __func__
, state
);
653 state
= CM_STATE_MSG_RECV
;
655 case CM_STATE_MSG_DISPATCH
:
656 cm
->cm_version
= CM_VERSION
;
657 error
= cm_send(fd
, buf
);
660 "<%s> cm_send()", __func__
);
661 state
= CM_STATE_EOM
;
663 case CM_STATE_ACK_WAIT
:
664 error
= cm_recv(fd
, buf
);
667 "<%s> cm_recv()", __func__
);
672 switch (cm
->cm_type
) {
677 "<%s> CM_TYPE_ERR", __func__
);
682 "<%s> unknown status", __func__
);
686 state
= CM_STATE_EOM
;
688 case CM_STATE_MSG_RECV
:
689 error
= cm_recv(fd
, buf
);
693 "<%s> cm_recv()", __func__
);
697 memset(&cp
, 0, sizeof(cp
));
700 "<%s> cm->cm_type = %d", __func__
, cm
->cm_type
);
702 "<%s> cm->cm_len = %zu", __func__
, cm
->cm_len
);
704 switch (cm
->cm_type
) {
706 state
= CM_STATE_EOM
;
708 cm
->cm_type
= CM_TYPE_ACK
;
709 cm
->cm_len
= sizeof(*cm
);
711 case CM_TYPE_REQ_GET_PROP
:
713 error
= cm_getprop(&cp
);
715 cm
->cm_type
= CM_TYPE_ERR
;
716 cm
->cm_len
= sizeof(*cm
);
718 cm
->cm_type
= CM_TYPE_ACK
;
719 cm
->cm_len
= sizeof(*cm
);
720 cm
->cm_len
+= cm_pl2bin(msg
, &cp
);
722 if (cp
.cp_val
!= NULL
)
725 case CM_TYPE_REQ_SET_PROP
:
727 error
= cm_setprop(&cp
);
729 cm
->cm_type
= CM_TYPE_ERR
;
730 cm
->cm_len
= sizeof(*cm
);
732 cm
->cm_type
= CM_TYPE_ACK
;
733 cm
->cm_len
= sizeof(*cm
);
737 cm
->cm_type
= CM_TYPE_ERR
;
738 cm
->cm_len
= sizeof(*cm
);
741 switch (cm
->cm_type
) {
744 state
= CM_STATE_MSG_DISPATCH
;
749 syslog(LOG_DEBUG
, "<%s> leave", __func__
);