control_server.c revision 224144
1224006Shrs/*-
2224006Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3224006Shrs * All rights reserved.
4224006Shrs *
5224006Shrs * Redistribution and use in source and binary forms, with or without
6224006Shrs * modification, are permitted provided that the following conditions
7224006Shrs * are met:
8224006Shrs * 1. Redistributions of source code must retain the above copyright
9224006Shrs *    notice, this list of conditions and the following disclaimer.
10224006Shrs * 2. Redistributions in binary form must reproduce the above copyright
11224006Shrs *    notice, this list of conditions and the following disclaimer in the
12224006Shrs *    documentation and/or other materials provided with the distribution.
13224006Shrs *
14224006Shrs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15224006Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16224006Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17224006Shrs * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18224006Shrs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19224006Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20224006Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21224006Shrs * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22224006Shrs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23224006Shrs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24224006Shrs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25224006Shrs *
26224006Shrs * $FreeBSD: head/usr.sbin/rtadvd/control_server.c 224144 2011-07-17 19:24:54Z hrs $
27224006Shrs *
28224006Shrs */
29224006Shrs
30224006Shrs#include <sys/queue.h>
31224006Shrs#include <sys/types.h>
32224006Shrs#include <sys/socket.h>
33224006Shrs#include <sys/stat.h>
34224006Shrs#include <sys/un.h>
35224006Shrs#include <sys/uio.h>
36224006Shrs#include <net/if.h>
37224006Shrs#include <net/if_dl.h>
38224006Shrs#include <netinet/in.h>
39224006Shrs#include <netinet/icmp6.h>
40224006Shrs#include <fcntl.h>
41224006Shrs#include <errno.h>
42224006Shrs#include <netdb.h>
43224006Shrs#include <unistd.h>
44224006Shrs#include <signal.h>
45224006Shrs#include <string.h>
46224006Shrs#include <stdarg.h>
47224006Shrs#include <stdio.h>
48224006Shrs#include <stdlib.h>
49224006Shrs#include <syslog.h>
50224006Shrs
51224006Shrs#include "pathnames.h"
52224006Shrs#include "rtadvd.h"
53224006Shrs#include "if.h"
54224006Shrs#include "control.h"
55224006Shrs#include "control_server.h"
56224006Shrs#include "timer.h"
57224006Shrs
58224144Shrsstatic char *do_reload_ifname;
59224144Shrsstatic int do_reload;
60224144Shrsstatic int do_shutdown;
61224006Shrs
62224144Shrsvoid set_do_reload(int sig __unused)	{ do_reload = 1; }
63224144Shrsvoid set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
64224144Shrsvoid set_do_shutdown(int sig __unused)	{ do_shutdown = 1; }
65224144Shrsvoid reset_do_reload(void)	{ do_reload = 0; do_reload_ifname = NULL; }
66224144Shrsvoid reset_do_shutdown(void)	{ do_shutdown = 0; }
67224144Shrsint is_do_reload(void)		{ return (do_reload); }
68224144Shrsint is_do_shutdown(void)	{ return (do_shutdown); }
69224144Shrschar *reload_ifname(void)	{ return (do_reload_ifname); }
70224006Shrs
71224006Shrs#define	DEF_PL_HANDLER(key)	{ #key, cmsg_getprop_##key }
72224006Shrs
73224006Shrsstatic int cmsg_getprop_echo(struct ctrl_msg_pl *);
74224006Shrsstatic int cmsg_getprop_version(struct ctrl_msg_pl *);
75224006Shrsstatic int cmsg_getprop_ifilist(struct ctrl_msg_pl *);
76224006Shrsstatic int cmsg_getprop_ifi(struct ctrl_msg_pl *);
77224144Shrsstatic int cmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
78224006Shrsstatic int cmsg_getprop_rai(struct ctrl_msg_pl *);
79224006Shrsstatic int cmsg_getprop_pfx(struct ctrl_msg_pl *);
80224006Shrsstatic int cmsg_getprop_rdnss(struct ctrl_msg_pl *);
81224006Shrsstatic int cmsg_getprop_dnssl(struct ctrl_msg_pl *);
82224006Shrsstatic int cmsg_getprop_rti(struct ctrl_msg_pl *);
83224006Shrs
84224144Shrsstatic int cmsg_setprop_reload(struct ctrl_msg_pl *);
85224144Shrsstatic int cmsg_setprop_enable(struct ctrl_msg_pl *);
86224144Shrsstatic int cmsg_setprop_disable(struct ctrl_msg_pl *);
87224144Shrs
88224006Shrsstatic struct dispatch_table {
89224006Shrs	const char	*dt_comm;
90224006Shrs	int		(*dt_act)(struct ctrl_msg_pl *cp);
91224006Shrs} getprop_dtable[] = {
92224006Shrs	{ "",	cmsg_getprop_echo },
93224006Shrs	DEF_PL_HANDLER(echo),
94224006Shrs	DEF_PL_HANDLER(version),
95224006Shrs	DEF_PL_HANDLER(ifilist),
96224006Shrs	DEF_PL_HANDLER(ifi),
97224144Shrs	DEF_PL_HANDLER(ifi_ra_timer),
98224006Shrs	DEF_PL_HANDLER(rai),
99224006Shrs	DEF_PL_HANDLER(rti),
100224006Shrs	DEF_PL_HANDLER(pfx),
101224006Shrs	DEF_PL_HANDLER(rdnss),
102224006Shrs	DEF_PL_HANDLER(dnssl),
103224006Shrs};
104224006Shrs
105224006Shrsstatic int
106224006Shrscmsg_getprop_echo(struct ctrl_msg_pl *cp)
107224006Shrs{
108224006Shrs
109224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
110224006Shrs	cp->cp_val = strdup("");
111224006Shrs	cp->cp_val_len = strlen(cp->cp_val) + 1;
112224006Shrs
113224006Shrs	return (0);
114224006Shrs}
115224006Shrs
116224006Shrsstatic int
117224006Shrscmsg_getprop_version(struct ctrl_msg_pl *cp)
118224006Shrs{
119224006Shrs
120224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
121224006Shrs	cp->cp_val = strdup(CM_VERSION_STR);
122224006Shrs	cp->cp_val_len = strlen(cp->cp_val) + 1;
123224006Shrs
124224006Shrs	return (0);
125224006Shrs}
126224006Shrs
127224006Shrsstatic int
128224006Shrscmsg_getprop_ifilist(struct ctrl_msg_pl *cp)
129224006Shrs{
130224006Shrs	struct ifinfo *ifi;
131224006Shrs	char *p;
132224006Shrs	size_t len;
133224006Shrs
134224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
135224006Shrs
136224006Shrs	len = 0;
137224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
138224006Shrs		len += strlen(ifi->ifi_ifname) + 1;
139224006Shrs	}
140224006Shrs
141224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
142224006Shrs
143224006Shrs	p = malloc(len);
144224006Shrs	if (p == NULL)
145224006Shrs		exit(1);
146224006Shrs	memset(p, 0, len);
147224006Shrs	cp->cp_val = p;
148224006Shrs
149224006Shrs	if (len > 0)
150224006Shrs		TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
151224006Shrs			syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
152224006Shrs			    __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
153224006Shrs			strcpy(p, ifi->ifi_ifname);
154224006Shrs			p += strlen(ifi->ifi_ifname) + 1;
155224006Shrs		}
156224006Shrs	cp->cp_val_len = p - cp->cp_val;
157224006Shrs
158224006Shrs	return (0);
159224006Shrs}
160224006Shrs
161224006Shrsstatic int
162224006Shrscmsg_getprop_ifi(struct ctrl_msg_pl *cp)
163224006Shrs{
164224006Shrs	struct ifinfo *ifi;
165224006Shrs	char *p;
166224006Shrs	size_t len;
167224006Shrs
168224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
169224006Shrs
170224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
171224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
172224006Shrs			break;
173224006Shrs	}
174224006Shrs	if (ifi == NULL) {
175224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
176224006Shrs		    cp->cp_ifname);
177224006Shrs		return (1);
178224006Shrs	}
179224006Shrs
180224006Shrs	p = malloc(sizeof(*ifi));
181224006Shrs	if (p == NULL)
182224006Shrs		exit(1);
183224006Shrs	len = cmsg_str2bin(p, ifi, sizeof(*ifi));
184224006Shrs
185224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
186224006Shrs
187224006Shrs	if (len == 0)
188224006Shrs		return (1);
189224006Shrs
190224006Shrs	cp->cp_val = p;
191224006Shrs	cp->cp_val_len = len;
192224006Shrs
193224006Shrs	return (0);
194224006Shrs}
195224006Shrs
196224006Shrsstatic int
197224006Shrscmsg_getprop_rai(struct ctrl_msg_pl *cp)
198224006Shrs{
199224006Shrs	struct ifinfo *ifi;
200224006Shrs	struct rainfo *rai;
201224006Shrs	char *p;
202224006Shrs	size_t len;
203224006Shrs
204224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
205224006Shrs
206224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
207224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
208224006Shrs			break;
209224006Shrs	}
210224006Shrs	if (ifi == NULL) {
211224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
212224006Shrs		    cp->cp_ifname);
213224006Shrs		return (1);
214224006Shrs	}
215224006Shrs	if ((rai = ifi->ifi_rainfo) == NULL) {
216224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
217224006Shrs		    cp->cp_ifname);
218224006Shrs		return (1);
219224006Shrs	}
220224006Shrs
221224006Shrs	p = malloc(sizeof(*rai));
222224006Shrs	if (p == NULL)
223224006Shrs		exit(1);
224224006Shrs	len = cmsg_str2bin(p, rai, sizeof(*rai));
225224006Shrs
226224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
227224006Shrs
228224006Shrs	if (len == 0)
229224006Shrs		return (1);
230224006Shrs
231224006Shrs	cp->cp_val = p;
232224006Shrs	cp->cp_val_len = len;
233224006Shrs
234224006Shrs	return (0);
235224006Shrs}
236224006Shrs
237224006Shrsstatic int
238224144Shrscmsg_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
239224006Shrs{
240224006Shrs	struct ifinfo *ifi;
241224006Shrs	struct rainfo *rai;
242224006Shrs	struct rtadvd_timer	*rtimer;
243224006Shrs	char *p;
244224006Shrs	size_t len;
245224006Shrs
246224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
247224006Shrs
248224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
249224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
250224006Shrs			break;
251224006Shrs	}
252224006Shrs	if (ifi == NULL) {
253224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
254224006Shrs		    cp->cp_ifname);
255224006Shrs		return (1);
256224006Shrs	}
257224006Shrs	if ((rai = ifi->ifi_rainfo) == NULL) {
258224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
259224006Shrs		    cp->cp_ifname);
260224006Shrs		return (1);
261224006Shrs	}
262224144Shrs	if ((rtimer = ifi->ifi_ra_timer) == NULL) {
263224144Shrs		syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
264224006Shrs		    cp->cp_ifname);
265224006Shrs		return (1);
266224006Shrs	}
267224006Shrs	p = malloc(sizeof(*rtimer));
268224006Shrs	if (p == NULL)
269224006Shrs		exit(1);
270224006Shrs	len = cmsg_str2bin(p, rtimer, sizeof(*rtimer));
271224006Shrs
272224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
273224006Shrs
274224006Shrs	if (len == 0)
275224006Shrs		return (1);
276224006Shrs
277224006Shrs	cp->cp_val = p;
278224006Shrs	cp->cp_val_len = len;
279224006Shrs
280224006Shrs	return (0);
281224006Shrs}
282224006Shrs
283224006Shrsstatic int
284224006Shrscmsg_getprop_rti(struct ctrl_msg_pl *cp)
285224006Shrs{
286224006Shrs	struct ifinfo *ifi;
287224006Shrs	struct rainfo *rai;
288224006Shrs	struct rtinfo *rti;
289224006Shrs	char *p;
290224006Shrs	size_t len;
291224006Shrs
292224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
293224006Shrs
294224006Shrs	len = 0;
295224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
296224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
297224006Shrs			break;
298224006Shrs	}
299224006Shrs	if (ifi == NULL) {
300224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
301224006Shrs		    cp->cp_ifname);
302224006Shrs		return (1);
303224006Shrs	}
304224006Shrs	if (ifi->ifi_rainfo == NULL) {
305224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
306224006Shrs		    cp->cp_ifname);
307224006Shrs		return (1);
308224006Shrs	}
309224006Shrs	rai = ifi->ifi_rainfo;
310224006Shrs	TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
311224006Shrs		len += sizeof(*rti);
312224006Shrs	}
313224006Shrs
314224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
315224006Shrs
316224006Shrs	p = malloc(len);
317224006Shrs	if (p == NULL)
318224006Shrs		exit(1);
319224006Shrs	memset(p, 0, len);
320224006Shrs	cp->cp_val = p;
321224006Shrs
322224006Shrs	if (len > 0)
323224006Shrs		TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
324224006Shrs			memcpy(p, rti, sizeof(*rti));
325224006Shrs			p += sizeof(*rti);
326224006Shrs		}
327224006Shrs	cp->cp_val_len = p - cp->cp_val;
328224006Shrs
329224006Shrs	return (0);
330224006Shrs}
331224006Shrs
332224006Shrsstatic int
333224006Shrscmsg_getprop_pfx(struct ctrl_msg_pl *cp)
334224006Shrs{
335224006Shrs	struct ifinfo *ifi;
336224006Shrs	struct rainfo *rai;
337224006Shrs	struct prefix *pfx;
338224006Shrs	char *p;
339224006Shrs	size_t len;
340224006Shrs
341224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
342224006Shrs
343224006Shrs	len = 0;
344224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
345224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
346224006Shrs			break;
347224006Shrs	}
348224006Shrs	if (ifi == NULL) {
349224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
350224006Shrs		    cp->cp_ifname);
351224006Shrs		return (1);
352224006Shrs	}
353224006Shrs	if (ifi->ifi_rainfo == NULL) {
354224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
355224006Shrs		    cp->cp_ifname);
356224006Shrs		return (1);
357224006Shrs	}
358224006Shrs	rai = ifi->ifi_rainfo;
359224006Shrs	TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
360224006Shrs		len += sizeof(*pfx);
361224006Shrs	}
362224006Shrs
363224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
364224006Shrs
365224006Shrs	p = malloc(len);
366224006Shrs	if (p == NULL)
367224006Shrs		exit(1);
368224006Shrs	memset(p, 0, len);
369224006Shrs	cp->cp_val = p;
370224006Shrs
371224006Shrs	if (len > 0)
372224006Shrs		TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
373224006Shrs			memcpy(p, pfx, sizeof(*pfx));
374224006Shrs			p += sizeof(*pfx);
375224006Shrs		}
376224006Shrs	cp->cp_val_len = p - cp->cp_val;
377224006Shrs
378224006Shrs	return (0);
379224006Shrs}
380224006Shrs
381224006Shrsstatic int
382224006Shrscmsg_getprop_rdnss(struct ctrl_msg_pl *cp)
383224006Shrs{
384224006Shrs	struct ifinfo *ifi;
385224006Shrs	struct rainfo *rai;
386224006Shrs	struct rdnss *rdn;
387224006Shrs	struct rdnss_addr *rda;
388224006Shrs	char *p;
389224006Shrs	size_t len;
390224144Shrs	uint16_t *rdn_cnt;
391224144Shrs	uint16_t *rda_cnt;
392224006Shrs
393224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
394224006Shrs
395224006Shrs	len = 0;
396224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
397224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
398224006Shrs			break;
399224006Shrs	}
400224006Shrs	if (ifi == NULL) {
401224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
402224006Shrs		    cp->cp_ifname);
403224006Shrs		return (1);
404224006Shrs	}
405224006Shrs	if (ifi->ifi_rainfo == NULL) {
406224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
407224006Shrs		    cp->cp_ifname);
408224006Shrs		return (1);
409224006Shrs	}
410224006Shrs	rai = ifi->ifi_rainfo;
411224006Shrs
412224006Shrs	len = sizeof(*rdn_cnt);
413224006Shrs	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
414224006Shrs		len += sizeof(*rdn);
415224006Shrs		len += sizeof(*rda_cnt);
416224006Shrs		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
417224006Shrs			len += sizeof(*rda);
418224006Shrs		}
419224006Shrs	}
420224006Shrs
421224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
422224006Shrs
423224006Shrs	p = malloc(len);
424224006Shrs	if (p == NULL)
425224006Shrs		exit(1);
426224006Shrs	memset(p, 0, len);
427224006Shrs	cp->cp_val = p;
428224006Shrs
429224144Shrs	rdn_cnt = (uint16_t *)p;
430224006Shrs	p += sizeof(*rdn_cnt);
431224006Shrs	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
432224006Shrs		*rdn_cnt += 1;
433224006Shrs		memcpy(p, rdn, sizeof(*rdn));
434224006Shrs		p += sizeof(*rdn);
435224006Shrs
436224144Shrs		rda_cnt = (uint16_t *)p;
437224006Shrs		p += sizeof(*rda_cnt);
438224006Shrs		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
439224006Shrs			*rda_cnt += 1;
440224006Shrs			memcpy(p, rda, sizeof(*rda));
441224006Shrs			p += sizeof(*rda);
442224006Shrs		}
443224006Shrs	}
444224006Shrs	syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
445224006Shrs	cp->cp_val_len = p - cp->cp_val;
446224006Shrs
447224006Shrs	return (0);
448224006Shrs}
449224006Shrs
450224006Shrsstatic int
451224006Shrscmsg_getprop_dnssl(struct ctrl_msg_pl *cp)
452224006Shrs{
453224006Shrs	struct ifinfo *ifi;
454224006Shrs	struct rainfo *rai;
455224006Shrs	struct dnssl *dns;
456224006Shrs	struct dnssl_addr *dna;
457224006Shrs	char *p;
458224006Shrs	size_t len;
459224144Shrs	uint16_t *dns_cnt;
460224144Shrs	uint16_t *dna_cnt;
461224006Shrs
462224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
463224006Shrs
464224006Shrs	len = 0;
465224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
466224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
467224006Shrs			break;
468224006Shrs	}
469224006Shrs	if (ifi == NULL) {
470224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
471224006Shrs		    cp->cp_ifname);
472224006Shrs		return (1);
473224006Shrs	}
474224006Shrs	if (ifi->ifi_rainfo == NULL) {
475224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
476224006Shrs		    cp->cp_ifname);
477224006Shrs		return (1);
478224006Shrs	}
479224006Shrs	rai = ifi->ifi_rainfo;
480224006Shrs
481224006Shrs	len = sizeof(*dns_cnt);
482224006Shrs	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
483224006Shrs		len += sizeof(*dns);
484224006Shrs		len += sizeof(*dna_cnt);
485224006Shrs		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
486224006Shrs			len += sizeof(*dna);
487224006Shrs		}
488224006Shrs	}
489224006Shrs
490224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
491224006Shrs
492224006Shrs	p = malloc(len);
493224006Shrs	if (p == NULL)
494224006Shrs		exit(1);
495224006Shrs	memset(p, 0, len);
496224006Shrs	cp->cp_val = p;
497224006Shrs
498224144Shrs	dns_cnt = (uint16_t *)cp->cp_val;
499224006Shrs	p += sizeof(*dns_cnt);
500224006Shrs	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
501224006Shrs		(*dns_cnt)++;
502224006Shrs		memcpy(p, dns, sizeof(*dns));
503224006Shrs		p += sizeof(*dns);
504224006Shrs
505224144Shrs		dna_cnt = (uint16_t *)p;
506224006Shrs		p += sizeof(*dna_cnt);
507224006Shrs		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
508224006Shrs			(*dna_cnt)++;
509224006Shrs			memcpy(p, dna, sizeof(*dna));
510224006Shrs			p += sizeof(*dna);
511224006Shrs		}
512224006Shrs	}
513224006Shrs	cp->cp_val_len = p - cp->cp_val;
514224006Shrs
515224006Shrs	return (0);
516224006Shrs}
517224006Shrs
518224006Shrsint
519224006Shrscmsg_getprop(struct ctrl_msg_pl *cp)
520224006Shrs{
521224006Shrs	size_t i;
522224006Shrs
523224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
524224006Shrs
525224006Shrs	if (cp == NULL)
526224006Shrs		return (1);
527224006Shrs
528224006Shrs	for (i = 0;
529224006Shrs	     i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
530224006Shrs	     i++) {
531224006Shrs		if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
532224006Shrs			return (getprop_dtable[i].dt_act(cp));
533224006Shrs	}
534224006Shrs	return (1);
535224006Shrs}
536224006Shrs
537224006Shrsint
538224006Shrscmsg_setprop(struct ctrl_msg_pl *cp)
539224006Shrs{
540224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
541224006Shrs
542224006Shrs	if (cp == NULL || cp->cp_key == NULL)
543224006Shrs		return (1);
544224006Shrs
545224144Shrs	if (strncmp(cp->cp_key, "reload", sizeof("reload")) == 0)
546224144Shrs		cmsg_setprop_reload(cp);
547224144Shrs	else if (strncmp(cp->cp_key, "shutdown", sizeof("shutdown")) == 0)
548224144Shrs		set_do_shutdown(0);
549224144Shrs	else if (strncmp(cp->cp_key, "enable", sizeof("enable")) == 0)
550224144Shrs		cmsg_setprop_enable(cp);
551224144Shrs	else if (strncmp(cp->cp_key, "disable", sizeof("disable")) == 0)
552224144Shrs		cmsg_setprop_disable(cp);
553224006Shrs	else if (strncmp(cp->cp_key, "echo", 8) == 0)
554224006Shrs		; 		/* do nothing */
555224006Shrs	else
556224006Shrs		return (1);
557224006Shrs
558224006Shrs	return (0);
559224006Shrs}
560224006Shrs
561224144Shrsstatic int
562224144Shrscmsg_setprop_reload(struct ctrl_msg_pl *cp)
563224144Shrs{
564224144Shrs
565224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
566224144Shrs
567224144Shrs	set_do_reload_ifname(cp->cp_ifname);
568224144Shrs	set_do_reload(1);
569224144Shrs
570224144Shrs	return (0);
571224144Shrs}
572224144Shrs
573224144Shrsstatic int
574224144Shrscmsg_setprop_enable(struct ctrl_msg_pl *cp)
575224144Shrs{
576224144Shrs	struct ifinfo *ifi;
577224144Shrs
578224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
579224144Shrs
580224144Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
581224144Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
582224144Shrs			break;
583224144Shrs	}
584224144Shrs	if (ifi == NULL) {
585224144Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
586224144Shrs		    cp->cp_ifname);
587224144Shrs		return (1);
588224144Shrs	}
589224144Shrs
590224144Shrs	ifi->ifi_persist = 1;
591224144Shrs	set_do_reload_ifname(ifi->ifi_ifname);
592224144Shrs	set_do_reload(0);
593224144Shrs
594224144Shrs	return (0);
595224144Shrs}
596224144Shrs
597224144Shrsstatic int
598224144Shrscmsg_setprop_disable(struct ctrl_msg_pl *cp)
599224144Shrs{
600224144Shrs	struct ifinfo *ifi;
601224144Shrs
602224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
603224144Shrs
604224144Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
605224144Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
606224144Shrs			break;
607224144Shrs	}
608224144Shrs	if (ifi == NULL) {
609224144Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
610224144Shrs		    cp->cp_ifname);
611224144Shrs		return (1);
612224144Shrs	}
613224144Shrs
614224144Shrs	ifi->ifi_persist = 0;
615224144Shrs
616224144Shrs	return (0);
617224144Shrs}
618224144Shrs
619224006Shrsint
620224006Shrscmsg_handler_server(int fd)
621224006Shrs{
622224006Shrs	int state;
623224006Shrs	char *msg;
624224006Shrs	struct ctrl_msg_hdr *cm;
625224006Shrs	struct ctrl_msg_pl cp;
626224006Shrs	char buf[CM_MSG_MAXLEN];
627224006Shrs	char pbuf[CM_MSG_MAXLEN];
628224006Shrs	int error;
629224006Shrs
630224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
631224006Shrs
632224006Shrs	memset(buf, 0, sizeof(buf));
633224006Shrs	memset(pbuf, 0, sizeof(pbuf));
634224006Shrs	cm = (struct ctrl_msg_hdr *)buf;
635224006Shrs	msg = (char *)buf + sizeof(*cm);
636224006Shrs
637224006Shrs	state = CM_STATE_INIT;
638224006Shrs	while (state != CM_STATE_EOM) {
639224006Shrs		syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
640224006Shrs
641224006Shrs		switch (state) {
642224006Shrs		case CM_STATE_INIT:
643224006Shrs			state = CM_STATE_MSG_RECV;
644224006Shrs			break;
645224006Shrs		case CM_STATE_MSG_DISPATCH:
646224006Shrs			cm->cm_version = CM_VERSION;
647224006Shrs			error = cmsg_send(fd, buf);
648224006Shrs			if (error)
649224006Shrs				syslog(LOG_WARNING,
650224006Shrs				    "<%s> cmsg_send()", __func__);
651224006Shrs			state = CM_STATE_EOM;
652224006Shrs			break;
653224006Shrs		case CM_STATE_ACK_WAIT:
654224006Shrs			error = cmsg_recv(fd, buf);
655224006Shrs			if (error) {
656224006Shrs				syslog(LOG_ERR,
657224006Shrs				    "<%s> cmsg_recv()", __func__);
658224006Shrs				close(fd);
659224006Shrs				return (-1);
660224006Shrs			}
661224006Shrs
662224006Shrs			switch (cm->cm_type) {
663224006Shrs			case CM_TYPE_ACK:
664224006Shrs				break;
665224006Shrs			case CM_TYPE_ERR:
666224006Shrs				syslog(LOG_DEBUG,
667224006Shrs				    "<%s> CM_TYPE_ERR", __func__);
668224006Shrs				close(fd);
669224006Shrs				return (-1);
670224006Shrs			default:
671224006Shrs				syslog(LOG_DEBUG,
672224006Shrs				    "<%s> unknown status", __func__);
673224006Shrs				close(fd);
674224006Shrs				return (-1);
675224006Shrs			}
676224006Shrs			state = CM_STATE_EOM;
677224006Shrs			break;
678224006Shrs		case CM_STATE_MSG_RECV:
679224006Shrs			error = cmsg_recv(fd, buf);
680224006Shrs
681224006Shrs			if (error) {
682224006Shrs				syslog(LOG_ERR,
683224006Shrs				    "<%s> cmsg_recv()", __func__);
684224006Shrs				close(fd);
685224006Shrs				return (-1);
686224006Shrs			}
687224006Shrs			memset(&cp, 0, sizeof(cp));
688224006Shrs
689224006Shrs			syslog(LOG_DEBUG,
690224006Shrs			    "<%s> cm->cm_type = %d", __func__, cm->cm_type);
691224006Shrs			syslog(LOG_DEBUG,
692224144Shrs			    "<%s> cm->cm_len = %zu", __func__, cm->cm_len);
693224006Shrs
694224006Shrs			switch (cm->cm_type) {
695224006Shrs			case CM_TYPE_EOM:
696224006Shrs				state = CM_STATE_EOM;
697224006Shrs			case CM_TYPE_NUL:
698224006Shrs				cm->cm_type = CM_TYPE_ACK;
699224006Shrs				cm->cm_len = sizeof(*cm);
700224006Shrs				break;
701224006Shrs			case CM_TYPE_REQ_GET_PROP:
702224006Shrs				cmsg_bin2pl(msg, &cp);
703224006Shrs				error = cmsg_getprop(&cp);
704224006Shrs				if (error) {
705224006Shrs					cm->cm_type = CM_TYPE_ERR;
706224006Shrs					cm->cm_len = sizeof(*cm);
707224006Shrs				} else {
708224006Shrs					cm->cm_type = CM_TYPE_ACK;
709224006Shrs					cm->cm_len = sizeof(*cm);
710224006Shrs					cm->cm_len += cmsg_pl2bin(msg, &cp);
711224006Shrs				}
712224144Shrs				if (cp.cp_val != NULL)
713224144Shrs					free(cp.cp_val);
714224006Shrs				break;
715224006Shrs			case CM_TYPE_REQ_SET_PROP:
716224006Shrs				cmsg_bin2pl(msg, &cp);
717224006Shrs				error = cmsg_setprop(&cp);
718224006Shrs				if (error) {
719224006Shrs					cm->cm_type = CM_TYPE_ERR;
720224006Shrs					cm->cm_len = sizeof(*cm);
721224006Shrs				} else {
722224006Shrs					cm->cm_type = CM_TYPE_ACK;
723224006Shrs					cm->cm_len = sizeof(*cm);
724224006Shrs				}
725224006Shrs				break;
726224006Shrs			default:
727224006Shrs				cm->cm_type = CM_TYPE_ERR;
728224006Shrs				cm->cm_len = sizeof(*cm);
729224006Shrs			}
730224006Shrs
731224006Shrs			switch (cm->cm_type) {
732224006Shrs			case CM_TYPE_ERR:
733224006Shrs			case CM_TYPE_ACK:
734224006Shrs				state = CM_STATE_MSG_DISPATCH;
735224006Shrs				break;
736224006Shrs			}
737224006Shrs		}
738224006Shrs	}
739224006Shrs	syslog(LOG_DEBUG, "<%s> leave", __func__);
740224006Shrs
741224006Shrs	return (0);
742224006Shrs}
743