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
61static char *do_reload_ifname;
62static int do_reload;
63static int do_shutdown;
64
65void set_do_reload(int sig __unused)	{ do_reload = 1; }
66void set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
67void set_do_shutdown(int sig __unused)	{ do_shutdown = 1; }
68void reset_do_reload(void)	{ do_reload = 0; do_reload_ifname = NULL; }
69void reset_do_shutdown(void)	{ do_shutdown = 0; }
70int is_do_reload(void)		{ return (do_reload); }
71int is_do_shutdown(void)	{ return (do_shutdown); }
72char *reload_ifname(void)	{ return (do_reload_ifname); }
73
74#define	DEF_PL_HANDLER(key)	{ #key, cm_getprop_##key }
75
76static int cm_getprop_echo(struct ctrl_msg_pl *);
77static int cm_getprop_version(struct ctrl_msg_pl *);
78static int cm_getprop_ifilist(struct ctrl_msg_pl *);
79static int cm_getprop_ifi(struct ctrl_msg_pl *);
80static int cm_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
81static int cm_getprop_rai(struct ctrl_msg_pl *);
82static int cm_getprop_pfx(struct ctrl_msg_pl *);
83static int cm_getprop_rdnss(struct ctrl_msg_pl *);
84static int cm_getprop_dnssl(struct ctrl_msg_pl *);
85static int cm_getprop_rti(struct ctrl_msg_pl *);
86
87static int cm_setprop_reload(struct ctrl_msg_pl *);
88static int cm_setprop_enable(struct ctrl_msg_pl *);
89static int cm_setprop_disable(struct ctrl_msg_pl *);
90
91static 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
108static int
109cm_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
119static int
120cm_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
130static int
131cm_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
164static int
165cm_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
199static int
200cm_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
240static int
241cm_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
286static int
287cm_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
335static int
336cm_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
384static int
385cm_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
453static int
454cm_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
521int
522cm_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
540int
541cm_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
564static int
565cm_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
576static int
577cm_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
600static int
601cm_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
631int
632cm_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