xref: /freebsd/usr.sbin/rtadvd/control_server.c (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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.
27  *
28  * $FreeBSD$
29  *
30  */
31 
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <sys/un.h>
37 #include <sys/uio.h>
38 #include <net/if.h>
39 #include <net/if_dl.h>
40 #include <netinet/in.h>
41 #include <netinet/icmp6.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <netdb.h>
45 #include <unistd.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <syslog.h>
52 
53 #include "pathnames.h"
54 #include "rtadvd.h"
55 #include "if.h"
56 #include "config.h"
57 #include "control.h"
58 #include "control_server.h"
59 #include "timer.h"
60 
61 static char *do_reload_ifname;
62 static int do_reload;
63 static int do_shutdown;
64 
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); }
73 
74 #define	DEF_PL_HANDLER(key)	{ #key, cm_getprop_##key }
75 
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 *);
86 
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 *);
90 
91 static struct dispatch_table {
92 	const char	*dt_comm;
93 	int		(*dt_act)(struct ctrl_msg_pl *cp);
94 } getprop_dtable[] = {
95 	{ "",	cm_getprop_echo },
96 	DEF_PL_HANDLER(echo),
97 	DEF_PL_HANDLER(version),
98 	DEF_PL_HANDLER(ifilist),
99 	DEF_PL_HANDLER(ifi),
100 	DEF_PL_HANDLER(ifi_ra_timer),
101 	DEF_PL_HANDLER(rai),
102 	DEF_PL_HANDLER(rti),
103 	DEF_PL_HANDLER(pfx),
104 	DEF_PL_HANDLER(rdnss),
105 	DEF_PL_HANDLER(dnssl),
106 };
107 
108 static int
109 cm_getprop_echo(struct ctrl_msg_pl *cp)
110 {
111 
112 	syslog(LOG_DEBUG, "<%s> enter", __func__);
113 	cp->cp_val = strdup("");
114 	cp->cp_val_len = strlen(cp->cp_val) + 1;
115 
116 	return (0);
117 }
118 
119 static int
120 cm_getprop_version(struct ctrl_msg_pl *cp)
121 {
122 
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;
126 
127 	return (0);
128 }
129 
130 static int
131 cm_getprop_ifilist(struct ctrl_msg_pl *cp)
132 {
133 	struct ifinfo *ifi;
134 	char *p;
135 	size_t len;
136 
137 	syslog(LOG_DEBUG, "<%s> enter", __func__);
138 
139 	len = 0;
140 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
141 		len += strlen(ifi->ifi_ifname) + 1;
142 	}
143 
144 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
145 
146 	p = malloc(len);
147 	if (p == NULL)
148 		exit(1);
149 	memset(p, 0, len);
150 	cp->cp_val = p;
151 
152 	if (len > 0)
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;
158 		}
159 	cp->cp_val_len = p - cp->cp_val;
160 
161 	return (0);
162 }
163 
164 static int
165 cm_getprop_ifi(struct ctrl_msg_pl *cp)
166 {
167 	struct ifinfo *ifi;
168 	char *p;
169 	size_t len;
170 
171 	syslog(LOG_DEBUG, "<%s> enter", __func__);
172 
173 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
174 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
175 			break;
176 	}
177 	if (ifi == NULL) {
178 		syslog(LOG_ERR, "<%s> %s not found", __func__,
179 		    cp->cp_ifname);
180 		return (1);
181 	}
182 
183 	p = malloc(sizeof(*ifi));
184 	if (p == NULL)
185 		exit(1);
186 	len = cm_str2bin(p, ifi, sizeof(*ifi));
187 
188 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
189 
190 	if (len == 0)
191 		return (1);
192 
193 	cp->cp_val = p;
194 	cp->cp_val_len = len;
195 
196 	return (0);
197 }
198 
199 static int
200 cm_getprop_rai(struct ctrl_msg_pl *cp)
201 {
202 	struct ifinfo *ifi;
203 	struct rainfo *rai;
204 	char *p;
205 	size_t len;
206 
207 	syslog(LOG_DEBUG, "<%s> enter", __func__);
208 
209 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
210 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
211 			break;
212 	}
213 	if (ifi == NULL) {
214 		syslog(LOG_ERR, "<%s> %s not found", __func__,
215 		    cp->cp_ifname);
216 		return (1);
217 	}
218 	if ((rai = ifi->ifi_rainfo) == NULL) {
219 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
220 		    cp->cp_ifname);
221 		return (1);
222 	}
223 
224 	p = malloc(sizeof(*rai));
225 	if (p == NULL)
226 		exit(1);
227 	len = cm_str2bin(p, rai, sizeof(*rai));
228 
229 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
230 
231 	if (len == 0)
232 		return (1);
233 
234 	cp->cp_val = p;
235 	cp->cp_val_len = len;
236 
237 	return (0);
238 }
239 
240 static int
241 cm_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
242 {
243 	struct ifinfo *ifi;
244 	struct rainfo *rai;
245 	struct rtadvd_timer	*rtimer;
246 	char *p;
247 	size_t len;
248 
249 	syslog(LOG_DEBUG, "<%s> enter", __func__);
250 
251 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
252 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
253 			break;
254 	}
255 	if (ifi == NULL) {
256 		syslog(LOG_ERR, "<%s> %s not found", __func__,
257 		    cp->cp_ifname);
258 		return (1);
259 	}
260 	if ((rai = ifi->ifi_rainfo) == NULL) {
261 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
262 		    cp->cp_ifname);
263 		return (1);
264 	}
265 	if ((rtimer = ifi->ifi_ra_timer) == NULL) {
266 		syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
267 		    cp->cp_ifname);
268 		return (1);
269 	}
270 	p = malloc(sizeof(*rtimer));
271 	if (p == NULL)
272 		exit(1);
273 	len = cm_str2bin(p, rtimer, sizeof(*rtimer));
274 
275 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
276 
277 	if (len == 0)
278 		return (1);
279 
280 	cp->cp_val = p;
281 	cp->cp_val_len = len;
282 
283 	return (0);
284 }
285 
286 static int
287 cm_getprop_rti(struct ctrl_msg_pl *cp)
288 {
289 	struct ifinfo *ifi;
290 	struct rainfo *rai;
291 	struct rtinfo *rti;
292 	char *p;
293 	size_t len;
294 
295 	syslog(LOG_DEBUG, "<%s> enter", __func__);
296 
297 	len = 0;
298 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
299 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
300 			break;
301 	}
302 	if (ifi == NULL) {
303 		syslog(LOG_ERR, "<%s> %s not found", __func__,
304 		    cp->cp_ifname);
305 		return (1);
306 	}
307 	if (ifi->ifi_rainfo == NULL) {
308 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
309 		    cp->cp_ifname);
310 		return (1);
311 	}
312 	rai = ifi->ifi_rainfo;
313 	TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
314 		len += sizeof(*rti);
315 	}
316 
317 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
318 
319 	p = malloc(len);
320 	if (p == NULL)
321 		exit(1);
322 	memset(p, 0, len);
323 	cp->cp_val = p;
324 
325 	if (len > 0)
326 		TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
327 			memcpy(p, rti, sizeof(*rti));
328 			p += sizeof(*rti);
329 		}
330 	cp->cp_val_len = p - cp->cp_val;
331 
332 	return (0);
333 }
334 
335 static int
336 cm_getprop_pfx(struct ctrl_msg_pl *cp)
337 {
338 	struct ifinfo *ifi;
339 	struct rainfo *rai;
340 	struct prefix *pfx;
341 	char *p;
342 	size_t len;
343 
344 	syslog(LOG_DEBUG, "<%s> enter", __func__);
345 
346 	len = 0;
347 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
348 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
349 			break;
350 	}
351 	if (ifi == NULL) {
352 		syslog(LOG_ERR, "<%s> %s not found", __func__,
353 		    cp->cp_ifname);
354 		return (1);
355 	}
356 	if (ifi->ifi_rainfo == NULL) {
357 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
358 		    cp->cp_ifname);
359 		return (1);
360 	}
361 	rai = ifi->ifi_rainfo;
362 	TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
363 		len += sizeof(*pfx);
364 	}
365 
366 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
367 
368 	p = malloc(len);
369 	if (p == NULL)
370 		exit(1);
371 	memset(p, 0, len);
372 	cp->cp_val = p;
373 
374 	if (len > 0)
375 		TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
376 			memcpy(p, pfx, sizeof(*pfx));
377 			p += sizeof(*pfx);
378 		}
379 	cp->cp_val_len = p - cp->cp_val;
380 
381 	return (0);
382 }
383 
384 static int
385 cm_getprop_rdnss(struct ctrl_msg_pl *cp)
386 {
387 	struct ifinfo *ifi;
388 	struct rainfo *rai;
389 	struct rdnss *rdn;
390 	struct rdnss_addr *rda;
391 	char *p;
392 	size_t len;
393 	uint16_t *rdn_cnt;
394 	uint16_t *rda_cnt;
395 
396 	syslog(LOG_DEBUG, "<%s> enter", __func__);
397 
398 	len = 0;
399 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
400 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
401 			break;
402 	}
403 	if (ifi == NULL) {
404 		syslog(LOG_ERR, "<%s> %s not found", __func__,
405 		    cp->cp_ifname);
406 		return (1);
407 	}
408 	if (ifi->ifi_rainfo == NULL) {
409 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
410 		    cp->cp_ifname);
411 		return (1);
412 	}
413 	rai = ifi->ifi_rainfo;
414 
415 	len = sizeof(*rdn_cnt);
416 	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
417 		len += sizeof(*rdn);
418 		len += sizeof(*rda_cnt);
419 		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
420 			len += sizeof(*rda);
421 		}
422 	}
423 
424 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
425 
426 	p = malloc(len);
427 	if (p == NULL)
428 		exit(1);
429 	memset(p, 0, len);
430 	cp->cp_val = p;
431 
432 	rdn_cnt = (uint16_t *)p;
433 	p += sizeof(*rdn_cnt);
434 	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
435 		*rdn_cnt += 1;
436 		memcpy(p, rdn, sizeof(*rdn));
437 		p += sizeof(*rdn);
438 
439 		rda_cnt = (uint16_t *)p;
440 		p += sizeof(*rda_cnt);
441 		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
442 			*rda_cnt += 1;
443 			memcpy(p, rda, sizeof(*rda));
444 			p += sizeof(*rda);
445 		}
446 	}
447 	syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
448 	cp->cp_val_len = p - cp->cp_val;
449 
450 	return (0);
451 }
452 
453 static int
454 cm_getprop_dnssl(struct ctrl_msg_pl *cp)
455 {
456 	struct ifinfo *ifi;
457 	struct rainfo *rai;
458 	struct dnssl *dns;
459 	struct dnssl_addr *dna;
460 	char *p;
461 	size_t len;
462 	uint16_t *dns_cnt;
463 	uint16_t *dna_cnt;
464 
465 	syslog(LOG_DEBUG, "<%s> enter", __func__);
466 
467 	len = 0;
468 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
469 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
470 			break;
471 	}
472 	if (ifi == NULL) {
473 		syslog(LOG_ERR, "<%s> %s not found", __func__,
474 		    cp->cp_ifname);
475 		return (1);
476 	}
477 	if (ifi->ifi_rainfo == NULL) {
478 		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
479 		    cp->cp_ifname);
480 		return (1);
481 	}
482 	rai = ifi->ifi_rainfo;
483 
484 	len = sizeof(*dns_cnt);
485 	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
486 		len += sizeof(*dns);
487 		len += sizeof(*dna_cnt);
488 		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
489 			len += sizeof(*dna);
490 		}
491 	}
492 
493 	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
494 
495 	p = malloc(len);
496 	if (p == NULL)
497 		exit(1);
498 	memset(p, 0, len);
499 	cp->cp_val = p;
500 
501 	dns_cnt = (uint16_t *)cp->cp_val;
502 	p += sizeof(*dns_cnt);
503 	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
504 		(*dns_cnt)++;
505 		memcpy(p, dns, sizeof(*dns));
506 		p += sizeof(*dns);
507 
508 		dna_cnt = (uint16_t *)p;
509 		p += sizeof(*dna_cnt);
510 		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
511 			(*dna_cnt)++;
512 			memcpy(p, dna, sizeof(*dna));
513 			p += sizeof(*dna);
514 		}
515 	}
516 	cp->cp_val_len = p - cp->cp_val;
517 
518 	return (0);
519 }
520 
521 int
522 cm_getprop(struct ctrl_msg_pl *cp)
523 {
524 	size_t i;
525 
526 	syslog(LOG_DEBUG, "<%s> enter", __func__);
527 
528 	if (cp == NULL)
529 		return (1);
530 
531 	for (i = 0;
532 	     i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
533 	     i++) {
534 		if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
535 			return (getprop_dtable[i].dt_act(cp));
536 	}
537 	return (1);
538 }
539 
540 int
541 cm_setprop(struct ctrl_msg_pl *cp)
542 {
543 	syslog(LOG_DEBUG, "<%s> enter", __func__);
544 
545 	if (cp == NULL || cp->cp_key == NULL)
546 		return (1);
547 
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)
551 		set_do_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)
557 		; 		/* do nothing */
558 	else
559 		return (1);
560 
561 	return (0);
562 }
563 
564 static int
565 cm_setprop_reload(struct ctrl_msg_pl *cp)
566 {
567 
568 	syslog(LOG_DEBUG, "<%s> enter", __func__);
569 
570 	set_do_reload_ifname(cp->cp_ifname);
571 	set_do_reload(1);
572 
573 	return (0);
574 }
575 
576 static int
577 cm_setprop_enable(struct ctrl_msg_pl *cp)
578 {
579 	struct ifinfo *ifi;
580 
581 	syslog(LOG_DEBUG, "<%s> enter", __func__);
582 
583 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
584 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
585 			break;
586 	}
587 	if (ifi == NULL) {
588 		syslog(LOG_ERR, "<%s> %s not found", __func__,
589 		    cp->cp_ifname);
590 		return (1);
591 	}
592 
593 	ifi->ifi_persist = 1;
594 	set_do_reload_ifname(ifi->ifi_ifname);
595 	set_do_reload(0);
596 
597 	return (0);
598 }
599 
600 static int
601 cm_setprop_disable(struct ctrl_msg_pl *cp)
602 {
603 	struct ifinfo *ifi;
604 
605 	syslog(LOG_DEBUG, "<%s> enter", __func__);
606 
607 	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
608 		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
609 			break;
610 	}
611 	if (ifi == NULL) {
612 		syslog(LOG_ERR, "<%s> %s not found", __func__,
613 		    cp->cp_ifname);
614 		return (1);
615 	}
616 
617 	if (ifi->ifi_persist == 1) {
618 		ifi->ifi_persist = 0;
619 		rm_ifinfo(ifi);
620 
621 		/* MC leaving needed here */
622 		sock_mc_leave(&sock, ifi->ifi_ifindex);
623 
624 		set_do_reload_ifname(ifi->ifi_ifname);
625 		set_do_reload(0);
626 	}
627 
628 	return (0);
629 }
630 
631 int
632 cm_handler_server(int fd)
633 {
634 	int state;
635 	char *msg;
636 	struct ctrl_msg_hdr *cm;
637 	struct ctrl_msg_pl cp;
638 	char buf[CM_MSG_MAXLEN];
639 	char pbuf[CM_MSG_MAXLEN];
640 	int error;
641 
642 	syslog(LOG_DEBUG, "<%s> enter", __func__);
643 
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);
648 
649 	state = CM_STATE_INIT;
650 	while (state != CM_STATE_EOM) {
651 		syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
652 
653 		switch (state) {
654 		case CM_STATE_INIT:
655 			state = CM_STATE_MSG_RECV;
656 			break;
657 		case CM_STATE_MSG_DISPATCH:
658 			cm->cm_version = CM_VERSION;
659 			error = cm_send(fd, buf);
660 			if (error)
661 				syslog(LOG_WARNING,
662 				    "<%s> cm_send()", __func__);
663 			state = CM_STATE_EOM;
664 			break;
665 		case CM_STATE_ACK_WAIT:
666 			error = cm_recv(fd, buf);
667 			if (error) {
668 				syslog(LOG_ERR,
669 				    "<%s> cm_recv()", __func__);
670 				close(fd);
671 				return (-1);
672 			}
673 
674 			switch (cm->cm_type) {
675 			case CM_TYPE_ACK:
676 				break;
677 			case CM_TYPE_ERR:
678 				syslog(LOG_DEBUG,
679 				    "<%s> CM_TYPE_ERR", __func__);
680 				close(fd);
681 				return (-1);
682 			default:
683 				syslog(LOG_DEBUG,
684 				    "<%s> unknown status", __func__);
685 				close(fd);
686 				return (-1);
687 			}
688 			state = CM_STATE_EOM;
689 			break;
690 		case CM_STATE_MSG_RECV:
691 			error = cm_recv(fd, buf);
692 
693 			if (error) {
694 				syslog(LOG_ERR,
695 				    "<%s> cm_recv()", __func__);
696 				close(fd);
697 				return (-1);
698 			}
699 			memset(&cp, 0, sizeof(cp));
700 
701 			syslog(LOG_DEBUG,
702 			    "<%s> cm->cm_type = %d", __func__, cm->cm_type);
703 			syslog(LOG_DEBUG,
704 			    "<%s> cm->cm_len = %zu", __func__, cm->cm_len);
705 
706 			switch (cm->cm_type) {
707 			case CM_TYPE_EOM:
708 				state = CM_STATE_EOM;
709 			case CM_TYPE_NUL:
710 				cm->cm_type = CM_TYPE_ACK;
711 				cm->cm_len = sizeof(*cm);
712 				break;
713 			case CM_TYPE_REQ_GET_PROP:
714 				cm_bin2pl(msg, &cp);
715 				error = cm_getprop(&cp);
716 				if (error) {
717 					cm->cm_type = CM_TYPE_ERR;
718 					cm->cm_len = sizeof(*cm);
719 				} else {
720 					cm->cm_type = CM_TYPE_ACK;
721 					cm->cm_len = sizeof(*cm);
722 					cm->cm_len += cm_pl2bin(msg, &cp);
723 				}
724 				if (cp.cp_val != NULL)
725 					free(cp.cp_val);
726 				break;
727 			case CM_TYPE_REQ_SET_PROP:
728 				cm_bin2pl(msg, &cp);
729 				error = cm_setprop(&cp);
730 				if (error) {
731 					cm->cm_type = CM_TYPE_ERR;
732 					cm->cm_len = sizeof(*cm);
733 				} else {
734 					cm->cm_type = CM_TYPE_ACK;
735 					cm->cm_len = sizeof(*cm);
736 				}
737 				break;
738 			default:
739 				cm->cm_type = CM_TYPE_ERR;
740 				cm->cm_len = sizeof(*cm);
741 			}
742 
743 			switch (cm->cm_type) {
744 			case CM_TYPE_ERR:
745 			case CM_TYPE_ACK:
746 				state = CM_STATE_MSG_DISPATCH;
747 				break;
748 			}
749 		}
750 	}
751 	syslog(LOG_DEBUG, "<%s> leave", __func__);
752 
753 	return (0);
754 }
755