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