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