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 - message from kernel handling routines
28 *	--------------------------------------------------
29 *
30 *	$Id: msghdl.c,v 1.11 2009/04/16 05:56:32 lukem Exp $
31 *
32 * $FreeBSD$
33 *
34 *      last edit-date: [Thu Sep 21 11:11:48 2000]
35 *
36 *---------------------------------------------------------------------------*/
37
38#include "isdnd.h"
39
40#include <sys/socket.h>
41#include <net/if.h>
42#include <net/if_types.h>
43
44#if defined(__FreeBSD__)
45#include <net/if_var.h>
46#endif
47
48#include <netinet/in.h>
49#include <netinet/in_systm.h>
50#include <netinet/in_var.h>
51#include <netinet/ip.h>
52#include <netinet/tcp.h>
53#include <netinet/udp.h>
54#include <netinet/ip_icmp.h>
55
56/*---------------------------------------------------------------------------*
57 *	handle incoming CONNECT_IND (=SETUP) message
58 *---------------------------------------------------------------------------*/
59void
60msg_connect_ind(msg_connect_ind_t *mp, int len)
61{
62	struct cfg_entry *cep;
63	const char *src_tela = "ERROR-src_tela";
64	const char *dst_tela = "ERROR-dst_tela";
65
66#define SRC (aliasing == 0 ? mp->src_telno : src_tela)
67#define DST (aliasing == 0 ? mp->dst_telno : dst_tela)
68
69	if (aliasing)
70	{
71		src_tela = get_alias(mp->src_telno);
72		dst_tela = get_alias(mp->dst_telno);
73	}
74
75	if ((cep = find_matching_entry_incoming(mp, len)) == NULL)
76	{
77		/* log message generated in find_matching_entry_incoming() */
78		sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
79		handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
80		return;
81	}
82
83	if (cep->cdid != CDID_UNUSED && cep->cdid != CDID_RESERVED)
84	{
85		/*
86		 * This is an incoming call on a number we just dialed out.
87		 * Stop our dial-out and accept the incoming call.
88		 */
89		if (cep->saved_call.cdid != CDID_UNUSED &&
90		   cep->saved_call.cdid != CDID_RESERVED)
91		{
92			int cdid;
93
94			/* disconnect old, not new */
95
96			cdid = cep->cdid;
97			cep->cdid = cep->saved_call.cdid;
98			sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
99			cep->cdid = cdid;
100
101			/*
102			 * Shortcut the state machine and mark this
103			 * entry as free
104			 */
105/* XXX */		cep->state = ST_IDLE;	/* this is an invalid	*/
106						/* transition,		*/
107						/* so no next_state()	*/
108			/* we have to wait here for an incoming	*/
109			/* disconnect message !!! (-hm)		*/
110		}
111	}
112
113	if (cep->inout == DIR_OUTONLY)
114	{
115		logit(LL_CHD, "%05d %s incoming call from %s to %s not allowed by configuration!",
116			mp->header.cdid, cep->name, SRC, DST);
117		sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
118		handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
119		return;
120	}
121
122	cep->charge = 0;
123	cep->last_charge = 0;
124
125	switch (cep->dialin_reaction)
126	{
127	case REACT_ACCEPT:
128		logit(LL_CHD, "%05d %s accepting: incoming call from %s to %s",
129			mp->header.cdid, cep->name, SRC, DST);
130		decr_free_channels(find_ctrl_state(mp->controller));
131		next_state(cep, EV_MCI);
132		break;
133
134	case REACT_REJECT:
135		logit(LL_CHD, "%05d %s rejecting: incoming call from %s to %s",
136			mp->header.cdid, cep->name, SRC, DST);
137		sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
138			(CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
139		cep->cdid = CDID_UNUSED;
140		break;
141
142	case REACT_IGNORE:
143		logit(LL_CHD, "%05d %s ignoring: incoming call from %s to %s",
144			mp->header.cdid, cep->name, SRC, DST);
145		sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
146		break;
147
148	case REACT_ANSWER:
149		decr_free_channels(find_ctrl_state(mp->controller));
150		if (cep->alert)
151		{
152			if (mp->display)
153			{
154				logit(LL_CHD, "%05d %s alerting: incoming call from %s to %s (%s)",
155					mp->header.cdid, cep->name, SRC, DST, mp->display);
156			}
157			else
158			{
159				logit(LL_CHD, "%05d %s alerting: incoming call from %s to %s",
160					mp->header.cdid, cep->name, SRC, DST);
161			}
162			next_state(cep, EV_ALRT);
163		}
164		else
165		{
166			if (mp->display)
167			{
168				logit(LL_CHD, "%05d %s answering: incoming call from %s to %s (%s)",
169					mp->header.cdid, cep->name, SRC, DST, mp->display);
170			}
171			else
172			{
173				logit(LL_CHD, "%05d %s answering: incoming call from %s to %s",
174					mp->header.cdid, cep->name, SRC, DST);
175			}
176			next_state(cep, EV_MCI);
177		}
178		break;
179
180	case REACT_CALLBACK:
181
182#ifdef NOTDEF
183/*XXX reserve channel ??? */	decr_free_channels(mp->controller);
184#endif
185		if (cep->cdid == CDID_RESERVED)
186		{
187			logit(LL_CHD, "%05d %s reserved: incoming call from %s to %s",
188				mp->header.cdid, cep->name, SRC, DST);
189			sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
190#if 0
191				(CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
192#else
193				(CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
194#endif
195			/* no state change */
196		}
197		else
198		{
199			sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
200#if 0
201				(CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
202#else
203				(CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
204#endif
205			if (cep->budget_callbackperiod && cep->budget_callbackncalls)
206			{
207				cep->budget_callback_req++;
208				cep->budget_calltype = 0;
209				if (cep->budget_callbackncalls_cnt == 0)
210				{
211					logit(LL_CHD, "%05d %s no budget: call from %s to %s",
212						mp->header.cdid, cep->name, SRC, DST);
213					cep->cdid = CDID_UNUSED;
214					cep->budget_callback_rej++;
215					break;
216				}
217				else
218				{
219					cep->budget_calltype = BUDGET_TYPE_CBACK;
220				}
221			}
222
223			logit(LL_CHD, "%05d %s callback: incoming call from %s to %s",
224				mp->header.cdid, cep->name, SRC, DST);
225
226			cep->last_release_time = time(NULL);
227			cep->cdid = CDID_RESERVED;
228			next_state(cep, EV_CBRQ);
229		}
230		break;
231
232	default:
233		logit(LL_WRN, "msg_connect_ind: unknown response type, tx SETUP_RESP_DNTCRE");
234		sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
235		break;
236	}
237	handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
238#undef SRC
239#undef DST
240}
241
242/*---------------------------------------------------------------------------*
243 *	handle incoming CONNECT_ACTIVE_IND message
244 *---------------------------------------------------------------------------*/
245void
246msg_connect_active_ind(msg_connect_active_ind_t *mp)
247{
248	struct cfg_entry *cep;
249
250	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
251	{
252		logit(LL_WRN, "msg_connect_active_ind: cdid not found!");
253		return;
254	}
255
256	cep->isdncontrollerused = mp->controller;
257	cep->isdnchannelused = mp->channel;
258
259	cep->aoc_now = cep->connect_time = time(NULL);
260	cep->aoc_last = 0;
261	cep->aoc_diff = 0;
262	cep->aoc_valid = AOC_INVALID;
263
264	cep->local_disconnect = DISCON_REM;
265
266	cep->inbytes = INVALID;
267	cep->outbytes = INVALID;
268	cep->hangup = 0;
269
270	/* set the B-channel to active */
271
272	if ((set_channel_busy(find_ctrl_state(cep->isdncontrollerused), cep->isdnchannelused)) == ERROR)
273		logit(LL_ERR, "msg_connect_active_ind: set_channel_busy failed!");
274
275	if (cep->direction == DIR_OUT)
276	{
277		logit(LL_CHD, "%05d %s outgoing call active (ctl %d, ch %d, %s%d)",
278			cep->cdid, cep->name,
279			cep->isdncontrollerused, cep->isdnchannelused,
280			cep->usrdevicename, cep->usrdeviceunit);
281
282		if (cep->budget_calltype)
283		{
284			if (cep->budget_calltype == BUDGET_TYPE_CBACK)
285			{
286				cep->budget_callback_done++;
287				cep->budget_callbackncalls_cnt--;
288				DBGL(DL_BDGT, (logit(LL_DBG, "%s: new cback-budget = %d",
289					cep->name, cep->budget_callbackncalls_cnt)));
290				if (cep->budget_callbacks_file != NULL)
291					upd_callstat_file(cep->budget_callbacks_file, cep->budget_callbacksfile_rotate);
292			}
293			else if (cep->budget_calltype == BUDGET_TYPE_COUT)
294			{
295				cep->budget_callout_done++;
296				cep->budget_calloutncalls_cnt--;
297				DBGL(DL_BDGT, (logit(LL_DBG, "%s: new cout-budget = %d",
298					cep->name, cep->budget_calloutncalls_cnt)));
299				if (cep->budget_callouts_file != NULL)
300					upd_callstat_file(cep->budget_callouts_file, cep->budget_calloutsfile_rotate);
301			}
302			cep->budget_calltype = 0;
303		}
304	}
305	else
306	{
307		logit(LL_CHD, "%05d %s incoming call active (ctl %d, ch %d, %s%d)",
308			cep->cdid, cep->name,
309			cep->isdncontrollerused, cep->isdnchannelused,
310			cep->usrdevicename, cep->usrdeviceunit);
311	}
312
313#ifdef USE_CURSES
314	if (do_fullscreen)
315		display_connect(cep);
316#endif
317#ifdef I4B_EXTERNAL_MONITOR
318	if (do_monitor && accepted)
319		monitor_evnt_connect(cep);
320#endif
321
322	if (isdntime && (mp->datetime[0] != '\0'))
323	{
324		logit(LL_DMN, "date/time from exchange = %s", mp->datetime);
325	}
326
327	next_state(cep, EV_MCAI);
328}
329
330/*---------------------------------------------------------------------------*
331 *	handle incoming PROCEEDING_IND message
332 *---------------------------------------------------------------------------*/
333void
334msg_proceeding_ind(msg_proceeding_ind_t *mp)
335{
336	struct cfg_entry *cep;
337
338	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
339	{
340		logit(LL_WRN, "msg_proceeding_ind: cdid not found!");
341		return;
342	}
343
344	cep->isdncontrollerused = mp->controller;
345	cep->isdnchannelused = mp->channel;
346
347	/* set the B-channels active */
348
349	if ((set_channel_busy(find_ctrl_state(cep->isdncontrollerused), cep->isdnchannelused)) == ERROR)
350		logit(LL_ERR, "msg_proceeding_ind: set_channel_busy failed!");
351
352	logit(LL_CHD, "%05d %s outgoing call proceeding (ctl %d, ch %d)",
353			cep->cdid, cep->name,
354			cep->isdncontrollerused, cep->isdnchannelused);
355}
356
357/*---------------------------------------------------------------------------*
358 *	handle incoming ALERT_IND message
359 *---------------------------------------------------------------------------*/
360void
361msg_alert_ind(msg_alert_ind_t *mp)
362{
363	struct cfg_entry *cep;
364
365	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
366	{
367		logit(LL_WRN, "msg_alert_ind: cdid not found!");
368		return;
369	}
370#ifdef NOTDEF
371	logit(LL_CHD, "%05d %s incoming alert", cep->cdid, cep->name);
372#endif
373}
374
375/*---------------------------------------------------------------------------*
376 *	handle incoming L12STAT_IND message
377 *---------------------------------------------------------------------------*/
378void
379msg_l12stat_ind(msg_l12stat_ind_t *ml)
380{
381	struct isdn_ctrl_state * ctrl = find_ctrl_state(ml->controller);
382	if (ctrl == NULL) {
383		logit(LL_ERR, "msg_l12stat_ind: invalid controller number: %d !", ml->controller);
384		return;
385	}
386
387#ifdef USE_CURSES
388	if (do_fullscreen)
389		display_l12stat(ml->controller, ml->layer, ml->state);
390#endif
391#ifdef I4B_EXTERNAL_MONITOR
392	if (do_monitor && accepted)
393		monitor_evnt_l12stat(ml->controller, ml->layer, ml->state);
394#endif
395
396	DBGL(DL_CNST, (logit(LL_DBG, "msg_l12stat_ind: unit %d, layer %d, state %d",
397		ml->controller, ml->layer, ml->state)));
398
399	if (ml->layer == LAYER_ONE)
400	{
401		if (ml->state == LAYER_IDLE)
402			ctrl->l2stat = ml->state;
403		ctrl->l1stat = ml->state;
404	}
405	else if (ml->layer == LAYER_TWO)
406	{
407		if (ml->state == LAYER_ACTIVE)
408			ctrl->l1stat = ml->state;
409		ctrl->l2stat = ml->state;
410	}
411	else
412	{
413		logit(LL_ERR, "msg_l12stat_ind: invalid layer number [%d]!", ml->layer);
414	}
415}
416
417/*---------------------------------------------------------------------------*
418 *	handle incoming TEIASG_IND message
419 *---------------------------------------------------------------------------*/
420void
421msg_teiasg_ind(msg_teiasg_ind_t *mt)
422{
423	struct isdn_ctrl_state *ctrl = find_ctrl_state(mt->controller);
424
425	if (ctrl == NULL) {
426		logit(LL_ERR, "msg_teiasg_ind: invalid controller number [%d]!", mt->controller);
427		return;
428	}
429
430#ifdef USE_CURSES
431	if (do_fullscreen)
432		display_tei(mt->controller, mt->tei);
433#endif
434#ifdef I4B_EXTERNAL_MONITOR
435	if (do_monitor && accepted)
436		monitor_evnt_tei(mt->controller, mt->tei);
437#endif
438
439	DBGL(DL_CNST, (logit(LL_DBG, "msg_teiasg_ind: unit %d, tei = %d",
440		mt->controller, mt->tei)));
441
442	ctrl->tei = mt->tei;
443}
444
445/*---------------------------------------------------------------------------*
446 *	handle incoming PDEACT_IND message
447 *---------------------------------------------------------------------------*/
448void
449msg_pdeact_ind(msg_pdeact_ind_t *md)
450{
451	int isdnif = md->controller;
452	struct cfg_entry *cep;
453	struct isdn_ctrl_state * ctrl = find_ctrl_state(isdnif);
454
455#ifdef USE_CURSES
456	if (do_fullscreen)
457	{
458		display_l12stat(isdnif, LAYER_ONE, LAYER_IDLE);
459		display_l12stat(isdnif, LAYER_TWO, LAYER_IDLE);
460		display_tei(isdnif, -1);
461	}
462#endif
463#ifdef I4B_EXTERNAL_MONITOR
464	if (do_monitor && accepted)
465	{
466		monitor_evnt_l12stat(isdnif, LAYER_ONE, LAYER_IDLE);
467		monitor_evnt_l12stat(isdnif, LAYER_TWO, LAYER_IDLE);
468		monitor_evnt_tei(isdnif, -1);
469	}
470#endif
471
472	DBGL(DL_CNST, (logit(LL_DBG, "msg_pdeact_ind: BRI %d, persistent deactivation", isdnif)));
473
474	ctrl->l1stat = LAYER_IDLE;
475	ctrl->l2stat = LAYER_IDLE;
476	ctrl->tei = -1;
477
478	for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
479		if (cep->cdid != CDID_UNUSED &&
480		    cep->isdncontrollerused == isdnif) {
481
482			if (cep->cdid == CDID_RESERVED)
483			{
484				cep->state = ST_IDLE;
485				cep->cdid = CDID_UNUSED;
486				continue;
487			}
488
489			cep->cdid = CDID_UNUSED;
490
491			cep->last_release_time = time(NULL);
492
493			SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
494			SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_L1ERROR);
495
496			if (cep->direction == DIR_OUT)
497			{
498				logit(LL_CHD, "%05d %s outgoing call disconnected (local)",
499					cep->cdid, cep->name);
500			}
501			else
502			{
503				logit(LL_CHD, "%05d %s incoming call disconnected (local)",
504					cep->cdid, cep->name);
505			}
506
507			logit(LL_CHD, "%05d %s cause %s",
508				cep->cdid, cep->name, print_i4b_cause(cep->disc_cause));
509
510#ifdef USE_CURSES
511			if (do_fullscreen && (cep->connect_time > 0))
512				display_disconnect(cep);
513#endif
514#ifdef I4B_EXTERNAL_MONITOR
515			if (do_monitor && accepted)
516				monitor_evnt_disconnect(cep);
517#endif
518
519			if (cep->disconnectprog)
520				exec_connect_prog(cep, cep->disconnectprog, 1);
521
522			if (cep->connect_time > 0)
523			{
524				if (cep->direction == DIR_OUT)
525				{
526					logit(LL_CHD, "%05d %s charging: %d units, %d seconds",
527						cep->cdid, cep->name, cep->charge,
528						(int)difftime(time(NULL), cep->connect_time));
529				}
530				else
531				{
532					logit(LL_CHD, "%05d %s connected %d seconds",
533						cep->cdid, cep->name,
534						(int)difftime(time(NULL), cep->connect_time));
535				}
536
537				if ((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
538				{
539					if ((cep->ioutbytes != cep->outbytes) ||
540					   (cep->iinbytes != cep->inbytes))
541					{
542						logit(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
543							cep->cdid, cep->name,
544							cep->inbytes, cep->outbytes,
545							cep->iinbytes, cep->ioutbytes);
546					}
547					else
548					{
549						logit(LL_CHD, "%05d %s accounting: in %d, out %d",
550							cep->cdid, cep->name,
551							cep->inbytes, cep->outbytes);
552					}
553				}
554			}
555
556			if (useacctfile && (cep->connect_time > 0))
557			{
558				int con_secs;
559				char logdatetime[41];
560				struct tm *tp;
561
562				con_secs = difftime(time(NULL), cep->connect_time);
563
564				tp = localtime(&cep->connect_time);
565
566				strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
567
568				if (cep->inbytes != INVALID && cep->outbytes != INVALID)
569				{
570					fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
571						logdatetime, getlogdatetime(),
572						cep->name, cep->charge, con_secs,
573						cep->inbytes, cep->outbytes);
574				}
575				else
576				{
577					fprintf(acctfp, "%s - %s %s %d (%d)\n",
578						logdatetime, getlogdatetime(),
579						cep->name, cep->charge, con_secs);
580				}
581			}
582
583			/* set the B-channel inactive */
584
585			if ((set_channel_idle(ctrl, cep->isdnchannelused)) == ERROR)
586				logit(LL_ERR, "msg_pdeact_ind: set_channel_idle failed!");
587
588			incr_free_channels(ctrl);
589
590			cep->connect_time = 0;
591
592			cep->state = ST_IDLE;
593		}
594	}
595}
596
597/*---------------------------------------------------------------------------*
598 *	handle incoming NEGCOMP_IND message
599 *---------------------------------------------------------------------------*/
600void
601msg_negcomplete_ind(msg_negcomplete_ind_t *mp)
602{
603	struct cfg_entry *cep;
604
605	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
606	{
607		logit(LL_WRN, "msg_negcomp_ind: cdid not found");
608		return;
609	}
610
611	if (cep->connectprog)
612		exec_connect_prog(cep, cep->connectprog, 0);
613}
614
615/*---------------------------------------------------------------------------*
616 *	handle incoming IFSTATE_CHANGED indication
617 *---------------------------------------------------------------------------*/
618void
619msg_ifstatechg_ind(msg_ifstatechg_ind_t *mp)
620{
621	struct cfg_entry *cep;
622
623	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
624	{
625		logit(LL_WRN, "msg_negcomp_ind: cdid not found");
626		return;
627	}
628
629	logit(LL_DBG, "%s%d: switched to state %d", cep->usrdevicename, cep->usrdeviceunit, mp->state);
630}
631
632/*---------------------------------------------------------------------------*
633 *	handle incoming DISCONNECT_IND message
634 *---------------------------------------------------------------------------*/
635void
636msg_disconnect_ind(msg_disconnect_ind_t *mp)
637{
638	struct cfg_entry *cep;
639	struct isdn_ctrl_state *ctrl;
640
641	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
642	{
643		logit(LL_WRN, "msg_disconnect_ind: cdid not found");
644		return;
645	}
646
647	/* is this an aborted out-call prematurely called back? */
648	if (cep->saved_call.cdid == mp->header.cdid)
649	{
650		DBGL(DL_CNST, (logit(LL_DBG, "aborted outcall %05d disconnected",
651			mp->header.cdid)));
652		cep->saved_call.cdid = CDID_UNUSED;
653
654		ctrl = find_ctrl_state(cep->saved_call.controller);
655		set_channel_idle(ctrl, cep->saved_call.channel);
656
657		incr_free_channels(ctrl);
658		return;
659	}
660
661	cep->last_release_time = time(NULL);
662	cep->disc_cause = mp->cause;
663
664	if (cep->direction == DIR_OUT)
665	{
666		logit(LL_CHD, "%05d %s outgoing call disconnected %s",
667			cep->cdid, cep->name,
668			cep->local_disconnect == DISCON_LOC ?
669						"(local)" : "(remote)");
670	}
671	else
672	{
673		logit(LL_CHD, "%05d %s incoming call disconnected %s",
674			cep->cdid, cep->name,
675			cep->local_disconnect == DISCON_LOC ?
676						"(local)" : "(remote)");
677	}
678
679	logit(LL_CHD, "%05d %s cause %s",
680		cep->cdid, cep->name, print_i4b_cause(mp->cause));
681
682#ifdef USE_CURSES
683	if (do_fullscreen && (cep->connect_time > 0))
684		display_disconnect(cep);
685#endif
686#ifdef I4B_EXTERNAL_MONITOR
687	if (do_monitor && accepted)
688		monitor_evnt_disconnect(cep);
689#endif
690
691	if (cep->disconnectprog)
692		exec_connect_prog(cep, cep->disconnectprog, 1);
693
694	if (cep->connect_time > 0)
695	{
696		if (cep->direction == DIR_OUT)
697		{
698			logit(LL_CHD, "%05d %s charging: %d units, %d seconds",
699				cep->cdid, cep->name, cep->charge,
700				(int)difftime(time(NULL), cep->connect_time));
701		}
702		else
703		{
704			logit(LL_CHD, "%05d %s connected %d seconds",
705				cep->cdid, cep->name,
706				(int)difftime(time(NULL), cep->connect_time));
707		}
708
709		if ((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
710		{
711			if ((cep->ioutbytes != cep->outbytes) ||
712			   (cep->iinbytes != cep->inbytes))
713			{
714				logit(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
715					cep->cdid, cep->name,
716					cep->inbytes, cep->outbytes,
717					cep->iinbytes, cep->ioutbytes);
718			}
719			else
720			{
721				logit(LL_CHD, "%05d %s accounting: in %d, out %d",
722					cep->cdid, cep->name,
723					cep->inbytes, cep->outbytes);
724			}
725		}
726	}
727
728	if (useacctfile && (cep->connect_time > 0))
729	{
730		int con_secs;
731		char logdatetime[41];
732		struct tm *tp;
733
734		con_secs = difftime(time(NULL), cep->connect_time);
735
736		tp = localtime(&cep->connect_time);
737
738		strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
739
740		if (cep->inbytes != INVALID && cep->outbytes != INVALID)
741		{
742			fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
743				logdatetime, getlogdatetime(),
744				cep->name, cep->charge, con_secs,
745				cep->inbytes, cep->outbytes);
746		}
747		else
748		{
749			fprintf(acctfp, "%s - %s %s %d (%d)\n",
750				logdatetime, getlogdatetime(),
751				cep->name, cep->charge, con_secs);
752		}
753	}
754
755	/* set the B-channel inactive */
756
757	ctrl = find_ctrl_state(cep->isdncontrollerused);
758	set_channel_idle(ctrl, cep->isdnchannelused);
759
760	incr_free_channels(ctrl);
761
762	cep->connect_time = 0;
763
764	next_state(cep, EV_MDI);
765}
766
767/*---------------------------------------------------------------------------*
768 *	handle incoming DIALOUT message
769 *---------------------------------------------------------------------------*/
770void
771msg_dialout(msg_dialout_ind_t *mp)
772{
773	struct cfg_entry *cep;
774
775	if ((cep = find_by_device_for_dialout(mp->driver, mp->driver_unit)) == NULL)
776	{
777		DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: config entry reserved or no match")));
778		return;
779	}
780
781	DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: dial req from %s%d", cep->usrdevicename, mp->driver_unit)));
782
783	if (cep->inout == DIR_INONLY)
784	{
785		dialresponse(cep, DSTAT_INONLY);
786		return;
787	}
788
789	if (cep->budget_calloutperiod && cep->budget_calloutncalls)
790	{
791		cep->budget_calltype = 0;
792		cep->budget_callout_req++;
793
794		if (cep->budget_calloutncalls_cnt == 0)
795		{
796			logit(LL_CHD, "%05d %s no budget for calling out", 0, cep->name);
797			cep->budget_callout_rej++;
798			dialresponse(cep, DSTAT_TFAIL);
799			return;
800		}
801		else
802		{
803			cep->budget_calltype = BUDGET_TYPE_COUT;
804		}
805	}
806
807	if ((cep->cdid = get_cdid()) == 0)
808	{
809		DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialout: get_cdid() returned 0!")));
810		return;
811	}
812
813	cep->charge = 0;
814	cep->last_charge = 0;
815
816	next_state(cep, EV_MDO);
817}
818
819/*---------------------------------------------------------------------------*
820 *	handle incoming DIALOUTNUMBER message
821 *---------------------------------------------------------------------------*/
822void
823msg_dialoutnumber(msg_dialoutnumber_ind_t *mp)
824{
825	struct cfg_entry *cep;
826
827	if ((cep = find_by_device_for_dialoutnumber(mp->driver, mp->driver_unit, mp->cmdlen, mp->cmd)) == NULL)
828	{
829		DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: config entry reserved or no match")));
830		return;
831	}
832
833	DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: dial req from %s%d", cep->usrdevicename, mp->driver_unit)));
834
835	if (cep->inout == DIR_INONLY)
836	{
837		dialresponse(cep, DSTAT_INONLY);
838		return;
839	}
840
841	if (cep->budget_calloutperiod && cep->budget_calloutncalls)
842	{
843		cep->budget_calltype = 0;
844		cep->budget_callout_req++;
845
846		if (cep->budget_calloutncalls_cnt == 0)
847		{
848			logit(LL_CHD, "%05d %s no budget for calling out", 0, cep->name);
849			cep->budget_callout_rej++;
850			dialresponse(cep, DSTAT_TFAIL);
851			return;
852		}
853		else
854		{
855			cep->budget_calltype = BUDGET_TYPE_COUT;
856		}
857	}
858
859	if ((cep->cdid = get_cdid()) == 0)
860	{
861		DBGL(DL_DRVR, (logit(LL_DBG, "msg_dialoutnumber: get_cdid() returned 0!")));
862		return;
863	}
864
865	cep->charge = 0;
866	cep->last_charge = 0;
867
868	next_state(cep, EV_MDO);
869}
870
871/*---------------------------------------------------------------------------*
872 *	handle incoming DRVRDISC_REQ message
873 *---------------------------------------------------------------------------*/
874void
875msg_drvrdisc_req(msg_drvrdisc_req_t *mp)
876{
877	struct cfg_entry *cep;
878
879	DBGL(DL_DRVR, (logit(LL_DBG, "msg_drvrdisc_req for call %d", mp->header.cdid)));
880
881	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
882	{
883		DBGL(DL_DRVR, (logit(LL_DBG, "msg_drvrdisc_req: config entry not found")));
884		return;
885	}
886	next_state(cep, EV_DRQ);
887}
888
889/*---------------------------------------------------------------------------*
890 *	handle incoming ACCOUNTING message
891 *---------------------------------------------------------------------------*/
892void
893msg_accounting(msg_accounting_ind_t *mp)
894{
895	struct cfg_entry *cep;
896
897	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
898	{
899		logit(LL_WRN, "msg_accounting: no config entry found!");
900		return;
901	}
902
903	cep->inbytes = mp->inbytes;
904	cep->iinbytes = mp->iinbytes;
905	cep->outbytes = mp->outbytes;
906	cep->ioutbytes = mp->ioutbytes;
907	cep->inbps = mp->inbps;
908	cep->outbps = mp->outbps;
909
910	if (mp->accttype == ACCT_DURING)
911	{
912#ifdef USE_CURSES
913		if (do_fullscreen)
914			display_acct(cep);
915#endif
916#ifdef I4B_EXTERNAL_MONITOR
917		if (do_monitor && accepted)
918			monitor_evnt_acct(cep);
919#endif
920	}
921}
922
923/*---------------------------------------------------------------------------*
924 *	handle incoming CHARGING message
925 *---------------------------------------------------------------------------*/
926void
927msg_charging_ind(msg_charging_ind_t *mp)
928{
929	static const char *cttab[] = {
930		"invalid",
931		"AOCD",
932		"AOCE",
933		"estimated" };
934
935	struct cfg_entry *cep;
936
937	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
938	{
939		logit(LL_WRN, "msg_charging_ind: cdid not found");
940		return;
941	}
942
943	if (mp->units_type < CHARGE_INVALID || mp->units_type > CHARGE_CALC)
944	{
945		logit(LL_ERR, "msg_charging: units_type %d out of range!", mp->units_type);
946		error_exit(1, "msg_charging: units_type %d out of range!", mp->units_type);
947	}
948
949	DBGL(DL_DRVR, (logit(LL_DBG, "msg_charging: %d unit(s) (%s)",
950			mp->units, cttab[mp->units_type])));
951
952	cep->charge = mp->units;
953
954	switch (mp->units_type)
955	{
956	case CHARGE_AOCD:
957		if ((cep->unitlengthsrc == ULSRC_DYN) &&
958		   (cep->charge != cep->last_charge))
959		{
960			cep->last_charge = cep->charge;
961			handle_charge(cep);
962		}
963		break;
964
965	case CHARGE_CALC:
966#ifdef USE_CURSES
967		if (do_fullscreen)
968			display_ccharge(cep, mp->units);
969#endif
970#ifdef I4B_EXTERNAL_MONITOR
971		if (do_monitor && accepted)
972			monitor_evnt_charge(cep, mp->units, 1);
973#endif
974		break;
975	}
976}
977
978/*---------------------------------------------------------------------------*
979 *	handle incoming IDLE_TIMEOUT_IND message
980 *---------------------------------------------------------------------------*/
981void
982msg_idle_timeout_ind(msg_idle_timeout_ind_t *mp)
983{
984	struct cfg_entry *cep;
985
986	if ((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
987	{
988		logit(LL_WRN, "msg_idle_timeout_ind: cdid not found!");
989		return;
990	}
991
992	cep->local_disconnect = DISCON_LOC;
993
994	DBGL(DL_DRVR, (logit(LL_DBG, "msg_idle_timeout_ind: idletimeout, kernel sent disconnect!")));
995
996	check_and_kill(cep);
997}
998
999/*---------------------------------------------------------------------------*
1000 *    handle incoming MSG_PACKET_IND message
1001 *---------------------------------------------------------------------------*/
1002static char *
1003strapp(char *buf, char *lim, const char *txt)
1004{
1005	while (*txt && buf < lim - 1)
1006		*buf++ = *txt++;
1007	*buf = '\0';
1008	return buf;
1009}
1010
1011/*---------------------------------------------------------------------------*
1012 *    handle incoming MSG_PACKET_IND message
1013 *---------------------------------------------------------------------------*/
1014static char *
1015ipapp(char *buf, char *lim, unsigned long a)
1016{
1017	unsigned long ma = ntohl(a);
1018	ssize_t n;
1019
1020	n = snprintf(buf, lim - buf, "%lu.%lu.%lu.%lu", (ma>>24)&0xFF,
1021	    (ma>>16)&0xFF, (ma>>8)&0xFF, (ma)&0xFF);
1022	if (n > 0)
1023		return buf + n;
1024	else
1025		return NULL;
1026}
1027
1028/*---------------------------------------------------------------------------*
1029 *    handle incoming MSG_PACKET_IND message
1030 *---------------------------------------------------------------------------*/
1031void
1032msg_packet_ind(msg_packet_ind_t *mp)
1033{
1034	struct cfg_entry *cep;
1035	struct ip *ip;
1036	u_char *proto_hdr;
1037	char tmp[80];
1038	char *cptr = tmp;
1039	const char *name = "???";
1040
1041	for (cep = get_first_cfg_entry(); cep; cep = NEXT_CFE(cep)) {
1042		if (cep->usrdevice == mp->driver &&
1043			cep->usrdeviceunit == mp->driver_unit)
1044		{
1045			name = cep->name;
1046			break;
1047		}
1048	}
1049
1050	ip = (struct ip*)mp->pktdata;
1051	proto_hdr = mp->pktdata + ((ip->ip_hl)<<2);
1052
1053	if (ip->ip_p == IPPROTO_TCP)
1054	{
1055		struct tcphdr* tcp = (struct tcphdr*)proto_hdr;
1056
1057		cptr = strapp(cptr, tmp + sizeof(tmp), "TCP ");
1058		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr);
1059		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1060		    ":%u -> ", ntohs(tcp->th_sport));
1061		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr);
1062		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1063		    ":%u", ntohs(tcp->th_dport));
1064
1065		if (tcp->th_flags & TH_FIN)
1066			cptr = strapp(cptr, tmp + sizeof(tmp), " FIN");
1067		if (tcp->th_flags & TH_SYN)
1068			cptr = strapp(cptr, tmp + sizeof(tmp), " SYN");
1069		if (tcp->th_flags & TH_RST)
1070			cptr = strapp(cptr, tmp + sizeof(tmp), " RST");
1071		if (tcp->th_flags & TH_PUSH)
1072			cptr = strapp(cptr, tmp + sizeof(tmp), " PUSH");
1073		if (tcp->th_flags & TH_ACK)
1074			cptr = strapp(cptr, tmp + sizeof(tmp), " ACK");
1075		if (tcp->th_flags & TH_URG)
1076			cptr = strapp(cptr, tmp + sizeof(tmp), " URG");
1077	}
1078	else if (ip->ip_p == IPPROTO_UDP)
1079	{
1080		struct udphdr* udp = (struct udphdr*)proto_hdr;
1081
1082		cptr = strapp(cptr, tmp + sizeof(tmp), "UDP ");
1083		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr);
1084		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1085		    ":%u -> ", ntohs(udp->uh_sport));
1086		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr);
1087		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1088		    ":%u", ntohs(udp->uh_dport));
1089	}
1090	else if (ip->ip_p == IPPROTO_ICMP)
1091	{
1092		struct icmp* icmp = (struct icmp*)proto_hdr;
1093
1094		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1095		    "ICMP:%u.%u", icmp->icmp_type, icmp->icmp_code);
1096		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr);
1097		cptr = strapp(cptr, tmp + sizeof(tmp), " -> ");
1098		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr);
1099	}
1100	else
1101	{
1102		cptr += snprintf(cptr, sizeof(tmp) - (cptr - tmp),
1103		    "PROTO=%u ", ip->ip_p);
1104		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_src.s_addr);
1105		cptr = strapp(cptr, tmp + sizeof(tmp), " -> ");
1106		cptr = ipapp(cptr, tmp + sizeof(tmp), ip->ip_dst.s_addr);
1107	}
1108
1109	logit(LL_PKT, "%s %s %u %s", name, mp->direction ? "send" : "recv",
1110	    ntohs(ip->ip_len), tmp);
1111}
1112
1113/*
1114 * A new controller arrived or is gone away
1115 */
1116void
1117msg_ctrl_ev_ind(msg_ctrl_ev_ind_t *mp)
1118{
1119	logit(LL_DMN, "controller %d %s", mp->controller, mp->event?"attached":"detached");
1120	if (mp->event) {
1121		/* new, add to controller list */
1122		init_new_controller(mp->controller);
1123		init_single_controller_protocol(find_ctrl_state(mp->controller));
1124	} else {
1125		/* controller gone, remove */
1126		remove_ctrl_state(mp->controller);
1127	}
1128}
1129
1130/*---------------------------------------------------------------------------*
1131 *	get a cdid from kernel
1132 *---------------------------------------------------------------------------*/
1133int
1134get_cdid(void)
1135{
1136	msg_cdid_req_t mcr;
1137
1138	mcr.cdid = 0;
1139
1140	if ((ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0)
1141	{
1142		logit(LL_ERR, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno));
1143		error_exit(1, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno));
1144	}
1145
1146	return(mcr.cdid);
1147}
1148
1149/*---------------------------------------------------------------------------*
1150 *      send message "connect request" to kernel
1151 *---------------------------------------------------------------------------*/
1152int
1153sendm_connect_req(struct cfg_entry *cep)
1154{
1155        msg_connect_req_t mcr;
1156        int ret;
1157
1158	cep->local_disconnect = DISCON_REM;
1159
1160	cep->unitlength = get_current_rate(cep, 1);
1161
1162	mcr.cdid = cep->cdid;
1163
1164	mcr.controller = cep->isdncontrollerused;
1165	mcr.channel = cep->isdnchannelused;
1166	mcr.txdelay = cep->isdntxdelout;
1167
1168	mcr.bprot = cep->b1protocol;
1169
1170	mcr.driver = cep->usrdevice;
1171	mcr.driver_unit = cep->usrdeviceunit;
1172
1173	/* setup the shorthold data */
1174	mcr.shorthold_data.shorthold_algorithm = cep->shorthold_algorithm;
1175	mcr.shorthold_data.unitlen_time = cep->unitlength;
1176	mcr.shorthold_data.idle_time = cep->idle_time_out;
1177	mcr.shorthold_data.earlyhup_time = cep->earlyhangup;
1178
1179	if (cep->unitlengthsrc == ULSRC_DYN)
1180		mcr.unitlen_method = ULEN_METHOD_DYNAMIC;
1181	else
1182		mcr.unitlen_method = ULEN_METHOD_STATIC;
1183
1184	strlcpy(mcr.dst_telno, cep->remote_phone_dialout,
1185	    sizeof(mcr.dst_telno));
1186	strlcpy(mcr.src_telno, cep->local_phone_dialout, sizeof(mcr.src_telno));
1187
1188	cep->last_dial_time = time(NULL);
1189	cep->direction = DIR_OUT;
1190
1191	DBGL(DL_CNST, (logit(LL_DBG, "sendm_connect_req: ctrl = %d, chan = %d", cep->isdncontrollerused, cep->isdnchannelused)));
1192
1193	if ((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0)
1194	{
1195		logit(LL_ERR, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
1196		error_exit(1, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
1197	}
1198
1199	decr_free_channels(find_ctrl_state(cep->isdncontrollerused));
1200
1201	logit(LL_CHD, "%05d %s dialing out from %s to %s",
1202		cep->cdid,
1203	        cep->name,
1204		aliasing ? get_alias(cep->local_phone_dialout) : cep->local_phone_dialout,
1205		aliasing ? get_alias(cep->remote_phone_dialout) : cep->remote_phone_dialout);
1206
1207	return(ret);
1208}
1209
1210/*---------------------------------------------------------------------------*
1211 *	send message "connect response" to kernel
1212 *---------------------------------------------------------------------------*/
1213int
1214sendm_connect_resp(struct cfg_entry *cep, int cdid, int response, cause_t cause)
1215{
1216	msg_connect_resp_t mcr;
1217	int ret;
1218
1219	mcr.cdid = cdid;
1220
1221	mcr.response = response;
1222
1223	if (response == SETUP_RESP_REJECT)
1224	{
1225		mcr.cause = cause;
1226		DBGL(DL_DRVR, (logit(LL_DBG, "sendm_connect_resp: reject, cause=0x%x", cause)));
1227	}
1228	else if (response == SETUP_RESP_ACCEPT)
1229	{
1230		cep->direction = DIR_IN;
1231
1232		mcr.txdelay = cep->isdntxdelin;
1233
1234		mcr.bprot = cep->b1protocol;
1235
1236		mcr.driver = cep->usrdevice;
1237		mcr.driver_unit = cep->usrdeviceunit;
1238
1239		mcr.max_idle_time = cep->idle_time_in;
1240
1241		DBGL(DL_DRVR, (logit(LL_DBG, "sendm_connect_resp: accept")));
1242	}
1243
1244	if ((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &mcr)) < 0)
1245	{
1246		logit(LL_ERR, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno));
1247		error_exit(1, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno));
1248	}
1249	return(ret);
1250}
1251
1252/*---------------------------------------------------------------------------*
1253 *	send message "disconnect request" to kernel
1254 *---------------------------------------------------------------------------*/
1255int
1256sendm_disconnect_req(struct cfg_entry *cep, cause_t cause)
1257{
1258	msg_discon_req_t mcr;
1259	int ret = 0;
1260
1261	mcr.cdid = cep->cdid;
1262
1263	mcr.cause = cause;
1264
1265	cep->local_disconnect = DISCON_LOC;
1266
1267	if ((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mcr)) < 0)
1268	{
1269		logit(LL_ERR, "sendm_disconnect_req: ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno));
1270	}
1271	else
1272	{
1273		DBGL(DL_DRVR, (logit(LL_DBG, "sendm_disconnect_req: sent DISCONNECT_REQ")));
1274	}
1275	return(ret);
1276}
1277
1278/*---------------------------------------------------------------------------*
1279 *	send message "alert request" to kernel
1280 *---------------------------------------------------------------------------*/
1281int
1282sendm_alert_req(struct cfg_entry *cep)
1283{
1284	msg_alert_req_t mar;
1285	int ret;
1286
1287	mar.cdid = cep->cdid;
1288
1289	if ((ret = ioctl(isdnfd, I4B_ALERT_REQ, &mar)) < 0)
1290	{
1291		logit(LL_ERR, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno));
1292		error_exit(1, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno));
1293	}
1294	else
1295	{
1296		DBGL(DL_DRVR, (logit(LL_DBG, "sendm_alert_req: sent ALERT_REQ")));
1297	}
1298	return(ret);
1299}
1300
1301/* EOF */
1302