1/*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 *	i4b daemon - misc support routines
28 *	----------------------------------
29 *
30 *	$Id: support.c,v 1.15 2009/04/16 05:56:32 lukem Exp $
31 *
32 * $FreeBSD$
33 *
34 *      last edit-date: [Wed Oct  4 18:24:27 2000]
35 *
36 *---------------------------------------------------------------------------*/
37
38#include "isdnd.h"
39
40static int isvalidtime(struct cfg_entry *cep);
41
42static SLIST_HEAD(, isdn_ctrl_state) isdn_ctrl_list =
43    SLIST_HEAD_INITIALIZER(isdn_ctrl_list);
44
45static SIMPLEQ_HEAD(, cfg_entry) cfg_entry_list =
46    SIMPLEQ_HEAD_INITIALIZER(cfg_entry_list);
47
48/*---------------------------------------------------------------------------*
49 *	find an active entry by driver type and driver unit
50 *---------------------------------------------------------------------------*/
51struct cfg_entry *
52find_active_entry_by_driver(int drivertype, int driverunit)
53{
54	struct cfg_entry *cep = NULL;
55
56	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
57
58		if (!((cep->usrdevice == drivertype) &&
59		     (cep->usrdeviceunit == driverunit)))
60		{
61			continue;
62		}
63
64		/* check time interval */
65
66		if (isvalidtime(cep) == 0)
67		{
68			DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d, time not valid!", cep->index)));
69			continue;
70		}
71
72		/* found */
73
74		if (cep->cdid == CDID_UNUSED)
75		{
76			DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_UNUSED !",
77				cep->index, cep->usrdevicename, driverunit)));
78			return(NULL);
79		}
80		else if (cep->cdid == CDID_RESERVED)
81		{
82			DBGL(DL_MSG, (logit(LL_DBG, "find_active_entry_by_driver: entry %d [%s%d], cdid=CDID_RESERVED!",
83				cep->index, cep->usrdevicename, driverunit)));
84			return(NULL);
85		}
86		return(cep);
87	}
88	return(NULL);
89}
90
91/*---------------------------------------------------------------------------*
92 *	find entry by drivertype and driverunit and setup for dialing out
93 *---------------------------------------------------------------------------*/
94struct cfg_entry *
95find_by_device_for_dialout(int drivertype, int driverunit)
96{
97	struct cfg_entry *cep;
98
99	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
100
101		/* compare driver type and unit */
102
103		if (!((cep->usrdevice == drivertype) &&
104		     (cep->usrdeviceunit == driverunit)))
105		{
106			continue;
107		}
108
109		/* check time interval */
110
111		if (isvalidtime(cep) == 0)
112		{
113			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, time not valid!", cep->index)));
114			continue;
115		}
116
117		/* found, check if already reserved */
118
119		if (cep->cdid == CDID_RESERVED)
120		{
121			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", cep->index)));
122			return(NULL);
123		}
124
125		/* check if this entry is already in use ? */
126
127		if (cep->cdid != CDID_UNUSED)
128		{
129			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", cep->index)));
130			return(NULL);
131		}
132
133		if ((setup_dialout(cep)) == GOOD)
134		{
135			/* found an entry to be used for calling out */
136
137			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: found entry %d!", cep->index)));
138			return(cep);
139		}
140		else
141		{
142			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", cep->index)));
143			return(NULL);
144		}
145	}
146
147	DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialout: no entry found!")));
148	return(NULL);
149}
150
151/*---------------------------------------------------------------------------*
152 *	find entry by drivertype and driverunit and setup for dialing out
153 *---------------------------------------------------------------------------*/
154struct cfg_entry *
155find_by_device_for_dialoutnumber(int drivertype, int driverunit, int cmdlen, char *cmd)
156{
157	struct cfg_entry *cep;
158	int j;
159
160	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
161
162		/* compare driver type and unit */
163
164		if (!((cep->usrdevice == drivertype) &&
165		     (cep->usrdeviceunit == driverunit)))
166		{
167			continue;
168		}
169
170		/* check time interval */
171
172		if (isvalidtime(cep) == 0)
173		{
174			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, time not valid!", cep->index)));
175			continue;
176		}
177
178		/* found, check if already reserved */
179
180		if (cep->cdid == CDID_RESERVED)
181		{
182			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid reserved!", cep->index)));
183			return(NULL);
184		}
185
186		/* check if this entry is already in use ? */
187
188		if (cep->cdid != CDID_UNUSED)
189		{
190			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, cdid in use", cep->index)));
191			return(NULL);
192		}
193
194		/* check number and copy to cep->remote_numbers[] */
195
196		for (j = 0; j < cmdlen; j++)
197		{
198			if (!(isdigit((unsigned char)*(cmd+j))))
199			{
200				DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, dial string contains non-digit at pos %d", cep->index, j)));
201				return(NULL);
202			}
203			/* fill in number to dial */
204			cep->remote_numbers[0].number[j] = *(cmd+j);
205		}
206		cep->remote_numbers[0].number[j] = '\0';
207		cep->remote_numbers_count = 1;
208
209		if ((setup_dialout(cep)) == GOOD)
210		{
211			/* found an entry to be used for calling out */
212
213			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: found entry %d!", cep->index)));
214			return(cep);
215		}
216		else
217		{
218			DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: entry %d, setup_dialout() failed!", cep->index)));
219			return(NULL);
220		}
221	}
222
223	DBGL(DL_MSG, (logit(LL_DBG, "find_by_device_for_dialoutnumber: no entry found!")));
224	return(NULL);
225}
226
227/*---------------------------------------------------------------------------*
228 *	find entry by drivertype and driverunit and setup for dialing out
229 *---------------------------------------------------------------------------*/
230int
231setup_dialout(struct cfg_entry *cep)
232{
233	struct isdn_ctrl_state *ctrl;
234	int i;
235
236	if (cep->isdncontroller < 0) {
237		/* we are free to choose a controller */
238		for (ctrl = get_first_ctrl_state(); ctrl; ctrl = NEXT_CTRL(ctrl)) {
239			if (get_controller_state(ctrl) != CTRL_UP)
240				continue;
241			switch (cep->isdnchannel) {
242			case CHAN_ANY:
243				for (i = 0; i < ctrl->nbch; i++)
244				{
245					if (ret_channel_state(ctrl, i)
246					    == CHAN_IDLE)
247						break;
248				}
249				if (i == ctrl->nbch)
250					continue;
251				break;
252			default:
253				if (ret_channel_state(ctrl, cep->isdnchannel)
254				    != CHAN_IDLE)
255					continue;
256				break;
257			}
258			/* this controller looks ok */
259			break;
260		}
261	} else {
262		/* fixed controller in config, use that */
263		ctrl = find_ctrl_state(cep->isdncontroller);
264	}
265
266	if (ctrl == NULL)
267		return (ERROR);
268
269	/* check controller operational */
270
271	if (get_controller_state(ctrl) != CTRL_UP)
272	{
273		DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name)));
274		return(ERROR);
275	}
276
277	cep->isdncontrollerused = ctrl->isdnif;
278
279	/* check channel available */
280
281	switch (cep->isdnchannel)
282	{
283	case CHAN_ANY:
284		for (i = 0; i < ctrl->nbch; i++)
285		{
286			if (ret_channel_state(ctrl, i) == CHAN_IDLE)
287				break;
288		}
289		if (i == ctrl->nbch)
290		{
291			DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
292			return(ERROR);
293		}
294		cep->isdnchannelused = CHAN_ANY;
295		break;
296
297	default:
298		if (ret_channel_state(ctrl, cep->isdnchannel) != CHAN_IDLE)
299		{
300			DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
301			return(ERROR);
302		}
303		cep->isdnchannelused = cep->isdnchannel;
304		break;
305	}
306
307	DBGL(DL_MSG, (logit(LL_DBG, "setup_dialout: entry %s ok!", cep->name)));
308
309	/* preset disconnect cause */
310
311	SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
312	SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL);
313
314	return(GOOD);
315}
316
317/*---------------------------------------------------------------------------*
318 *	find entry by drivertype and driverunit
319 *---------------------------------------------------------------------------*/
320struct cfg_entry *
321get_cep_by_driver(int drivertype, int driverunit)
322{
323	struct cfg_entry *cep;
324
325	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
326
327		if (!((cep->usrdevice == drivertype) &&
328		     (cep->usrdeviceunit == driverunit)))
329		{
330			continue;
331		}
332
333		/* check time interval */
334
335		if (isvalidtime(cep) == 0)
336		{
337			DBGL(DL_MSG, (logit(LL_DBG, "get_cep_by_driver: entry %d, time not valid!", cep->index)));
338			continue;
339		}
340
341		DBGL(DL_MSG, (logit(LL_DBG, "get_cep_by_driver: found entry %d!", cep->index)));
342		return(cep);
343	}
344	return(NULL);
345}
346
347/*---------------------------------------------------------------------------*
348 *	find a matching entry for an incoming call
349 *
350 *	- not found/no match: log output with LL_CHD and return NULL
351 *	- found/match: make entry in free cep, return address
352 *---------------------------------------------------------------------------*/
353struct cfg_entry *
354find_matching_entry_incoming(msg_connect_ind_t *mp, int len)
355{
356	struct cfg_entry *cep = NULL;
357	static const char resvd_type[] = "reserverd";
358	static const char no_type[] = "no type";
359	static const char * const numbering_types[] = {
360		"unknown",
361		"international",
362		"national",
363		"network specific",
364		"subscriber",
365		"abbreviated",
366		resvd_type,
367		resvd_type,
368		resvd_type
369	};
370	const char * ntype;
371	int i;
372
373	/* older kernels do not deliver all the information */
374	if (((u_int8_t*)&mp->type_plan - (u_int8_t*)mp + (int)sizeof(mp->type_plan)) <= len) {
375		ntype = numbering_types[(mp->type_plan & 0x70)>>4];
376	} else {
377		ntype = no_type;
378	}
379
380	/* check for CW (call waiting) early */
381
382	if (mp->channel == CHAN_NO)
383	{
384		if (aliasing)
385	        {
386			const char *src_tela = "ERROR-src_tela";
387			const char *dst_tela = "ERROR-dst_tela";
388
389	                src_tela = get_alias(mp->src_telno);
390	                dst_tela = get_alias(mp->dst_telno);
391
392			logit(LL_CHD, "%05d <unknown> CW from %s (%s) to %s (%s) (no channel free)",
393				mp->header.cdid, src_tela, ntype, dst_tela, mp->display);
394		}
395		else
396		{
397			logit(LL_CHD, "%05d <unknown> call waiting from %s (%s) to %s (%s) (no channel free)",
398				mp->header.cdid, mp->src_telno, ntype, mp->dst_telno, mp->display);
399		}
400		return(NULL);
401	}
402
403	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
404
405		int n;
406		struct isdn_ctrl_state *ctrl;
407
408		/* check my number */
409
410		if (strncmp(cep->local_phone_incoming, mp->dst_telno, strlen(cep->local_phone_incoming)))
411		{
412			DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s",
413				cep->index, cep->local_phone_incoming, mp->dst_telno)));
414			continue;
415		}
416
417		/* check all allowed remote number's for this entry */
418
419		for (n = 0; n < cep->incoming_numbers_count; n++)
420		{
421			incoming_number_t *in = &cep->remote_phone_incoming[n];
422			if (in->number[0] == '*')
423				break;
424			if (strncmp(in->number, mp->src_telno, strlen(in->number)))
425			{
426				DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s",
427					cep->index, in->number, mp->src_telno)));
428			}
429			else
430				break;
431		}
432		if (n >= cep->incoming_numbers_count)
433			continue;
434
435		/* check b protocol */
436
437		if (cep->b1protocol != mp->bprot)
438		{
439			DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d",
440				cep->index, cep->b1protocol, mp->bprot)));
441			continue;
442		}
443
444		/* is this entry currently in use ? */
445
446		if (cep->cdid != CDID_UNUSED)
447		{
448			if (cep->cdid == CDID_RESERVED)
449			{
450				DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", cep->index)));
451			}
452			else if (cep->dialin_reaction == REACT_ACCEPT
453				 && cep->dialouttype == DIALOUT_CALLEDBACK)
454			{
455				/*
456				 * We might consider doing this even if this is
457				 * not a calledback config entry - BUT: there are
458				 * severe race conditions and timinig problems
459				 * ex. if both sides run I4B with no callback
460				 * delay - both may shutdown the outgoing call
461				 * and never be able to establish a connection.
462				 * In the called-back case this should not happen.
463				 */
464				DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", cep->index, cep->cdid)));
465
466				/* save the current call state, we're going to overwrite it with the
467				 * new incoming state below... */
468				cep->saved_call.cdid = cep->cdid;
469				cep->saved_call.controller = cep->isdncontrollerused;
470				cep->saved_call.channel = cep->isdnchannelused;
471			}
472			else
473			{
474				DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", cep->index)));
475				continue;	/* yes, next */
476			}
477		}
478
479		/* check controller value ok */
480		ctrl = find_ctrl_state(mp->controller);
481
482		if (ctrl == NULL)
483		{
484			logit(LL_CHD, "%05d %s incoming call with invalid controller %d",
485                        	mp->header.cdid, cep->name, mp->controller);
486			return(NULL);
487		}
488
489		/* check controller marked up */
490
491		if (get_controller_state(ctrl) != CTRL_UP)
492		{
493			logit(LL_CHD, "%05d %s incoming call, controller %d DOWN!",
494                        	mp->header.cdid, cep->name, mp->controller);
495			return(NULL);
496		}
497
498		/* check channel he wants */
499
500		switch (mp->channel)
501		{
502		case CHAN_ANY:
503			for (i = 0; i < ctrl->nbch; i++)
504				if (ret_channel_state(ctrl, i) == CHAN_IDLE)
505					break;
506			if (i == ctrl->nbch)
507			{
508				logit(LL_CHD, "%05d %s incoming call, no channel free!",
509					mp->header.cdid, cep->name);
510				return(NULL);
511			}
512			break;
513
514		case CHAN_NO:
515			logit(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!",
516				mp->header.cdid, cep->name);
517			return(NULL);
518			break;
519
520		default:
521			if ((ret_channel_state(ctrl, mp->channel)) != CHAN_IDLE)
522			{
523				logit(LL_CHD, "%05d %s incoming call, channel B%d not free!",
524					mp->header.cdid, cep->name, mp->channel);
525				return(NULL);
526			}
527			break;
528		}
529
530		/* check time interval */
531
532		if (isvalidtime(cep) == 0)
533		{
534			DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, time not valid!", cep->index)));
535			continue;
536		}
537
538		/* found a matching entry */
539
540		cep->cdid = mp->header.cdid;
541		cep->isdncontrollerused = mp->controller;
542		cep->isdnchannelused = mp->channel;
543/*XXX*/		cep->disc_cause = 0;
544
545		/* cp number to real one used */
546
547		strlcpy(cep->real_phone_incoming, mp->src_telno,
548		    sizeof(cep->real_phone_incoming));
549
550		/* copy display string */
551
552		strlcpy(cep->display, mp->display, sizeof(cep->display));
553
554		/* entry currently down ? */
555
556		if (cep->state == ST_DOWN)
557		{
558			msg_updown_ind_t mui;
559
560			/* set interface up */
561
562			DBGL(DL_MSG, (logit(LL_DBG, "find_matching_entry_incoming: entry %d, ", cep->index)));
563
564			mui.driver = cep->usrdevice;
565			mui.driver_unit = cep->usrdeviceunit;
566			mui.updown = SOFT_ENA;
567
568			if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
569			{
570				logit(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
571				error_exit(1, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
572			}
573
574			cep->down_retry_count = 0;
575			cep->state = ST_IDLE;
576		}
577		return(cep);
578	}
579
580	if (aliasing)
581        {
582		const char *src_tela = "ERROR-src_tela";
583		const char *dst_tela = "ERROR-dst_tela";
584
585                src_tela = get_alias(mp->src_telno);
586                dst_tela = get_alias(mp->dst_telno);
587
588		logit(LL_CHD, "%05d Call from %s (%s) to %s (%s)",
589			mp->header.cdid, src_tela, ntype, dst_tela, mp->display);
590	}
591	else
592	{
593		logit(LL_CHD, "%05d <unknown> incoming call from %s (%s) to %s (%s)",
594			mp->header.cdid, mp->src_telno, ntype, mp->dst_telno, mp->display);
595	}
596	return(NULL);
597}
598
599/*---------------------------------------------------------------------------*
600 *	return address of ACTIVE config entry by controller and channel
601 *---------------------------------------------------------------------------*/
602struct cfg_entry *
603get_cep_by_cc(int ctrlr, int chan)
604{
605	struct cfg_entry *cep;
606	struct isdn_ctrl_state *cts;
607
608	cts = find_ctrl_state(ctrlr);
609	if (cts ==  NULL)
610		return(NULL);
611
612	if (chan < 0 || chan >= cts->nbch)
613		return(NULL);
614
615	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
616
617		if ((cep->cdid != CDID_UNUSED)		&&
618		   (cep->cdid != CDID_RESERVED)		&&
619		   (cep->isdnchannelused == chan)	&&
620		   (cep->isdncontrollerused == ctrlr)	&&
621		   ((ret_channel_state(cts, chan)) == CHAN_RUN))
622		{
623			return (cep);
624		}
625	}
626	return(NULL);
627}
628
629/*---------------------------------------------------------------------------*
630 *	return address of config entry identified by cdid
631 *---------------------------------------------------------------------------*/
632struct cfg_entry *
633get_cep_by_cdid(int cdid)
634{
635	struct cfg_entry *cep;
636
637	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
638		if (cep->cdid == cdid || cep->saved_call.cdid == cdid)
639			return(cep);
640	}
641	return(NULL);
642}
643
644/*---------------------------------------------------------------------------*
645 *	process AOCD charging messages
646 *---------------------------------------------------------------------------*/
647void
648handle_charge(struct cfg_entry *cep)
649{
650	time_t now = time(NULL);
651
652	if (cep->aoc_last == 0)		/* no last timestamp yet ? */
653	{
654		cep->aoc_last = now;	/* add time stamp */
655	}
656	else if (cep->aoc_now == 0)	/* no current timestamp yet ? */
657	{
658		cep->aoc_now = now;	/* current timestamp */
659	}
660	else
661	{
662		cep->aoc_last = cep->aoc_now;
663		cep->aoc_now = now;
664		cep->aoc_diff = cep->aoc_now - cep->aoc_last;
665		cep->aoc_valid = AOC_VALID;
666	}
667
668#ifdef USE_CURSES
669	if (do_fullscreen)
670		display_charge(cep);
671#endif
672
673#ifdef I4B_EXTERNAL_MONITOR
674	if (do_monitor && accepted)
675		monitor_evnt_charge(cep, cep->charge, 0);
676#endif
677
678	if (cep->aoc_valid == AOC_VALID)
679	{
680		if (cep->aoc_diff != cep->unitlength)
681		{
682			DBGL(DL_MSG, (logit(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff)));
683
684			cep->unitlength = cep->aoc_diff;
685
686			unitlen_chkupd(cep);
687		}
688		else
689		{
690#ifdef NOTDEF
691			DBGL(DL_MSG, (logit(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
692#endif
693		}
694	}
695}
696
697/*---------------------------------------------------------------------------*
698 *	update kernel idle_time, earlyhup_time and unitlen_time
699 *---------------------------------------------------------------------------*/
700void
701unitlen_chkupd(struct cfg_entry *cep)
702{
703	msg_timeout_upd_t tupd;
704
705	tupd.cdid = cep->cdid;
706
707	/* init the short hold data based on the shorthold algorithm type */
708
709	switch (cep->shorthold_algorithm)
710	{
711	case SHA_FIXU:
712		tupd.shorthold_data.shorthold_algorithm = SHA_FIXU;
713		tupd.shorthold_data.unitlen_time = cep->unitlength;
714		tupd.shorthold_data.idle_time = cep->idle_time_out;
715		tupd.shorthold_data.earlyhup_time = cep->earlyhangup;
716		break;
717
718	case SHA_VARU:
719		tupd.shorthold_data.shorthold_algorithm = SHA_VARU;
720		tupd.shorthold_data.unitlen_time = cep->unitlength;
721		tupd.shorthold_data.idle_time = cep->idle_time_out;
722		tupd.shorthold_data.earlyhup_time = 0;
723		break;
724	default:
725		logit(LL_ERR, "unitlen_chkupd bad shorthold_algorithm %d", cep->shorthold_algorithm );
726		return;
727		break;
728	}
729
730	if ((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0)
731	{
732		logit(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
733		error_exit(1, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
734	}
735}
736
737/*--------------------------------------------------------------------------*
738 *	this is intended to be called by do_exit and closes down all
739 *	active connections before the daemon exits or is reconfigured.
740 *--------------------------------------------------------------------------*/
741void
742close_allactive(void)
743{
744	int i, j;
745	struct cfg_entry *cep = NULL;
746	struct isdn_ctrl_state *cst;
747
748	j = 0;
749
750	SLIST_FOREACH(cst, &isdn_ctrl_list, ctrlq) {
751
752		if ((get_controller_state(cst)) != CTRL_UP)
753			continue;
754
755		for (i = 0; i < cst->nbch; i++)
756		{
757			if ((ret_channel_state(cst, i)) == CHAN_RUN)
758			{
759				if ((cep = get_cep_by_cc(cst->isdnif, i))
760				    != NULL)
761				{
762#ifdef USE_CURSES
763					if (do_fullscreen)
764						display_disconnect(cep);
765#endif
766#ifdef I4B_EXTERNAL_MONITOR
767					monitor_evnt_disconnect(cep);
768#endif
769					next_state(cep, EV_DRQ);
770					j++;
771				}
772			}
773		}
774	}
775
776	if (j)
777	{
778		logit(LL_DMN, "close_allactive: waiting for all connections terminated");
779		sleep(5);
780	}
781
782	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq) {
783		if (cep->autoupdown & AUTOUPDOWN_DONE) {
784			struct ifreq ifr;
785			int r, s;
786
787			s = socket(AF_INET, SOCK_DGRAM, 0);
788			memset(&ifr, 0, sizeof ifr);
789			snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s%d", cep->usrdevicename, cep->usrdeviceunit);
790			r = ioctl(s, SIOCGIFFLAGS, &ifr);
791			if (r >= 0) {
792				ifr.ifr_flags &= ~IFF_UP;
793				ioctl(s, SIOCSIFFLAGS, &ifr);
794			}
795			close(s);
796			cep->autoupdown &= ~AUTOUPDOWN_DONE;
797		}
798	}
799
800}
801
802/*--------------------------------------------------------------------------*
803 *	set an interface up
804 *--------------------------------------------------------------------------*/
805void
806if_up(struct cfg_entry *cep)
807{
808	msg_updown_ind_t mui;
809
810	/* set interface up */
811
812	DBGL(DL_MSG, (logit(LL_DBG, "if_up: taking %s%d up", cep->usrdevicename, cep->usrdeviceunit)));
813
814	mui.driver = cep->usrdevice;
815	mui.driver_unit = cep->usrdeviceunit;
816	mui.updown = SOFT_ENA;
817
818	if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
819	{
820		logit(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
821		error_exit(1, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
822	}
823	cep->down_retry_count = 0;
824
825#ifdef USE_CURSES
826	if (do_fullscreen)
827		display_updown(cep, 1);
828#endif
829#ifdef I4B_EXTERNAL_MONITOR
830	monitor_evnt_updown(cep, 1);
831#endif
832
833}
834
835/*--------------------------------------------------------------------------*
836 *	set an interface down
837 *--------------------------------------------------------------------------*/
838void
839if_down(struct cfg_entry *cep)
840{
841	msg_updown_ind_t mui;
842
843	/* set interface up */
844
845	DBGL(DL_MSG, (logit(LL_DBG, "if_down: taking %s%d down", cep->usrdevicename, cep->usrdeviceunit)));
846
847	mui.driver = cep->usrdevice;
848	mui.driver_unit = cep->usrdeviceunit;
849	mui.updown = SOFT_DIS;
850
851	if ((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
852	{
853		logit(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
854		error_exit(1, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
855	}
856	cep->went_down_time = time(NULL);
857	cep->down_retry_count = 0;
858
859#ifdef USE_CURSES
860	if (do_fullscreen)
861		display_updown(cep, 0);
862#endif
863#ifdef I4B_EXTERNAL_MONITOR
864	monitor_evnt_updown(cep, 0);
865#endif
866
867}
868
869/*--------------------------------------------------------------------------*
870 *	send a dial response to (an interface in) the kernel
871 *--------------------------------------------------------------------------*/
872void
873dialresponse(struct cfg_entry *cep, int dstat)
874{
875	msg_dialout_resp_t mdr;
876
877	static const char *stattab[] = {
878		"normal condition",
879		"temporary failure",
880		"permanent failure",
881		"dialout not allowed"
882	};
883
884	if (dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
885	{
886		logit(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
887		return;
888	}
889
890	mdr.driver = cep->usrdevice;
891	mdr.driver_unit = cep->usrdeviceunit;
892	mdr.stat = dstat;
893	mdr.cause = cep->disc_cause;
894
895	if ((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0)
896	{
897		logit(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
898		error_exit(1, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
899	}
900
901	DBGL(DL_DRVR, (logit(LL_DBG, "dialresponse: sent [%s]", stattab[dstat])));
902}
903
904/*--------------------------------------------------------------------------*
905 *	screening/presentation indicator
906 *--------------------------------------------------------------------------*/
907void
908handle_scrprs(int cdid, int scr, int prs, const char *caller)
909{
910	/* screening indicator */
911
912	if (scr < SCR_NONE || scr > SCR_NET)
913	{
914		logit(LL_ERR, "msg_connect_ind: invalid screening indicator value %d!", scr);
915	}
916	else
917	{
918		static const char *scrtab[] = {
919			"no screening indicator",
920			"sreening user provided, not screened",
921			"screening user provided, verified & passed",
922			"screening user provided, verified & failed",
923			"screening network provided", };
924
925		if (extcallattr)
926		{
927			logit(LL_CHD, "%05d %s %s", cdid, caller, scrtab[scr]);
928		}
929		else
930		{
931			DBGL(DL_MSG, (logit(LL_DBG, "%s - %s", caller, scrtab[scr])));
932		}
933	}
934
935	/* presentation indicator */
936
937	if (prs < PRS_NONE || prs > PRS_RESERVED)
938	{
939		logit(LL_ERR, "msg_connect_ind: invalid presentation indicator value %d!", prs);
940	}
941	else
942	{
943		static const char *prstab[] = {
944			"no presentation indicator",
945			"presentation allowed",
946			"presentation restricted",
947			"number not available due to interworking",
948			"reserved presentation value" };
949
950		if (extcallattr)
951		{
952			logit(LL_CHD, "%05d %s %s", cdid, caller, prstab[prs]);
953		}
954		else
955		{
956			DBGL(DL_MSG, (logit(LL_DBG, "%s - %s", caller, prstab[prs])));
957		}
958	}
959}
960
961/*--------------------------------------------------------------------------*
962 *	check if the time is valid for an entry
963 *--------------------------------------------------------------------------*/
964static int
965isvalidtime(struct cfg_entry *cep)
966{
967	time_t t;
968	struct tm *tp;
969
970	if (cep->day == 0)
971		return(1);
972
973	t = time(NULL);
974	tp = localtime(&t);
975
976	if (cep->day & HD)
977	{
978		if (isholiday(tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900))
979		{
980			DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: holiday %d.%d.%d", tp->tm_mday, (tp->tm_mon)+1, (tp->tm_year)+1900)));
981			goto dayok;
982		}
983	}
984
985	if (cep->day & (1 << tp->tm_wday))
986	{
987		DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: day match")));
988		goto dayok;
989	}
990
991	return(0);
992
993dayok:
994	if (cep->fromhr==0 && cep->frommin==0 && cep->tohr==0 && cep->tomin==0)
995	{
996		DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: no time specified, match!")));
997		return(1);
998	}
999
1000	if (cep->tohr < cep->fromhr)
1001	{
1002		/* before 00:00 */
1003
1004		if ( (tp->tm_hour > cep->fromhr) ||
1005		    (tp->tm_hour == cep->fromhr && tp->tm_min > cep->frommin) )
1006		{
1007			DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t<f-1, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1008				cep->fromhr, cep->frommin,
1009				cep->tohr, cep->tomin,
1010				tp->tm_hour, tp->tm_min)));
1011
1012			return(1);
1013		}
1014
1015		/* after 00:00 */
1016
1017		if ( (tp->tm_hour < cep->tohr) ||
1018		    (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) )
1019		{
1020			DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t<f-2, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1021				cep->fromhr, cep->frommin,
1022				cep->tohr, cep->tomin,
1023				tp->tm_hour, tp->tm_min)));
1024
1025			return(1);
1026		}
1027	}
1028	else if (cep->fromhr == cep->tohr)
1029	{
1030		if (tp->tm_min >= cep->frommin && tp->tm_min < cep->tomin)
1031		{
1032			DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: f=t, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1033				cep->fromhr, cep->frommin,
1034				cep->tohr, cep->tomin,
1035				tp->tm_hour, tp->tm_min)));
1036
1037			return(1);
1038		}
1039	}
1040	else
1041	{
1042		if ((tp->tm_hour > cep->fromhr && tp->tm_hour < cep->tohr) ||
1043		   (tp->tm_hour == cep->fromhr && tp->tm_min >= cep->frommin) ||
1044		   (tp->tm_hour == cep->tohr && tp->tm_min < cep->tomin) )
1045		{
1046			DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: t>f, spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, match!",
1047				cep->fromhr, cep->frommin,
1048				cep->tohr, cep->tomin,
1049				tp->tm_hour, tp->tm_min)));
1050			return(1);
1051		}
1052	}
1053	DBGL(DL_MSG, (logit(LL_DBG, "isvalidtime: spec=%02d:%02d-%02d:%02d, curr=%02d:%02d, no match!",
1054			cep->fromhr, cep->frommin,
1055			cep->tohr, cep->tomin,
1056			tp->tm_hour, tp->tm_min)));
1057
1058	return(0);
1059}
1060
1061struct cfg_entry *
1062get_first_cfg_entry()
1063{
1064	return (SIMPLEQ_FIRST(&cfg_entry_list));
1065}
1066
1067int count_cfg_entries()
1068{
1069	int cnt;
1070	struct cfg_entry *cfe;
1071
1072	cnt = 0;
1073	SIMPLEQ_FOREACH(cfe, &cfg_entry_list, cfgq)
1074		cnt++;
1075
1076	return (cnt);
1077}
1078
1079struct cfg_entry *
1080find_cfg_entry(int idx)
1081{
1082	struct cfg_entry *cep;
1083
1084	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq)
1085		if (cep->index == idx)
1086			return cep;
1087	return NULL;
1088}
1089
1090int
1091add_cfg_entry(struct cfg_entry *cfe)
1092{
1093	struct cfg_entry *cep;
1094	int max = -1;
1095
1096	SIMPLEQ_FOREACH(cep, &cfg_entry_list, cfgq)
1097		if (cep->index > max)
1098			max = cep->index;
1099
1100	cfe->index = max;
1101	SIMPLEQ_INSERT_TAIL(&cfg_entry_list, cfe, cfgq);
1102	return max;
1103}
1104
1105void
1106remove_all_cfg_entries()
1107{
1108	struct cfg_entry *cep;
1109
1110	while (!SIMPLEQ_EMPTY(&cfg_entry_list)) {
1111		cep = SIMPLEQ_FIRST(&cfg_entry_list);
1112		SIMPLEQ_REMOVE_HEAD(&cfg_entry_list, cfgq);
1113
1114		if (cep->ppp_expect_name)
1115		    free(cep->ppp_expect_name);
1116		if (cep->ppp_expect_password)
1117		    free(cep->ppp_expect_password);
1118		if (cep->ppp_send_name)
1119		    free(cep->ppp_send_name);
1120		if (cep->ppp_send_password)
1121		    free(cep->ppp_send_password);
1122
1123		free(cep);
1124	}
1125}
1126
1127struct isdn_ctrl_state * get_first_ctrl_state()
1128{
1129	return SLIST_FIRST(&isdn_ctrl_list);
1130}
1131
1132int count_ctrl_states()
1133{
1134	int cnt = 0;
1135	struct isdn_ctrl_state *ctrl;
1136
1137	SLIST_FOREACH(ctrl, &isdn_ctrl_list, ctrlq)
1138		cnt++;
1139
1140	return (cnt);
1141}
1142
1143void remove_all_ctrl_state()
1144{
1145	struct isdn_ctrl_state *ctrl;
1146
1147	while (!SLIST_EMPTY(&isdn_ctrl_list)) {
1148		ctrl = SLIST_FIRST(&isdn_ctrl_list);
1149		SLIST_REMOVE_HEAD(&isdn_ctrl_list, ctrlq);
1150		free(ctrl);
1151	}
1152}
1153
1154struct isdn_ctrl_state *
1155find_ctrl_state(int controller)
1156{
1157	struct isdn_ctrl_state *ctrl;
1158
1159	SLIST_FOREACH(ctrl, &isdn_ctrl_list, ctrlq)
1160		if (ctrl->isdnif == controller)
1161			return ctrl;
1162	return NULL;
1163}
1164
1165int
1166add_ctrl_state(struct isdn_ctrl_state *cstate)
1167{
1168	SLIST_INSERT_HEAD(&isdn_ctrl_list, cstate, ctrlq);
1169	return 0;
1170}
1171
1172int
1173remove_ctrl_state(int controller)
1174{
1175	struct isdn_ctrl_state *ctrl = find_ctrl_state(controller);
1176	struct cfg_entry *cep;
1177	int i;
1178
1179	if (ctrl == NULL)
1180		return 0;
1181
1182	if ((get_controller_state(ctrl)) == CTRL_UP) {
1183
1184		for (i = 0; i < ctrl->nbch; i++)
1185		{
1186			if ((ret_channel_state(ctrl, i)) == CHAN_RUN) {
1187				if ((cep = get_cep_by_cc(controller, i))
1188				    != NULL)
1189				{
1190#ifdef USE_CURSES
1191					if (do_fullscreen)
1192						display_disconnect(cep);
1193#endif
1194#ifdef I4B_EXTERNAL_MONITOR
1195					monitor_evnt_disconnect(cep);
1196#endif
1197					cep->cdid = -1;
1198					cep->isdncontrollerused = -1;
1199					cep->isdnchannelused = -1;
1200					cep->state = ST_IDLE;
1201				}
1202			}
1203		}
1204	}
1205
1206	SLIST_REMOVE(&isdn_ctrl_list, ctrl, isdn_ctrl_state, ctrlq);
1207	return 0;
1208}
1209
1210/* EOF */
1211