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$
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"
54225519Shrs#include "config.h"
55224006Shrs#include "control.h"
56224006Shrs#include "control_server.h"
57224006Shrs#include "timer.h"
58224006Shrs
59224144Shrsstatic char *do_reload_ifname;
60224144Shrsstatic int do_reload;
61224144Shrsstatic int do_shutdown;
62224006Shrs
63224144Shrsvoid set_do_reload(int sig __unused)	{ do_reload = 1; }
64224144Shrsvoid set_do_reload_ifname(char *ifname){ do_reload_ifname = ifname; }
65224144Shrsvoid set_do_shutdown(int sig __unused)	{ do_shutdown = 1; }
66224144Shrsvoid reset_do_reload(void)	{ do_reload = 0; do_reload_ifname = NULL; }
67224144Shrsvoid reset_do_shutdown(void)	{ do_shutdown = 0; }
68224144Shrsint is_do_reload(void)		{ return (do_reload); }
69224144Shrsint is_do_shutdown(void)	{ return (do_shutdown); }
70224144Shrschar *reload_ifname(void)	{ return (do_reload_ifname); }
71224006Shrs
72225519Shrs#define	DEF_PL_HANDLER(key)	{ #key, cm_getprop_##key }
73224006Shrs
74225519Shrsstatic int cm_getprop_echo(struct ctrl_msg_pl *);
75225519Shrsstatic int cm_getprop_version(struct ctrl_msg_pl *);
76225519Shrsstatic int cm_getprop_ifilist(struct ctrl_msg_pl *);
77225519Shrsstatic int cm_getprop_ifi(struct ctrl_msg_pl *);
78225519Shrsstatic int cm_getprop_ifi_ra_timer(struct ctrl_msg_pl *);
79225519Shrsstatic int cm_getprop_rai(struct ctrl_msg_pl *);
80225519Shrsstatic int cm_getprop_pfx(struct ctrl_msg_pl *);
81225519Shrsstatic int cm_getprop_rdnss(struct ctrl_msg_pl *);
82225519Shrsstatic int cm_getprop_dnssl(struct ctrl_msg_pl *);
83225519Shrsstatic int cm_getprop_rti(struct ctrl_msg_pl *);
84224006Shrs
85225519Shrsstatic int cm_setprop_reload(struct ctrl_msg_pl *);
86225519Shrsstatic int cm_setprop_enable(struct ctrl_msg_pl *);
87225519Shrsstatic int cm_setprop_disable(struct ctrl_msg_pl *);
88224144Shrs
89224006Shrsstatic struct dispatch_table {
90224006Shrs	const char	*dt_comm;
91224006Shrs	int		(*dt_act)(struct ctrl_msg_pl *cp);
92224006Shrs} getprop_dtable[] = {
93225519Shrs	{ "",	cm_getprop_echo },
94224006Shrs	DEF_PL_HANDLER(echo),
95224006Shrs	DEF_PL_HANDLER(version),
96224006Shrs	DEF_PL_HANDLER(ifilist),
97224006Shrs	DEF_PL_HANDLER(ifi),
98224144Shrs	DEF_PL_HANDLER(ifi_ra_timer),
99224006Shrs	DEF_PL_HANDLER(rai),
100224006Shrs	DEF_PL_HANDLER(rti),
101224006Shrs	DEF_PL_HANDLER(pfx),
102224006Shrs	DEF_PL_HANDLER(rdnss),
103224006Shrs	DEF_PL_HANDLER(dnssl),
104224006Shrs};
105224006Shrs
106224006Shrsstatic int
107225519Shrscm_getprop_echo(struct ctrl_msg_pl *cp)
108224006Shrs{
109224006Shrs
110224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
111224006Shrs	cp->cp_val = strdup("");
112224006Shrs	cp->cp_val_len = strlen(cp->cp_val) + 1;
113224006Shrs
114224006Shrs	return (0);
115224006Shrs}
116224006Shrs
117224006Shrsstatic int
118225519Shrscm_getprop_version(struct ctrl_msg_pl *cp)
119224006Shrs{
120224006Shrs
121224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
122224006Shrs	cp->cp_val = strdup(CM_VERSION_STR);
123224006Shrs	cp->cp_val_len = strlen(cp->cp_val) + 1;
124224006Shrs
125224006Shrs	return (0);
126224006Shrs}
127224006Shrs
128224006Shrsstatic int
129225519Shrscm_getprop_ifilist(struct ctrl_msg_pl *cp)
130224006Shrs{
131224006Shrs	struct ifinfo *ifi;
132224006Shrs	char *p;
133224006Shrs	size_t len;
134224006Shrs
135224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
136224006Shrs
137224006Shrs	len = 0;
138224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
139224006Shrs		len += strlen(ifi->ifi_ifname) + 1;
140224006Shrs	}
141224006Shrs
142224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
143224006Shrs
144224006Shrs	p = malloc(len);
145224006Shrs	if (p == NULL)
146224006Shrs		exit(1);
147224006Shrs	memset(p, 0, len);
148224006Shrs	cp->cp_val = p;
149224006Shrs
150224006Shrs	if (len > 0)
151224006Shrs		TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
152224006Shrs			syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
153224006Shrs			    __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
154224006Shrs			strcpy(p, ifi->ifi_ifname);
155224006Shrs			p += strlen(ifi->ifi_ifname) + 1;
156224006Shrs		}
157224006Shrs	cp->cp_val_len = p - cp->cp_val;
158224006Shrs
159224006Shrs	return (0);
160224006Shrs}
161224006Shrs
162224006Shrsstatic int
163225519Shrscm_getprop_ifi(struct ctrl_msg_pl *cp)
164224006Shrs{
165224006Shrs	struct ifinfo *ifi;
166224006Shrs	char *p;
167224006Shrs	size_t len;
168224006Shrs
169224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
170224006Shrs
171224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
172224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
173224006Shrs			break;
174224006Shrs	}
175224006Shrs	if (ifi == NULL) {
176224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
177224006Shrs		    cp->cp_ifname);
178224006Shrs		return (1);
179224006Shrs	}
180224006Shrs
181224006Shrs	p = malloc(sizeof(*ifi));
182224006Shrs	if (p == NULL)
183224006Shrs		exit(1);
184225519Shrs	len = cm_str2bin(p, ifi, sizeof(*ifi));
185224006Shrs
186224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
187224006Shrs
188224006Shrs	if (len == 0)
189224006Shrs		return (1);
190224006Shrs
191224006Shrs	cp->cp_val = p;
192224006Shrs	cp->cp_val_len = len;
193224006Shrs
194224006Shrs	return (0);
195224006Shrs}
196224006Shrs
197224006Shrsstatic int
198225519Shrscm_getprop_rai(struct ctrl_msg_pl *cp)
199224006Shrs{
200224006Shrs	struct ifinfo *ifi;
201224006Shrs	struct rainfo *rai;
202224006Shrs	char *p;
203224006Shrs	size_t len;
204224006Shrs
205224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
206224006Shrs
207224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
208224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
209224006Shrs			break;
210224006Shrs	}
211224006Shrs	if (ifi == NULL) {
212224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
213224006Shrs		    cp->cp_ifname);
214224006Shrs		return (1);
215224006Shrs	}
216224006Shrs	if ((rai = ifi->ifi_rainfo) == NULL) {
217224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
218224006Shrs		    cp->cp_ifname);
219224006Shrs		return (1);
220224006Shrs	}
221224006Shrs
222224006Shrs	p = malloc(sizeof(*rai));
223224006Shrs	if (p == NULL)
224224006Shrs		exit(1);
225225519Shrs	len = cm_str2bin(p, rai, sizeof(*rai));
226224006Shrs
227224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
228224006Shrs
229224006Shrs	if (len == 0)
230224006Shrs		return (1);
231224006Shrs
232224006Shrs	cp->cp_val = p;
233224006Shrs	cp->cp_val_len = len;
234224006Shrs
235224006Shrs	return (0);
236224006Shrs}
237224006Shrs
238224006Shrsstatic int
239225519Shrscm_getprop_ifi_ra_timer(struct ctrl_msg_pl *cp)
240224006Shrs{
241224006Shrs	struct ifinfo *ifi;
242224006Shrs	struct rainfo *rai;
243224006Shrs	struct rtadvd_timer	*rtimer;
244224006Shrs	char *p;
245224006Shrs	size_t len;
246224006Shrs
247224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
248224006Shrs
249224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
250224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
251224006Shrs			break;
252224006Shrs	}
253224006Shrs	if (ifi == NULL) {
254224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
255224006Shrs		    cp->cp_ifname);
256224006Shrs		return (1);
257224006Shrs	}
258224006Shrs	if ((rai = ifi->ifi_rainfo) == NULL) {
259224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
260224006Shrs		    cp->cp_ifname);
261224006Shrs		return (1);
262224006Shrs	}
263224144Shrs	if ((rtimer = ifi->ifi_ra_timer) == NULL) {
264224144Shrs		syslog(LOG_ERR, "<%s> %s has no ifi_ra_timer", __func__,
265224006Shrs		    cp->cp_ifname);
266224006Shrs		return (1);
267224006Shrs	}
268224006Shrs	p = malloc(sizeof(*rtimer));
269224006Shrs	if (p == NULL)
270224006Shrs		exit(1);
271225519Shrs	len = cm_str2bin(p, rtimer, sizeof(*rtimer));
272224006Shrs
273224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
274224006Shrs
275224006Shrs	if (len == 0)
276224006Shrs		return (1);
277224006Shrs
278224006Shrs	cp->cp_val = p;
279224006Shrs	cp->cp_val_len = len;
280224006Shrs
281224006Shrs	return (0);
282224006Shrs}
283224006Shrs
284224006Shrsstatic int
285225519Shrscm_getprop_rti(struct ctrl_msg_pl *cp)
286224006Shrs{
287224006Shrs	struct ifinfo *ifi;
288224006Shrs	struct rainfo *rai;
289224006Shrs	struct rtinfo *rti;
290224006Shrs	char *p;
291224006Shrs	size_t len;
292224006Shrs
293224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
294224006Shrs
295224006Shrs	len = 0;
296224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
297224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
298224006Shrs			break;
299224006Shrs	}
300224006Shrs	if (ifi == NULL) {
301224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
302224006Shrs		    cp->cp_ifname);
303224006Shrs		return (1);
304224006Shrs	}
305224006Shrs	if (ifi->ifi_rainfo == NULL) {
306224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
307224006Shrs		    cp->cp_ifname);
308224006Shrs		return (1);
309224006Shrs	}
310224006Shrs	rai = ifi->ifi_rainfo;
311224006Shrs	TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
312224006Shrs		len += sizeof(*rti);
313224006Shrs	}
314224006Shrs
315224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
316224006Shrs
317224006Shrs	p = malloc(len);
318224006Shrs	if (p == NULL)
319224006Shrs		exit(1);
320224006Shrs	memset(p, 0, len);
321224006Shrs	cp->cp_val = p;
322224006Shrs
323224006Shrs	if (len > 0)
324224006Shrs		TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
325224006Shrs			memcpy(p, rti, sizeof(*rti));
326224006Shrs			p += sizeof(*rti);
327224006Shrs		}
328224006Shrs	cp->cp_val_len = p - cp->cp_val;
329224006Shrs
330224006Shrs	return (0);
331224006Shrs}
332224006Shrs
333224006Shrsstatic int
334225519Shrscm_getprop_pfx(struct ctrl_msg_pl *cp)
335224006Shrs{
336224006Shrs	struct ifinfo *ifi;
337224006Shrs	struct rainfo *rai;
338224006Shrs	struct prefix *pfx;
339224006Shrs	char *p;
340224006Shrs	size_t len;
341224006Shrs
342224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
343224006Shrs
344224006Shrs	len = 0;
345224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
346224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
347224006Shrs			break;
348224006Shrs	}
349224006Shrs	if (ifi == NULL) {
350224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
351224006Shrs		    cp->cp_ifname);
352224006Shrs		return (1);
353224006Shrs	}
354224006Shrs	if (ifi->ifi_rainfo == NULL) {
355224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
356224006Shrs		    cp->cp_ifname);
357224006Shrs		return (1);
358224006Shrs	}
359224006Shrs	rai = ifi->ifi_rainfo;
360224006Shrs	TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
361224006Shrs		len += sizeof(*pfx);
362224006Shrs	}
363224006Shrs
364224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
365224006Shrs
366224006Shrs	p = malloc(len);
367224006Shrs	if (p == NULL)
368224006Shrs		exit(1);
369224006Shrs	memset(p, 0, len);
370224006Shrs	cp->cp_val = p;
371224006Shrs
372224006Shrs	if (len > 0)
373224006Shrs		TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
374224006Shrs			memcpy(p, pfx, sizeof(*pfx));
375224006Shrs			p += sizeof(*pfx);
376224006Shrs		}
377224006Shrs	cp->cp_val_len = p - cp->cp_val;
378224006Shrs
379224006Shrs	return (0);
380224006Shrs}
381224006Shrs
382224006Shrsstatic int
383225519Shrscm_getprop_rdnss(struct ctrl_msg_pl *cp)
384224006Shrs{
385224006Shrs	struct ifinfo *ifi;
386224006Shrs	struct rainfo *rai;
387224006Shrs	struct rdnss *rdn;
388224006Shrs	struct rdnss_addr *rda;
389224006Shrs	char *p;
390224006Shrs	size_t len;
391224144Shrs	uint16_t *rdn_cnt;
392224144Shrs	uint16_t *rda_cnt;
393224006Shrs
394224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
395224006Shrs
396224006Shrs	len = 0;
397224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
398224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
399224006Shrs			break;
400224006Shrs	}
401224006Shrs	if (ifi == NULL) {
402224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
403224006Shrs		    cp->cp_ifname);
404224006Shrs		return (1);
405224006Shrs	}
406224006Shrs	if (ifi->ifi_rainfo == NULL) {
407224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
408224006Shrs		    cp->cp_ifname);
409224006Shrs		return (1);
410224006Shrs	}
411224006Shrs	rai = ifi->ifi_rainfo;
412224006Shrs
413224006Shrs	len = sizeof(*rdn_cnt);
414224006Shrs	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
415224006Shrs		len += sizeof(*rdn);
416224006Shrs		len += sizeof(*rda_cnt);
417224006Shrs		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
418224006Shrs			len += sizeof(*rda);
419224006Shrs		}
420224006Shrs	}
421224006Shrs
422224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
423224006Shrs
424224006Shrs	p = malloc(len);
425224006Shrs	if (p == NULL)
426224006Shrs		exit(1);
427224006Shrs	memset(p, 0, len);
428224006Shrs	cp->cp_val = p;
429224006Shrs
430224144Shrs	rdn_cnt = (uint16_t *)p;
431224006Shrs	p += sizeof(*rdn_cnt);
432224006Shrs	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
433224006Shrs		*rdn_cnt += 1;
434224006Shrs		memcpy(p, rdn, sizeof(*rdn));
435224006Shrs		p += sizeof(*rdn);
436224006Shrs
437224144Shrs		rda_cnt = (uint16_t *)p;
438224006Shrs		p += sizeof(*rda_cnt);
439224006Shrs		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
440224006Shrs			*rda_cnt += 1;
441224006Shrs			memcpy(p, rda, sizeof(*rda));
442224006Shrs			p += sizeof(*rda);
443224006Shrs		}
444224006Shrs	}
445224006Shrs	syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
446224006Shrs	cp->cp_val_len = p - cp->cp_val;
447224006Shrs
448224006Shrs	return (0);
449224006Shrs}
450224006Shrs
451224006Shrsstatic int
452225519Shrscm_getprop_dnssl(struct ctrl_msg_pl *cp)
453224006Shrs{
454224006Shrs	struct ifinfo *ifi;
455224006Shrs	struct rainfo *rai;
456224006Shrs	struct dnssl *dns;
457224006Shrs	struct dnssl_addr *dna;
458224006Shrs	char *p;
459224006Shrs	size_t len;
460224144Shrs	uint16_t *dns_cnt;
461224144Shrs	uint16_t *dna_cnt;
462224006Shrs
463224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
464224006Shrs
465224006Shrs	len = 0;
466224006Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
467224006Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
468224006Shrs			break;
469224006Shrs	}
470224006Shrs	if (ifi == NULL) {
471224006Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
472224006Shrs		    cp->cp_ifname);
473224006Shrs		return (1);
474224006Shrs	}
475224006Shrs	if (ifi->ifi_rainfo == NULL) {
476224006Shrs		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
477224006Shrs		    cp->cp_ifname);
478224006Shrs		return (1);
479224006Shrs	}
480224006Shrs	rai = ifi->ifi_rainfo;
481224006Shrs
482224006Shrs	len = sizeof(*dns_cnt);
483224006Shrs	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
484224006Shrs		len += sizeof(*dns);
485224006Shrs		len += sizeof(*dna_cnt);
486224006Shrs		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
487224006Shrs			len += sizeof(*dna);
488224006Shrs		}
489224006Shrs	}
490224006Shrs
491224144Shrs	syslog(LOG_DEBUG, "<%s> len = %zu", __func__, len);
492224006Shrs
493224006Shrs	p = malloc(len);
494224006Shrs	if (p == NULL)
495224006Shrs		exit(1);
496224006Shrs	memset(p, 0, len);
497224006Shrs	cp->cp_val = p;
498224006Shrs
499224144Shrs	dns_cnt = (uint16_t *)cp->cp_val;
500224006Shrs	p += sizeof(*dns_cnt);
501224006Shrs	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
502224006Shrs		(*dns_cnt)++;
503224006Shrs		memcpy(p, dns, sizeof(*dns));
504224006Shrs		p += sizeof(*dns);
505224006Shrs
506224144Shrs		dna_cnt = (uint16_t *)p;
507224006Shrs		p += sizeof(*dna_cnt);
508224006Shrs		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
509224006Shrs			(*dna_cnt)++;
510224006Shrs			memcpy(p, dna, sizeof(*dna));
511224006Shrs			p += sizeof(*dna);
512224006Shrs		}
513224006Shrs	}
514224006Shrs	cp->cp_val_len = p - cp->cp_val;
515224006Shrs
516224006Shrs	return (0);
517224006Shrs}
518224006Shrs
519224006Shrsint
520225519Shrscm_getprop(struct ctrl_msg_pl *cp)
521224006Shrs{
522224006Shrs	size_t i;
523224006Shrs
524224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
525224006Shrs
526224006Shrs	if (cp == NULL)
527224006Shrs		return (1);
528224006Shrs
529224006Shrs	for (i = 0;
530224006Shrs	     i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
531224006Shrs	     i++) {
532224006Shrs		if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
533224006Shrs			return (getprop_dtable[i].dt_act(cp));
534224006Shrs	}
535224006Shrs	return (1);
536224006Shrs}
537224006Shrs
538224006Shrsint
539225519Shrscm_setprop(struct ctrl_msg_pl *cp)
540224006Shrs{
541224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
542224006Shrs
543224006Shrs	if (cp == NULL || cp->cp_key == NULL)
544224006Shrs		return (1);
545224006Shrs
546224144Shrs	if (strncmp(cp->cp_key, "reload", sizeof("reload")) == 0)
547225519Shrs		cm_setprop_reload(cp);
548224144Shrs	else if (strncmp(cp->cp_key, "shutdown", sizeof("shutdown")) == 0)
549224144Shrs		set_do_shutdown(0);
550224144Shrs	else if (strncmp(cp->cp_key, "enable", sizeof("enable")) == 0)
551225519Shrs		cm_setprop_enable(cp);
552224144Shrs	else if (strncmp(cp->cp_key, "disable", sizeof("disable")) == 0)
553225519Shrs		cm_setprop_disable(cp);
554224006Shrs	else if (strncmp(cp->cp_key, "echo", 8) == 0)
555224006Shrs		; 		/* do nothing */
556224006Shrs	else
557224006Shrs		return (1);
558224006Shrs
559224006Shrs	return (0);
560224006Shrs}
561224006Shrs
562224144Shrsstatic int
563225519Shrscm_setprop_reload(struct ctrl_msg_pl *cp)
564224144Shrs{
565224144Shrs
566224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
567224144Shrs
568224144Shrs	set_do_reload_ifname(cp->cp_ifname);
569224144Shrs	set_do_reload(1);
570224144Shrs
571224144Shrs	return (0);
572224144Shrs}
573224144Shrs
574224144Shrsstatic int
575225519Shrscm_setprop_enable(struct ctrl_msg_pl *cp)
576224144Shrs{
577224144Shrs	struct ifinfo *ifi;
578224144Shrs
579224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
580224144Shrs
581224144Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
582224144Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
583224144Shrs			break;
584224144Shrs	}
585224144Shrs	if (ifi == NULL) {
586224144Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
587224144Shrs		    cp->cp_ifname);
588224144Shrs		return (1);
589224144Shrs	}
590224144Shrs
591224144Shrs	ifi->ifi_persist = 1;
592224144Shrs	set_do_reload_ifname(ifi->ifi_ifname);
593224144Shrs	set_do_reload(0);
594224144Shrs
595224144Shrs	return (0);
596224144Shrs}
597224144Shrs
598224144Shrsstatic int
599225519Shrscm_setprop_disable(struct ctrl_msg_pl *cp)
600224144Shrs{
601224144Shrs	struct ifinfo *ifi;
602224144Shrs
603224144Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
604224144Shrs
605224144Shrs	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
606224144Shrs		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
607224144Shrs			break;
608224144Shrs	}
609224144Shrs	if (ifi == NULL) {
610224144Shrs		syslog(LOG_ERR, "<%s> %s not found", __func__,
611224144Shrs		    cp->cp_ifname);
612224144Shrs		return (1);
613224144Shrs	}
614224144Shrs
615225519Shrs	if (ifi->ifi_persist == 1) {
616225519Shrs		ifi->ifi_persist = 0;
617225519Shrs		rm_ifinfo(ifi);
618224144Shrs
619225519Shrs		/* MC leaving needed here */
620225519Shrs		sock_mc_leave(&sock, ifi->ifi_ifindex);
621225519Shrs
622225519Shrs		set_do_reload_ifname(ifi->ifi_ifname);
623225519Shrs		set_do_reload(0);
624225519Shrs	}
625225519Shrs
626224144Shrs	return (0);
627224144Shrs}
628224144Shrs
629224006Shrsint
630225519Shrscm_handler_server(int fd)
631224006Shrs{
632224006Shrs	int state;
633224006Shrs	char *msg;
634224006Shrs	struct ctrl_msg_hdr *cm;
635224006Shrs	struct ctrl_msg_pl cp;
636224006Shrs	char buf[CM_MSG_MAXLEN];
637224006Shrs	char pbuf[CM_MSG_MAXLEN];
638224006Shrs	int error;
639224006Shrs
640224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
641224006Shrs
642224006Shrs	memset(buf, 0, sizeof(buf));
643224006Shrs	memset(pbuf, 0, sizeof(pbuf));
644224006Shrs	cm = (struct ctrl_msg_hdr *)buf;
645224006Shrs	msg = (char *)buf + sizeof(*cm);
646224006Shrs
647224006Shrs	state = CM_STATE_INIT;
648224006Shrs	while (state != CM_STATE_EOM) {
649224006Shrs		syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
650224006Shrs
651224006Shrs		switch (state) {
652224006Shrs		case CM_STATE_INIT:
653224006Shrs			state = CM_STATE_MSG_RECV;
654224006Shrs			break;
655224006Shrs		case CM_STATE_MSG_DISPATCH:
656224006Shrs			cm->cm_version = CM_VERSION;
657225519Shrs			error = cm_send(fd, buf);
658224006Shrs			if (error)
659224006Shrs				syslog(LOG_WARNING,
660225519Shrs				    "<%s> cm_send()", __func__);
661224006Shrs			state = CM_STATE_EOM;
662224006Shrs			break;
663224006Shrs		case CM_STATE_ACK_WAIT:
664225519Shrs			error = cm_recv(fd, buf);
665224006Shrs			if (error) {
666224006Shrs				syslog(LOG_ERR,
667225519Shrs				    "<%s> cm_recv()", __func__);
668224006Shrs				close(fd);
669224006Shrs				return (-1);
670224006Shrs			}
671224006Shrs
672224006Shrs			switch (cm->cm_type) {
673224006Shrs			case CM_TYPE_ACK:
674224006Shrs				break;
675224006Shrs			case CM_TYPE_ERR:
676224006Shrs				syslog(LOG_DEBUG,
677224006Shrs				    "<%s> CM_TYPE_ERR", __func__);
678224006Shrs				close(fd);
679224006Shrs				return (-1);
680224006Shrs			default:
681224006Shrs				syslog(LOG_DEBUG,
682224006Shrs				    "<%s> unknown status", __func__);
683224006Shrs				close(fd);
684224006Shrs				return (-1);
685224006Shrs			}
686224006Shrs			state = CM_STATE_EOM;
687224006Shrs			break;
688224006Shrs		case CM_STATE_MSG_RECV:
689225519Shrs			error = cm_recv(fd, buf);
690224006Shrs
691224006Shrs			if (error) {
692224006Shrs				syslog(LOG_ERR,
693225519Shrs				    "<%s> cm_recv()", __func__);
694224006Shrs				close(fd);
695224006Shrs				return (-1);
696224006Shrs			}
697224006Shrs			memset(&cp, 0, sizeof(cp));
698224006Shrs
699224006Shrs			syslog(LOG_DEBUG,
700224006Shrs			    "<%s> cm->cm_type = %d", __func__, cm->cm_type);
701224006Shrs			syslog(LOG_DEBUG,
702224144Shrs			    "<%s> cm->cm_len = %zu", __func__, cm->cm_len);
703224006Shrs
704224006Shrs			switch (cm->cm_type) {
705224006Shrs			case CM_TYPE_EOM:
706224006Shrs				state = CM_STATE_EOM;
707224006Shrs			case CM_TYPE_NUL:
708224006Shrs				cm->cm_type = CM_TYPE_ACK;
709224006Shrs				cm->cm_len = sizeof(*cm);
710224006Shrs				break;
711224006Shrs			case CM_TYPE_REQ_GET_PROP:
712225519Shrs				cm_bin2pl(msg, &cp);
713225519Shrs				error = cm_getprop(&cp);
714224006Shrs				if (error) {
715224006Shrs					cm->cm_type = CM_TYPE_ERR;
716224006Shrs					cm->cm_len = sizeof(*cm);
717224006Shrs				} else {
718224006Shrs					cm->cm_type = CM_TYPE_ACK;
719224006Shrs					cm->cm_len = sizeof(*cm);
720225519Shrs					cm->cm_len += cm_pl2bin(msg, &cp);
721224006Shrs				}
722224144Shrs				if (cp.cp_val != NULL)
723224144Shrs					free(cp.cp_val);
724224006Shrs				break;
725224006Shrs			case CM_TYPE_REQ_SET_PROP:
726225519Shrs				cm_bin2pl(msg, &cp);
727225519Shrs				error = cm_setprop(&cp);
728224006Shrs				if (error) {
729224006Shrs					cm->cm_type = CM_TYPE_ERR;
730224006Shrs					cm->cm_len = sizeof(*cm);
731224006Shrs				} else {
732224006Shrs					cm->cm_type = CM_TYPE_ACK;
733224006Shrs					cm->cm_len = sizeof(*cm);
734224006Shrs				}
735224006Shrs				break;
736224006Shrs			default:
737224006Shrs				cm->cm_type = CM_TYPE_ERR;
738224006Shrs				cm->cm_len = sizeof(*cm);
739224006Shrs			}
740224006Shrs
741224006Shrs			switch (cm->cm_type) {
742224006Shrs			case CM_TYPE_ERR:
743224006Shrs			case CM_TYPE_ACK:
744224006Shrs				state = CM_STATE_MSG_DISPATCH;
745224006Shrs				break;
746224006Shrs			}
747224006Shrs		}
748224006Shrs	}
749224006Shrs	syslog(LOG_DEBUG, "<%s> leave", __func__);
750224006Shrs
751224006Shrs	return (0);
752224006Shrs}
753