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