1/* $NetBSD: monitor.c,v 1.15 2008/04/28 20:24:16 martin Exp $ */
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Martin Husemann <martin@NetBSD.org>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "isdnd.h"
33
34#ifndef I4B_EXTERNAL_MONITOR
35
36/*
37 * dummy version of routines needed by config file parser
38 * (config files should be valid with and without external montioring
39 * support compiled into the daemon)
40 */
41
42void monitor_clear_rights()
43{ }
44
45int monitor_start_rights(const char *clientspec)
46{ return I4BMAR_OK; }
47
48void monitor_add_rights(int rights_mask)
49{ }
50
51void monitor_fixup_rights()
52{ }
53
54#else
55
56#include "monitor.h"
57#include <sys/socket.h>
58#include <sys/un.h>
59#ifndef I4B_NOTCPIP_MONITOR
60#include <netinet/in.h>
61#include <arpa/inet.h>
62#include <netdb.h>
63#endif
64
65
66static TAILQ_HEAD(rights_q, monitor_rights) rights = TAILQ_HEAD_INITIALIZER(rights);
67
68static struct monitor_rights * local_rights = NULL;	/* entry for local socket */
69
70/* for each active monitor connection we have one of this: */
71
72struct monitor_connection {
73	TAILQ_ENTRY(monitor_connection) connections;
74	int sock;			/* socket for this connection */
75	int rights;			/* active rights for this connection */
76	int events;			/* bitmask of events client is interested in */
77	char source[FILENAME_MAX];
78};
79
80static TAILQ_HEAD(connections_tq, monitor_connection) connections = TAILQ_HEAD_INITIALIZER(connections);
81
82/* local prototypes */
83struct monitor_rights * monitor_next_rights(const struct monitor_rights *r);
84static int cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb);
85static int monitor_command(struct monitor_connection *con, int fd, int rights);
86static void cmd_dump_rights(int fd, int rights, u_int8_t *cmd, const char * source);
87static void cmd_dump_mcons(int fd, int rights, u_int8_t *cmd, const char * source);
88static void cmd_reread_cfg(int fd, int rights, u_int8_t *cmd, const char * source);
89static void cmd_hangup(int fd, int rights, u_int8_t *cmd, const char * source);
90static void monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes);
91static int anybody(int mask);
92static void hangup_channel(int controller, int channel, const char *source);
93static ssize_t sock_read(int fd, void *buf, size_t nbytes);
94static ssize_t sock_write(int fd, void *buf, size_t nbytes);
95
96/*
97 * Due to the way we structure config files, the rights for an external
98 * monitor might be stated in multiple steps. First a call to
99 * monitor_start_rights opens an entry. Further (optional) calls to
100 * montior_add_rights assemble additional rights for this "current"
101 * entry. When closing the sys-file section of the config file, the
102 * "current" entry becomes invalid.
103 */
104static struct monitor_rights * cur_add_entry = NULL;
105
106/*---------------------------------------------------------------------------
107 * Initialize the monitor server module. This affects only active
108 * connections, the access rights are not modified here!
109 *---------------------------------------------------------------------------*/
110void
111monitor_init(void)
112{
113	struct monitor_connection * con;
114	accepted = 0;
115	while ((con = TAILQ_FIRST(&connections)) != NULL)
116	{
117		TAILQ_REMOVE(&connections, con, connections);
118		free(con);
119	}
120}
121
122/*---------------------------------------------------------------------------
123 * Prepare for exit
124 *---------------------------------------------------------------------------*/
125void
126monitor_exit(void)
127{
128	struct monitor_connection *c;
129
130	/* Close all open connections. */
131	while((c = TAILQ_FIRST(&connections)) != NULL) {
132		close(c->sock);
133		TAILQ_REMOVE(&connections, c, connections);
134		free(c);
135	}
136}
137
138/*---------------------------------------------------------------------------
139 * Initialize access rights. No active connections are affected!
140 *---------------------------------------------------------------------------*/
141void
142monitor_clear_rights(void)
143{
144	struct monitor_rights *r;
145	while ((r = TAILQ_FIRST(&rights)) != NULL) {
146		TAILQ_REMOVE(&rights, r, list);
147		free(r);
148	}
149	cur_add_entry = NULL;
150	local_rights = NULL;
151}
152
153/*---------------------------------------------------------------------------
154 * Add an entry to the access lists. The clientspec either is
155 * the name of the local socket or a host- or networkname or
156 * numeric ip/host-bit-len spec.
157 *---------------------------------------------------------------------------*/
158int
159monitor_start_rights(const char *clientspec)
160{
161	struct monitor_rights r;
162
163	/* initialize the new rights entry */
164
165	memset(&r, 0, sizeof r);
166
167	/* check clientspec */
168
169	if (*clientspec == '/')
170	{
171		struct sockaddr_un sa;
172
173		/* this is a local socket spec, check if we already have one */
174
175		if (local_rights != NULL)
176			return I4BMAR_DUP;
177
178		/* does it fit in a local socket address? */
179
180		if (strlen(clientspec) > sizeof sa.sun_path)
181			return I4BMAR_LENGTH;
182
183		r.local = 1;
184		strlcpy(r.name, clientspec, sizeof(r.name));
185
186#ifndef I4B_NOTCPIP_MONITOR
187
188	}
189	else
190	{
191		/* remote entry, parse host/net and cidr */
192
193		struct monitor_rights * rp;
194		char hostname[FILENAME_MAX];
195		char *p;
196
197		p = strchr(clientspec, '/');
198
199		if (!p)
200		{
201			struct hostent *host;
202			u_int32_t hn;
203
204			/* must be a host spec */
205
206			r.mask = ~0;
207			host = gethostbyname(clientspec);
208
209			if (!host)
210				return I4BMAR_NOIP;
211
212			memcpy(&hn, host->h_addr_list[0], sizeof hn);
213			r.net = (u_int32_t)ntohl(hn);
214		}
215		else if (p[1])
216		{
217			/* must be net/cidr spec */
218
219			int l;
220			struct netent *net;
221			u_int32_t s = ~0U;
222			int num = strtol(p+1, NULL, 10);
223
224			if (num < 0 || num > 32)
225				return I4BMAR_CIDR;
226
227			s >>= num;
228			s ^= ~0U;
229			l = p - clientspec;
230
231			if (l >= (int)sizeof hostname)
232				return I4BMAR_LENGTH;
233
234			strncpy(hostname, clientspec, l);
235
236			hostname[l] = '\0';
237
238			net = getnetbyname(hostname);
239
240			if (net == NULL)
241				r.net = (u_int32_t)inet_network(hostname);
242			else
243				r.net = (u_int32_t)net->n_net;
244
245			r.mask = s;
246			r.net &= s;
247		}
248		else
249		{
250			return I4BMAR_CIDR;
251		}
252
253		/* check for duplicate entry */
254
255		for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
256		{
257			if (rp->mask == r.mask &&
258			    rp->net == r.net &&
259			    rp->local == r.local)
260			{
261				return I4BMAR_DUP;
262			}
263		}
264#endif
265	}
266
267	r.rights = 0;
268
269	/* entry ok, add it to the collection */
270
271	cur_add_entry = malloc(sizeof(r));
272	memcpy(cur_add_entry, &r, sizeof(r));
273	TAILQ_INSERT_TAIL(&rights, cur_add_entry, list);
274
275	if (r.local)
276		local_rights = cur_add_entry;
277
278	DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor = %s", clientspec)));
279
280	return I4BMAR_OK;
281}
282
283/*---------------------------------------------------------------------------
284 * Add rights to the currently constructed entry - if any.
285 *---------------------------------------------------------------------------*/
286void
287monitor_add_rights(int rights_mask)
288{
289	if (cur_add_entry == NULL)
290		return;		/* noone under construction */
291
292	cur_add_entry->rights |= rights_mask;
293
294	DBGL(DL_RCCF, (logit(LL_DBG, "system: monitor-access = 0x%x", rights_mask)));
295}
296
297/*---------------------------------------------------------------------------
298 * All rights have been added now. Sort the to get most specific
299 * host/net masks first, so we can travel the list and use the first
300 * match for actual rights.
301 *---------------------------------------------------------------------------*/
302void
303monitor_fixup_rights(void)
304{
305	struct monitor_rights * cur, * test, * next;
306
307	/* no more rights may be added to the current entry */
308
309	cur_add_entry = NULL;
310
311	/* sort the rights */
312	for (next = NULL, cur = TAILQ_FIRST(&rights); cur != NULL; cur = next)
313	{
314		next = TAILQ_NEXT(cur, list);
315		for (test = TAILQ_FIRST(&rights); test != NULL && test != cur; test = TAILQ_NEXT(test, list))
316		{
317			if (cmp_rights(cur, test) > 0) {
318				/* move cur up the list and insert before test */
319				TAILQ_REMOVE(&rights, cur, list);
320				if (test == TAILQ_FIRST(&rights))
321					TAILQ_INSERT_HEAD(&rights, cur, list);
322				else
323					TAILQ_INSERT_BEFORE(test, cur, list);
324				break;
325			}
326		}
327	}
328}
329
330/*---------------------------------------------------------------------------
331 * comparator for rights
332 *---------------------------------------------------------------------------*/
333static int
334cmp_rights(const struct monitor_rights *pa, const struct monitor_rights *pb)
335{
336	u_int32_t mask;
337
338	/* local sorts first */
339
340	if (pa->local)
341		return -1;
342
343	/* which is the less specific netmask? */
344
345	mask = pa->mask;
346
347	if ((pb->mask & mask) == 0)
348		mask = pb->mask;
349
350	/* are the entries disjunct? */
351
352	if ((pa->net & mask) != (pb->net & mask))
353	{
354		/* simply compare net part of address */
355		return ((pa->net & mask) < (pb->net & mask)) ? -1 : 1;
356	}
357
358	/* One entry is part of the others net. We already now "mask" is
359	 * the netmask of the less specific (i.e. greater) one */
360
361	return (pa->mask == mask) ? 1 : -1;
362}
363
364#ifndef I4B_NOTCPIP_MONITOR
365/*---------------------------------------------------------------------------
366 * Check if access rights for a remote socket are specified and
367 * create this socket. Return -1 otherwise.
368 *---------------------------------------------------------------------------*/
369int
370monitor_create_remote_socket(int portno)
371{
372	struct sockaddr_in sa;
373	int val;
374	int remotesockfd;
375
376	remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
377
378	if (remotesockfd == -1)
379	{
380		logit(LL_MER, "could not create remote monitor socket: %s", strerror(errno));
381		return(-1);
382	}
383
384	val = 1;
385
386	if (setsockopt(remotesockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val))
387	{
388		logit(LL_MER, "could not setsockopt: %s", strerror(errno));
389		return(-1);
390	}
391
392	memset(&sa, 0, sizeof sa);
393	sa.sin_len = sizeof sa;
394	sa.sin_family = AF_INET;
395	sa.sin_port = htons(portno);
396	sa.sin_addr.s_addr = htonl(INADDR_ANY);
397
398	if (bind(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1)
399	{
400		logit(LL_MER, "could not bind remote monitor socket to port %d: %s", portno, strerror(errno));
401		return(-1);
402	}
403
404	if (listen(remotesockfd, 0))
405	{
406		logit(LL_MER, "could not listen on monitor socket: %s", strerror(errno));
407		return(-1);
408	}
409
410	return(remotesockfd);
411}
412#endif
413
414/*---------------------------------------------------------------------------
415 * Check if access rights for a local socket are specified and
416 * create this socket. Return -1 otherwise.
417 *---------------------------------------------------------------------------*/
418int
419monitor_create_local_socket(void)
420{
421	int s;
422	struct sockaddr_un sa;
423
424	/* check for a local entry */
425
426	if (local_rights == NULL)
427		return(-1);
428
429	/* create and setup socket */
430
431	s = socket(AF_LOCAL, SOCK_STREAM, 0);
432
433	if (s == -1)
434	{
435		logit(LL_MER, "could not create local monitor socket, errno = %d", errno);
436		return(-1);
437	}
438
439	unlink(local_rights->name);
440
441	memset(&sa, 0, sizeof sa);
442	sa.sun_len = sizeof sa;
443	sa.sun_family = AF_LOCAL;
444	strlcpy(sa.sun_path, local_rights->name, sizeof(sa.sun_path));
445
446	if (bind(s, (struct sockaddr *)&sa, SUN_LEN(&sa)))
447	{
448		logit(LL_MER, "could not bind local monitor socket [%s], errno = %d", local_rights->name, errno);
449		return(-1);
450	}
451
452	chmod(local_rights->name, 0600);
453
454	if (listen(s, 0))
455	{
456		logit(LL_MER, "could not listen on local monitor socket, errno = %d", errno);
457		return(-1);
458	}
459
460	return(s);
461}
462
463/*---------------------------------------------------------------------------
464 * Prepare a fd_set for a select call. Add all our local
465 * filedescriptors to the set, increment max_fd if appropriate.
466 *---------------------------------------------------------------------------*/
467void
468monitor_prepselect(fd_set *selset, int *max_fd)
469{
470	struct monitor_connection * con;
471
472	for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
473	{
474		int fd = con->sock;
475
476		if (fd > *max_fd)
477			*max_fd = fd;
478
479		FD_SET(fd, selset);
480	}
481}
482
483/*---------------------------------------------------------------------------
484 * Check if the result from a select call indicates something
485 * to do for us.
486 *---------------------------------------------------------------------------*/
487void
488monitor_handle_input(fd_set *selset)
489{
490	struct monitor_connection * con, * next;
491
492	for (next = NULL, con = TAILQ_FIRST(&connections); con != NULL; con = next)
493	{
494		int fd = con->sock;
495		next = TAILQ_NEXT(con, connections);
496
497		if (FD_ISSET(fd, selset))
498		{
499			/* handle command from this client */
500
501			if (monitor_command(con, fd, con->rights) != 0)
502			{
503				/* broken or closed connection */
504
505				char source[FILENAME_MAX];
506
507				strlcpy(source, con->source, sizeof(source));
508				TAILQ_REMOVE(&connections, con, connections);
509				free(con);
510				logit(LL_DMN, "monitor closed from %s", source );
511			}
512		}
513	}
514
515	/* all connections gone? */
516
517	if (TAILQ_FIRST(&connections) == NULL)
518		accepted = 0;
519}
520
521/*---------------------------------------------------------------------------
522 * Try new incoming connection on the given socket.
523 * Setup client descriptor and send initial data.
524 *---------------------------------------------------------------------------*/
525void
526monitor_handle_connect(int sockfd, int is_local)
527{
528	struct monitor_connection *con;
529	struct monitor_rights *rp;
530	struct isdn_ctrl_state *ctrl;
531	struct cfg_entry *cfe;
532	int n;
533
534#ifndef I4B_NOTCPIP_MONITOR
535	struct sockaddr_in ia;
536	u_int32_t ha = 0;
537#endif
538
539	struct sockaddr_un ua;
540	socklen_t s;
541	u_int8_t idata[I4B_MON_IDATA_SIZE];
542	int fd = -1, r_mask, t_events;
543	char source[FILENAME_MAX];
544
545	/* accept the connection */
546
547	if (is_local)
548	{
549		s = sizeof ua;
550		fd = accept(sockfd, (struct sockaddr *)&ua, &s);
551		strlcpy(source, "local", sizeof(source));
552
553#ifndef I4B_NOTCPIP_MONITOR
554	}
555	else
556	{
557		struct hostent *hp;
558
559		s = sizeof ia;
560		fd = accept(sockfd, (struct sockaddr *)&ia, &s);
561
562		hp = gethostbyaddr((char *)&ia.sin_addr, 4, AF_INET);
563
564		if (hp == NULL)
565			snprintf(source, sizeof source, "%s (%s)", inet_ntoa(ia.sin_addr), inet_ntoa(ia.sin_addr));
566		else
567			snprintf(source, sizeof source, "%s (%s)", hp->h_name, inet_ntoa(ia.sin_addr));
568
569		memcpy(&ha, &ia.sin_addr.s_addr, sizeof ha);
570
571		ha = ntohl(ha);
572#endif
573	}
574
575	/* check the access rights of this connection */
576
577	r_mask = 0;
578
579	for (rp = TAILQ_FIRST(&rights); rp != NULL; rp = TAILQ_NEXT(rp, list))
580	{
581		if (rp->local)
582		{
583			if (is_local)
584			{
585				r_mask = rp->rights;
586				break;
587			}
588
589#ifndef I4B_NOTCPIP_MONITOR
590		}
591		else
592		{
593			if ((ha & rp->mask) == rp->net)
594			{
595				r_mask = rp->rights;
596				break;
597			}
598#endif
599		}
600	}
601
602	if (r_mask == 0)
603	{
604		/* no rights - go away */
605		logit(LL_MER, "monitor access denied from %s", source);
606		close(fd);
607		return;
608	}
609
610	accepted = 1;
611
612	con = malloc(sizeof(struct monitor_connection));
613	memset(con, 0, sizeof *con);
614	TAILQ_INSERT_TAIL(&connections, con, connections);
615	con->sock = fd;
616	con->rights = r_mask;
617	strlcpy(con->source, source, sizeof(con->source));
618
619	logit(LL_DMN, "monitor opened from %s rights 0x%x", source, r_mask);
620
621	/* send initial data */
622	I4B_PREP_CMD(idata, I4B_MON_IDATA_CODE);
623	I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMAJOR, MPROT_VERSION);
624	I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMINOR, MPROT_REL);
625	n = count_ctrl_states();
626	I4B_PUT_2B(idata, I4B_MON_IDATA_NUMCTRL, n);
627	n = count_cfg_entries();
628	I4B_PUT_2B(idata, I4B_MON_IDATA_NUMENTR, n);
629	I4B_PUT_4B(idata, I4B_MON_IDATA_CLACCESS, r_mask);
630
631	if ((sock_write(fd, idata, sizeof idata)) == -1)
632	{
633		logit(LL_MER, "monitor_handle_connect: sock_write 1 error - %s", strerror(errno));
634	}
635
636	for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
637		u_int8_t ictrl[I4B_MON_ICTRL_SIZE];
638		char ctrl_desc[100];
639
640		snprintf(ctrl_desc, sizeof(ctrl_desc), "%s: %s",
641		    ctrl->device_name, ctrl->controller);
642
643		I4B_PREP_CMD(ictrl, I4B_MON_ICTRL_CODE);
644		I4B_PUT_STR(ictrl, I4B_MON_ICTRL_NAME, ctrl_desc);
645		I4B_PUT_2B(ictrl, I4B_MON_ICTRL_BUSID, ctrl->isdnif);
646		I4B_PUT_4B(ictrl, I4B_MON_ICTRL_FLAGS, 0);
647		I4B_PUT_2B(ictrl, I4B_MON_ICTRL_NCHAN, 2);
648
649		if ((sock_write(fd, ictrl, sizeof ictrl)) == -1)
650		{
651			logit(LL_MER, "monitor_handle_connect: sock_write 2 error - %s", strerror(errno));
652		}
653
654	}
655
656	/* send device names from entries */
657
658	for (cfe = get_first_cfg_entry(); cfe; cfe = NEXT_CFE(cfe)) {
659		u_int8_t ictrl[I4B_MON_IDEV_SIZE];
660		char nbuf[64];
661
662		snprintf(nbuf, sizeof(nbuf), "%s%d ", cfe->usrdevicename, cfe->usrdeviceunit);
663
664		I4B_PREP_CMD(ictrl, I4B_MON_IDEV_CODE);
665/*XXX*/		I4B_PUT_2B(ictrl, I4B_MON_IDEV_STATE, 1);
666		I4B_PUT_STR(ictrl, I4B_MON_IDEV_NAME, nbuf);
667
668		if ((sock_write(fd, ictrl, sizeof ictrl)) == -1)
669		{
670			logit(LL_MER, "monitor_handle_connect: sock_write 3 error - %s", strerror(errno));
671		}
672	}
673
674/*XXX*/	t_events = con->events;
675/*XXX*/	con->events = -1;
676
677	/* current state of controller(s) */
678
679	for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
680		monitor_evnt_tei(ctrl->isdnif, ctrl->tei);
681		monitor_evnt_l12stat(ctrl->isdnif, LAYER_ONE, ctrl->l1stat);
682		monitor_evnt_l12stat(ctrl->isdnif, LAYER_TWO, ctrl->l2stat);
683	}
684
685	/* current state of entries */
686
687	for (cfe = get_first_cfg_entry(); cfe; cfe = NEXT_CFE(cfe)) {
688
689		if (cfe->state == ST_CONNECTED)
690		{
691			monitor_evnt_connect(cfe);
692			monitor_evnt_acct(cfe);
693			monitor_evnt_charge(cfe, cfe->charge, 1);
694		}
695        }
696
697/*XXX*/	con->events = t_events;
698
699}
700
701/*---------------------------------------------------------------------------
702 * dump all monitor rights
703 *---------------------------------------------------------------------------*/
704static void
705cmd_dump_rights(int fd, int r_mask, u_int8_t *cmd, const char *source)
706{
707	struct monitor_rights * r;
708	int num_rights;
709	u_int8_t drini[I4B_MON_DRINI_SIZE];
710	u_int8_t dr[I4B_MON_DR_SIZE];
711
712	for (num_rights = 0, r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
713		num_rights++;
714
715	I4B_PREP_EVNT(drini, I4B_MON_DRINI_CODE);
716	I4B_PUT_2B(drini, I4B_MON_DRINI_COUNT, num_rights);
717
718	if ((sock_write(fd, drini, sizeof drini)) == -1)
719	{
720		logit(LL_MER, "cmd_dump_rights: sock_write 1 error - %s", strerror(errno));
721	}
722
723	for (r = TAILQ_FIRST(&rights); r != NULL; r = TAILQ_NEXT(r, list))
724	{
725		I4B_PREP_EVNT(dr, I4B_MON_DR_CODE);
726		I4B_PUT_4B(dr, I4B_MON_DR_RIGHTS, r->rights);
727		I4B_PUT_4B(dr, I4B_MON_DR_NET, r->net);
728		I4B_PUT_4B(dr, I4B_MON_DR_MASK, r->mask);
729		I4B_PUT_1B(dr, I4B_MON_DR_LOCAL, r->local);
730		if ((sock_write(fd, dr, sizeof dr)) == -1)
731		{
732			logit(LL_MER, "cmd_dump_rights: sock_write 2 error - %s", strerror(errno));
733		}
734	}
735}
736
737/*---------------------------------------------------------------------------
738 * rescan config file
739 *---------------------------------------------------------------------------*/
740static void
741cmd_reread_cfg(int fd, int _rights, u_int8_t *cmd, const char * source)
742{
743	rereadconfig(42);
744}
745
746/*---------------------------------------------------------------------------
747 * drop one connection
748 *---------------------------------------------------------------------------*/
749static void
750cmd_hangup(int fd, int _rights, u_int8_t *cmd, const char * source)
751{
752	int channel = I4B_GET_4B(cmd, I4B_MON_HANGUP_CHANNEL);
753	int ctrl = I4B_GET_4B(cmd, I4B_MON_HANGUP_CTRL);
754
755	hangup_channel(ctrl, channel, source);
756}
757
758/*---------------------------------------------------------------------------
759 * dump all active monitor connections
760 *---------------------------------------------------------------------------*/
761static void
762cmd_dump_mcons(int fd, int _rights, u_int8_t *cmd, const char * source)
763{
764	int num_connections;
765	struct monitor_connection *con;
766	u_int8_t dcini[I4B_MON_DCINI_SIZE];
767
768	for (num_connections = 0, con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
769		num_connections++;
770
771	I4B_PREP_EVNT(dcini, I4B_MON_DCINI_CODE);
772	I4B_PUT_2B(dcini, I4B_MON_DCINI_COUNT, num_connections);
773
774	if ((sock_write(fd, dcini, sizeof dcini)) == -1)
775	{
776		logit(LL_MER, "cmd_dump_mcons: sock_write 1 error - %s", strerror(errno));
777	}
778
779	for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
780	{
781#ifndef I4B_NOTCPIP_MONITOR
782		socklen_t namelen;
783		struct sockaddr_in name;
784#endif
785		u_int8_t dc[I4B_MON_DC_SIZE];
786
787		I4B_PREP_EVNT(dc, I4B_MON_DC_CODE);
788		I4B_PUT_4B(dc, I4B_MON_DC_RIGHTS, con->rights);
789
790#ifndef I4B_NOTCPIP_MONITOR
791		namelen = sizeof name;
792
793		if (getpeername(con->sock, (struct sockaddr*)&name, &namelen) == 0)
794			memcpy(dc+I4B_MON_DC_WHO, &name.sin_addr, sizeof name.sin_addr);
795#endif
796		if ((sock_write(fd, dc, sizeof dc)) == -1)
797		{
798			logit(LL_MER, "cmd_dump_mcons: sock_write 2 error - %s", strerror(errno));
799		}
800	}
801}
802
803/*---------------------------------------------------------------------------
804 * Handle a command from the given socket. The client
805 * has rights as specified in the rights parameter.
806 * Return non-zero if connection is closed.
807 *---------------------------------------------------------------------------*/
808static int
809monitor_command(struct monitor_connection * con, int fd, int mcrights)
810{
811	char cmd[I4B_MAX_MON_CLIENT_CMD];
812	u_int code;
813
814	/* command dispatch table */
815	typedef void (*cmd_func_t)(int fd, int rights, u_int8_t *cmd, const char *source);
816
817	static struct {
818		cmd_func_t call;	/* function to execute */
819		u_int rights;		/* necessary rights */
820	} cmd_tab[] =
821	{
822	/* 0 */	{ NULL, 0 },
823	/* 1 */	{ cmd_dump_rights, I4B_CA_COMMAND_FULL },
824	/* 2 */	{ cmd_dump_mcons, I4B_CA_COMMAND_FULL },
825	/* 3 */ { cmd_reread_cfg, I4B_CA_COMMAND_FULL },
826	/* 4 */ { cmd_hangup, I4B_CA_COMMAND_FULL },
827	};
828#define	NUMCMD	(sizeof cmd_tab / sizeof cmd_tab[0])
829
830	int avail, bytes, err;
831
832	/* Network transfer may deliver two or more packets concatenated.
833	 * Peek at the header and read only one event at a time... */
834
835	avail = 0;
836	err = ioctl(fd, FIONREAD, &avail);
837
838	if (err == -1 || avail < I4B_MON_CMD_HDR)
839	{
840		if (err == -1 && errno == EINTR)
841			return 0;	/* try again later */
842
843		if (err == -1 || avail == 0)
844		{
845			/* logit(LL_MER, "monitor read 0 bytes"); */
846			/* socket closed by peer */
847			close(fd);
848			return 1;
849		}
850		return 0;	/* not enough data there yet */
851	}
852
853	bytes = recv(fd, cmd, I4B_MON_CMD_HDR, MSG_PEEK);
854
855	if (bytes < I4B_MON_CMD_HDR)
856	{
857		logit(LL_MER, "monitor read only %d bytes", bytes);
858		return 0;	/* errh? something must be wrong... */
859	}
860
861	bytes = I4B_GET_2B(cmd, I4B_MON_CMD_LEN);
862
863	if (bytes >= (int)sizeof cmd)
864	{
865		close(fd);
866		logit(LL_MER, "monitor: garbage on connection");
867		return 1;
868	}
869
870	/* now we know the size, it fits, so lets read it! */
871
872	if (sock_read(fd, cmd, bytes) <= 0)
873	{
874		logit(LL_MER, "monitor: sock_read <= 0");
875		close(fd);
876		return 1;
877	}
878
879	/* decode command */
880	code = I4B_GET_2B(cmd, I4B_MON_CMD);
881
882	/* special case: may modify our connection descriptor, is
883	 * beyound all rights checks */
884
885	if (code == I4B_MON_CCMD_SETMASK)
886	{
887/*XXX*/
888		/*
889		u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR);
890		u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR);
891		*/
892
893		int events = I4B_GET_4B(cmd, I4B_MON_ICLIENT_EVENTS);
894		con->events = events & mcrights;
895		return 0;
896	}
897
898	if (code >= NUMCMD)
899	{
900		logit(LL_MER, "illegal command from client, code = %d\n",
901			code);
902		return 0;
903	}
904
905	if (cmd_tab[code].call == NULL)
906		return 0;
907
908	if ((cmd_tab[code].rights & mcrights) == cmd_tab[code].rights)
909		cmd_tab[code].call(fd, mcrights, (u_char *)cmd, con->source);
910
911	return 0;
912}
913
914/*---------------------------------------------------------------------------
915 * Check if somebody would receive an event with this mask.
916 * We are lazy and try to avoid assembling unneccesary packets.
917 * Return 0 if no one interested, nonzero otherwise.
918 *---------------------------------------------------------------------------*/
919static int
920anybody(int mask)
921{
922	struct monitor_connection * con;
923
924	for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
925	{
926		if ((con->events & mask) == mask)
927			return 1;
928	}
929	return 0;
930}
931
932/*---------------------------------------------------------------------------
933 * exec hangup command
934 *---------------------------------------------------------------------------*/
935static void
936hangup_channel(int controller, int channel, const char *source)
937{
938	struct cfg_entry * cep = NULL;
939	struct isdn_ctrl_state * ctrl = NULL;
940	int i;
941
942	ctrl = find_ctrl_state(controller);
943	if (ctrl != NULL) {
944		if (ctrl->state != CTRL_UP)
945			return;
946		for (i = 0; i < ctrl->nbch; i++) {
947			if (ctrl->stateb[i] != CHAN_IDLE) {
948				cep = get_cep_by_cc(controller, i);
949				if (cep != NULL
950				    && cep->isdnchannelused == channel
951				    && cep->isdncontrollerused == controller)
952					goto found;
953			}
954		}
955	}
956	/* not found */
957	return;
958
959found:
960	logit(LL_CHD, "%05d %s manual disconnect (remote from %s)", cep->cdid, cep->name, source);
961	cep->hangup = 1;
962	return;
963}
964
965/*---------------------------------------------------------------------------
966 * Send an event to every connection interested in this kind of
967 * event
968 *---------------------------------------------------------------------------*/
969static void
970monitor_broadcast(int mask, u_int8_t *pkt, size_t bytes)
971{
972	struct monitor_connection *con;
973
974	for (con = TAILQ_FIRST(&connections); con != NULL; con = TAILQ_NEXT(con, connections))
975	{
976		if ((con->events & mask) == mask)
977		{
978			int fd = con->sock;
979
980			if ((sock_write(fd, pkt, bytes)) == -1)
981			{
982				logit(LL_MER, "monitor_broadcast: sock_write error - %s", strerror(errno));
983			}
984		}
985	}
986}
987
988/*---------------------------------------------------------------------------
989 * Post a logfile event
990 *---------------------------------------------------------------------------*/
991void
992monitor_evnt_log(int prio, const char * what, const char * msg)
993{
994	u_int8_t evnt[I4B_MON_LOGEVNT_SIZE];
995	time_t now;
996
997	if (!anybody(I4B_CA_EVNT_I4B))
998		return;
999
1000	time(&now);
1001
1002	I4B_PREP_EVNT(evnt, I4B_MON_LOGEVNT_CODE);
1003	I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_TSTAMP, (long)now);
1004	I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_PRIO, prio);
1005	I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_WHAT, what);
1006	I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_MSG, msg);
1007
1008	monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1009}
1010
1011/*---------------------------------------------------------------------------
1012 * Post a charging event on the connection described
1013 * by the given config entry.
1014 *---------------------------------------------------------------------------*/
1015void
1016monitor_evnt_charge(struct cfg_entry *cep, int units, int estimate)
1017{
1018	int mask;
1019	time_t now;
1020	u_int8_t evnt[I4B_MON_CHRG_SIZE];
1021
1022	mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1023
1024	if (!anybody(mask))
1025		return;
1026
1027	time(&now);
1028
1029	I4B_PREP_EVNT(evnt, I4B_MON_CHRG_CODE);
1030	I4B_PUT_4B(evnt, I4B_MON_CHRG_TSTAMP, (long)now);
1031	I4B_PUT_4B(evnt, I4B_MON_CHRG_CTRL, cep->isdncontrollerused);
1032	I4B_PUT_4B(evnt, I4B_MON_CHRG_CHANNEL, cep->isdnchannelused);
1033	I4B_PUT_4B(evnt, I4B_MON_CHRG_UNITS, units);
1034	I4B_PUT_4B(evnt, I4B_MON_CHRG_ESTIMATED, estimate ? 1 : 0);
1035
1036	monitor_broadcast(mask, evnt, sizeof evnt);
1037}
1038
1039/*---------------------------------------------------------------------------
1040 * Post a connection event
1041 *---------------------------------------------------------------------------*/
1042void
1043monitor_evnt_connect(struct cfg_entry *cep)
1044{
1045	u_int8_t evnt[I4B_MON_CONNECT_SIZE];
1046	char devnam[I4B_MAX_MON_STRING];
1047	int mask;
1048	time_t now;
1049
1050	mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1051
1052	if (!anybody(mask))
1053		return;
1054
1055	time(&now);
1056
1057	snprintf(devnam, sizeof devnam, "%s%d", cep->usrdevicename, cep->usrdeviceunit);
1058
1059	I4B_PREP_EVNT(evnt, I4B_MON_CONNECT_CODE);
1060	I4B_PUT_4B(evnt, I4B_MON_CONNECT_TSTAMP, (long)now);
1061	I4B_PUT_4B(evnt, I4B_MON_CONNECT_DIR, cep->direction == DIR_OUT ? 1 : 0);
1062	I4B_PUT_4B(evnt, I4B_MON_CONNECT_CTRL, cep->isdncontrollerused);
1063	I4B_PUT_4B(evnt, I4B_MON_CONNECT_CHANNEL, cep->isdnchannelused);
1064	I4B_PUT_STR(evnt, I4B_MON_CONNECT_CFGNAME, cep->name);
1065	I4B_PUT_STR(evnt, I4B_MON_CONNECT_DEVNAME, devnam);
1066
1067	if (cep->direction == DIR_OUT)
1068	{
1069		I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->remote_phone_dialout);
1070		I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_dialout);
1071	}
1072	else
1073	{
1074		I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->real_phone_incoming);
1075		I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->local_phone_incoming);
1076	}
1077	monitor_broadcast(mask, evnt, sizeof evnt);
1078}
1079
1080/*---------------------------------------------------------------------------
1081 * Post a disconnect event
1082 *---------------------------------------------------------------------------*/
1083void
1084monitor_evnt_disconnect(struct cfg_entry *cep)
1085{
1086	u_int8_t evnt[I4B_MON_DISCONNECT_SIZE];
1087	int mask;
1088	time_t now;
1089
1090	mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1091
1092	if (!anybody(mask))
1093		return;
1094
1095	time(&now);
1096
1097	I4B_PREP_EVNT(evnt, I4B_MON_DISCONNECT_CODE);
1098	I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_TSTAMP, (long)now);
1099	I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CTRL, cep->isdncontrollerused);
1100	I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CHANNEL, cep->isdnchannelused);
1101
1102	monitor_broadcast(mask, evnt, sizeof evnt);
1103}
1104
1105/*---------------------------------------------------------------------------
1106 * Post an up/down event
1107 *---------------------------------------------------------------------------*/
1108void
1109monitor_evnt_updown(struct cfg_entry *cep, int up)
1110{
1111	u_int8_t evnt[I4B_MON_UPDOWN_SIZE];
1112	int mask;
1113	time_t now;
1114
1115	mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
1116
1117	if (!anybody(mask))
1118		return;
1119
1120	time(&now);
1121
1122	I4B_PREP_EVNT(evnt, I4B_MON_UPDOWN_CODE);
1123	I4B_PUT_4B(evnt, I4B_MON_UPDOWN_TSTAMP, (long)now);
1124	I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CTRL, cep->isdncontrollerused);
1125	I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CHANNEL, cep->isdnchannelused);
1126	I4B_PUT_4B(evnt, I4B_MON_UPDOWN_ISUP, up);
1127
1128	monitor_broadcast(mask, evnt, sizeof evnt);
1129}
1130
1131/*---------------------------------------------------------------------------
1132 * Post a Layer1/2 status change event
1133 *---------------------------------------------------------------------------*/
1134void
1135monitor_evnt_l12stat(int controller, int layer, int state)
1136{
1137	u_int8_t evnt[I4B_MON_L12STAT_SIZE];
1138	time_t now;
1139
1140	if (!anybody(I4B_CA_EVNT_I4B))
1141		return;
1142
1143	time(&now);
1144
1145	I4B_PREP_EVNT(evnt, I4B_MON_L12STAT_CODE);
1146	I4B_PUT_4B(evnt, I4B_MON_L12STAT_TSTAMP, (long)now);
1147	I4B_PUT_4B(evnt, I4B_MON_L12STAT_CTRL, controller);
1148	I4B_PUT_4B(evnt, I4B_MON_L12STAT_LAYER, layer);
1149	I4B_PUT_4B(evnt, I4B_MON_L12STAT_STATE, state);
1150
1151	monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1152}
1153
1154/*---------------------------------------------------------------------------
1155 * Post a TEI change event
1156 *---------------------------------------------------------------------------*/
1157void
1158monitor_evnt_tei(int controller, int tei)
1159{
1160	u_int8_t evnt[I4B_MON_TEI_SIZE];
1161	time_t now;
1162
1163	if (!anybody(I4B_CA_EVNT_I4B))
1164		return;
1165
1166	time(&now);
1167
1168	I4B_PREP_EVNT(evnt, I4B_MON_TEI_CODE);
1169	I4B_PUT_4B(evnt, I4B_MON_TEI_TSTAMP, (long)now);
1170	I4B_PUT_4B(evnt, I4B_MON_TEI_CTRL, controller);
1171	I4B_PUT_4B(evnt, I4B_MON_TEI_TEI, tei);
1172
1173	monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1174}
1175
1176/*---------------------------------------------------------------------------
1177 * Post an accounting event
1178 *---------------------------------------------------------------------------*/
1179void
1180monitor_evnt_acct(struct cfg_entry *cep)
1181{
1182	u_int8_t evnt[I4B_MON_ACCT_SIZE];
1183	time_t now;
1184
1185	if (!anybody(I4B_CA_EVNT_I4B))
1186		return;
1187
1188	time(&now);
1189
1190	I4B_PREP_EVNT(evnt, I4B_MON_ACCT_CODE);
1191	I4B_PUT_4B(evnt, I4B_MON_ACCT_TSTAMP, (long)now);
1192
1193	I4B_PUT_4B(evnt, I4B_MON_ACCT_CTRL,   cep->isdncontrollerused);
1194	I4B_PUT_4B(evnt, I4B_MON_ACCT_CHAN,   cep->isdnchannelused);
1195	I4B_PUT_4B(evnt, I4B_MON_ACCT_OBYTES, cep->outbytes);
1196	I4B_PUT_4B(evnt, I4B_MON_ACCT_OBPS,   cep->outbps);
1197	I4B_PUT_4B(evnt, I4B_MON_ACCT_IBYTES, cep->inbytes);
1198	I4B_PUT_4B(evnt, I4B_MON_ACCT_IBPS,   cep->inbps);
1199
1200	monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
1201}
1202
1203/*---------------------------------------------------------------------------
1204 * read from a socket
1205 *---------------------------------------------------------------------------*/
1206static ssize_t
1207sock_read(int fd, void *buf, size_t nbytes)
1208{
1209	size_t nleft;
1210	ssize_t nread;
1211	unsigned char *ptr;
1212
1213	ptr = buf;
1214	nleft = nbytes;
1215
1216	while(nleft > 0)
1217	{
1218		if ((nread = read(fd, ptr, nleft)) < 0)
1219		{
1220			if (errno == EINTR)
1221			{
1222				nread = 0;
1223			}
1224			else
1225			{
1226				return(-1);
1227			}
1228		}
1229		else if (nread == 0)
1230		{
1231			break; /* EOF */
1232		}
1233
1234		nleft -= nread;
1235		ptr += nread;
1236	}
1237	return(nbytes - nleft);
1238}
1239
1240/*---------------------------------------------------------------------------
1241 * write to a socket
1242 *---------------------------------------------------------------------------*/
1243static ssize_t
1244sock_write(int fd, void *buf, size_t nbytes)
1245{
1246	size_t nleft;
1247	ssize_t nwritten;
1248	unsigned char *ptr;
1249
1250	ptr = buf;
1251	nleft = nbytes;
1252
1253	while(nleft > 0)
1254	{
1255		if ((nwritten = write(fd, ptr, nleft)) <= 0)
1256		{
1257			if (errno == EINTR)
1258			{
1259				nwritten = 0;
1260			}
1261			else
1262			{
1263				return(-1);
1264			}
1265		}
1266
1267		nleft -= nwritten;
1268		ptr += nwritten;
1269	}
1270	return(nbytes);
1271}
1272
1273struct monitor_rights * monitor_next_rights(const struct monitor_rights *r)
1274{
1275	if (r == NULL)
1276		return TAILQ_FIRST(&rights);
1277	else
1278		return TAILQ_NEXT(r, list);
1279}
1280
1281#endif	/* I4B_EXTERNAL_MONITOR */
1282