xref: /dragonfly/usr.sbin/rtadvd/control_server.c (revision 8d391e2802fe0d87afae295f319d057f74d181dd)
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: stable/10/usr.sbin/rtadvd/control_server.c 225519 2011-09-12 23:52:55Z hrs $
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 
59 static char *do_reload_ifname;
60 static int do_reload;
61 static int do_shutdown;
62 
set_do_reload(int sig __unused)63 void set_do_reload(int sig __unused)    { do_reload = 1; }
set_do_reload_ifname(char * ifname)64 void set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
set_do_shutdown(int sig __unused)65 void set_do_shutdown(int sig __unused)  { do_shutdown = 1; }
reset_do_reload(void)66 void reset_do_reload(void)    { do_reload = 0; do_reload_ifname = NULL; }
reset_do_shutdown(void)67 void reset_do_shutdown(void)  { do_shutdown = 0; }
is_do_reload(void)68 int is_do_reload(void)                  { return (do_reload); }
is_do_shutdown(void)69 int is_do_shutdown(void)      { return (do_shutdown); }
reload_ifname(void)70 char *reload_ifname(void)     { return (do_reload_ifname); }
71 
72 #define   DEF_PL_HANDLER(key) { #key, cm_getprop_##key }
73 
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 *);
84 
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 *);
88 
89 static 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 
106 static int
cm_getprop_echo(struct ctrl_msg_pl * cp)107 cm_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 
117 static int
cm_getprop_version(struct ctrl_msg_pl * cp)118 cm_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 
128 static int
cm_getprop_ifilist(struct ctrl_msg_pl * cp)129 cm_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 
162 static int
cm_getprop_ifi(struct ctrl_msg_pl * cp)163 cm_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 
197 static int
cm_getprop_rai(struct ctrl_msg_pl * cp)198 cm_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 
238 static int
cm_getprop_ifi_ra_timer(struct ctrl_msg_pl * cp)239 cm_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 
284 static int
cm_getprop_rti(struct ctrl_msg_pl * cp)285 cm_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 
333 static int
cm_getprop_pfx(struct ctrl_msg_pl * cp)334 cm_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 
382 static int
cm_getprop_rdnss(struct ctrl_msg_pl * cp)383 cm_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 
451 static int
cm_getprop_dnssl(struct ctrl_msg_pl * cp)452 cm_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 
519 int
cm_getprop(struct ctrl_msg_pl * cp)520 cm_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 
538 int
cm_setprop(struct ctrl_msg_pl * cp)539 cm_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 
562 static int
cm_setprop_reload(struct ctrl_msg_pl * cp)563 cm_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 
574 static int
cm_setprop_enable(struct ctrl_msg_pl * cp)575 cm_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 
598 static int
cm_setprop_disable(struct ctrl_msg_pl * cp)599 cm_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 
629 int
cm_handler_server(int fd)630 cm_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                                         /* FALLTHROUGH */
708                               case CM_TYPE_NUL:
709                                         cm->cm_type = CM_TYPE_ACK;
710                                         cm->cm_len = sizeof(*cm);
711                                         break;
712                               case CM_TYPE_REQ_GET_PROP:
713                                         cm_bin2pl(msg, &cp);
714                                         error = cm_getprop(&cp);
715                                         if (error) {
716                                                   cm->cm_type = CM_TYPE_ERR;
717                                                   cm->cm_len = sizeof(*cm);
718                                         } else {
719                                                   cm->cm_type = CM_TYPE_ACK;
720                                                   cm->cm_len = sizeof(*cm);
721                                                   cm->cm_len += cm_pl2bin(msg, &cp);
722                                         }
723                                         if (cp.cp_val != NULL)
724                                                   free(cp.cp_val);
725                                         break;
726                               case CM_TYPE_REQ_SET_PROP:
727                                         cm_bin2pl(msg, &cp);
728                                         error = cm_setprop(&cp);
729                                         if (error) {
730                                                   cm->cm_type = CM_TYPE_ERR;
731                                                   cm->cm_len = sizeof(*cm);
732                                         } else {
733                                                   cm->cm_type = CM_TYPE_ACK;
734                                                   cm->cm_len = sizeof(*cm);
735                                         }
736                                         break;
737                               default:
738                                         cm->cm_type = CM_TYPE_ERR;
739                                         cm->cm_len = sizeof(*cm);
740                               }
741 
742                               switch (cm->cm_type) {
743                               case CM_TYPE_ERR:
744                               case CM_TYPE_ACK:
745                                         state = CM_STATE_MSG_DISPATCH;
746                                         break;
747                               }
748                     }
749           }
750           syslog(LOG_DEBUG, "<%s> leave", __func__);
751 
752           return (0);
753 }
754