MFC r1.6 r1.30 r1.28 (HEAD):
[dragonfly.git] / usr.sbin / i4b / isdnd / msghdl.c
blob029d4ec12e37674f9772a84c6a734a7d4e1b5bd1
1 /*
2 * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
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.
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.
25 *---------------------------------------------------------------------------
27 * i4b daemon - message from kernel handling routines
28 * --------------------------------------------------
30 * $Id: msghdl.c,v 1.78 2000/09/21 11:29:51 hm Exp $
32 * $FreeBSD: src/usr.sbin/i4b/isdnd/msghdl.c,v 1.6.2.3 2001/12/16 15:13:38 hm Exp $
33 * $DragonFly: src/usr.sbin/i4b/isdnd/msghdl.c,v 1.3 2004/02/10 02:59:42 rob Exp $
35 * last edit-date: [Thu Sep 21 11:11:48 2000]
37 *---------------------------------------------------------------------------*/
39 #include "isdnd.h"
41 #include <sys/socket.h>
42 #include <net/if.h>
43 #include <net/if_types.h>
45 #if defined(__DragonFly__)
46 #include <net/if_var.h>
47 #endif
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/in_var.h>
52 #include <netinet/ip.h>
53 #include <netinet/tcp.h>
54 #include <netinet/udp.h>
55 #include <netinet/ip_icmp.h>
57 /*---------------------------------------------------------------------------*
58 * handle incoming CONNECT_IND (=SETUP) message
59 *---------------------------------------------------------------------------*/
60 void
61 msg_connect_ind(msg_connect_ind_t *mp)
63 cfg_entry_t *cep;
64 char *src_tela = "ERROR-src_tela";
65 char *dst_tela = "ERROR-dst_tela";
67 #define SRC (aliasing == 0 ? mp->src_telno : src_tela)
68 #define DST (aliasing == 0 ? mp->dst_telno : dst_tela)
70 if(aliasing)
72 src_tela = get_alias(mp->src_telno);
73 dst_tela = get_alias(mp->dst_telno);
76 if((cep = find_matching_entry_incoming(mp)) == NULL)
78 /* log message generated in find_matching_entry_incoming() */
79 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
80 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
81 return;
84 if(cep->cdid != CDID_UNUSED && cep->cdid != CDID_RESERVED)
86 /*
87 * This is an incoming call on a number we just dialed out.
88 * Stop our dial-out and accept the incoming call.
90 if(cep->saved_call.cdid != CDID_UNUSED &&
91 cep->saved_call.cdid != CDID_RESERVED)
93 int cdid;
95 /* disconnect old, not new */
97 cdid = cep->cdid;
98 cep->cdid = cep->saved_call.cdid;
99 sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
100 cep->cdid = cdid;
103 * Shortcut the state machine and mark this
104 * entry as free
106 /* XXX */ cep->state = ST_IDLE; /* this is an invalid */
107 /* transition, */
108 /* so no next_state() */
109 /* we have to wait here for an incoming */
110 /* disconnect message !!! (-hm) */
114 if(cep->inout == DIR_OUTONLY)
116 log(LL_CHD, "%05d %s incoming call from %s to %s not allowed by configuration!",
117 mp->header.cdid, cep->name, SRC, DST);
118 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
119 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
120 return;
123 cep->charge = 0;
124 cep->last_charge = 0;
126 switch(cep->dialin_reaction)
128 case REACT_ACCEPT:
129 log(LL_CHD, "%05d %s accepting: incoming call from %s to %s",
130 mp->header.cdid, cep->name, SRC, DST);
131 decr_free_channels(mp->controller);
132 next_state(cep, EV_MCI);
133 break;
135 case REACT_REJECT:
136 log(LL_CHD, "%05d %s rejecting: incoming call from %s to %s",
137 mp->header.cdid, cep->name, SRC, DST);
138 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
139 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
140 cep->cdid = CDID_UNUSED;
141 break;
143 case REACT_IGNORE:
144 log(LL_CHD, "%05d %s ignoring: incoming call from %s to %s",
145 mp->header.cdid, cep->name, SRC, DST);
146 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
147 cep->cdid = CDID_UNUSED;
148 break;
150 case REACT_ANSWER:
151 decr_free_channels(mp->controller);
152 if(cep->alert)
154 if(mp->display)
156 log(LL_CHD, "%05d %s alerting: incoming call from %s to %s (%s)",
157 mp->header.cdid, cep->name, SRC, DST, mp->display);
159 else
161 log(LL_CHD, "%05d %s alerting: incoming call from %s to %s",
162 mp->header.cdid, cep->name, SRC, DST);
164 next_state(cep, EV_ALRT);
166 else
168 if(mp->display)
170 log(LL_CHD, "%05d %s answering: incoming call from %s to %s (%s)",
171 mp->header.cdid, cep->name, SRC, DST, mp->display);
173 else
175 log(LL_CHD, "%05d %s answering: incoming call from %s to %s",
176 mp->header.cdid, cep->name, SRC, DST);
178 next_state(cep, EV_MCI);
180 break;
182 case REACT_CALLBACK:
184 #ifdef NOTDEF
185 /*XXX reserve channel ??? */ decr_free_channels(mp->controller);
186 #endif
187 if(cep->cdid == CDID_RESERVED)
189 log(LL_CHD, "%05d %s reserved: incoming call from %s to %s",
190 mp->header.cdid, cep->name, SRC, DST);
191 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
192 #if 0
193 (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
194 #else
195 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
196 #endif
197 /* no state change */
199 else
201 sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
202 #if 0
203 (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
204 #else
205 (CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
206 #endif
207 if(cep->budget_callbackperiod && cep->budget_callbackncalls)
209 cep->budget_callback_req++;
210 cep->budget_calltype = 0;
211 if(cep->budget_callbackncalls_cnt == 0)
213 log(LL_CHD, "%05d %s no budget: call from %s to %s",
214 mp->header.cdid, cep->name, SRC, DST);
215 cep->cdid = CDID_UNUSED;
216 cep->budget_callback_rej++;
217 break;
219 else
221 cep->budget_calltype = BUDGET_TYPE_CBACK;
225 log(LL_CHD, "%05d %s callback: incoming call from %s to %s",
226 mp->header.cdid, cep->name, SRC, DST);
228 cep->last_release_time = time(NULL);
229 cep->cdid = CDID_RESERVED;
230 next_state(cep, EV_CBRQ);
232 break;
234 default:
235 log(LL_WRN, "msg_connect_ind: unknown response type, tx SETUP_RESP_DNTCRE");
236 sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
237 break;
239 handle_scrprs(mp->header.cdid, mp->scr_ind, mp->prs_ind, SRC);
240 #undef SRC
241 #undef DST
244 /*---------------------------------------------------------------------------*
245 * handle incoming CONNECT_ACTIVE_IND message
246 *---------------------------------------------------------------------------*/
247 void
248 msg_connect_active_ind(msg_connect_active_ind_t *mp)
250 cfg_entry_t *cep;
251 char *device;
253 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
255 log(LL_WRN, "msg_connect_active_ind: cdid not found!");
256 return;
259 cep->isdncontrollerused = mp->controller;
260 cep->isdnchannelused = mp->channel;
262 cep->aoc_now = cep->connect_time = time(NULL);
263 cep->aoc_last = 0;
264 cep->aoc_diff = 0;
265 cep->aoc_valid = AOC_INVALID;
267 cep->local_disconnect = DISCON_REM;
269 cep->inbytes = INVALID;
270 cep->outbytes = INVALID;
271 cep->hangup = 0;
273 device = bdrivername(cep->usrdevicename);
275 /* set the B-channel to active */
277 if((set_channel_busy(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
278 log(LL_ERR, "msg_connect_active_ind: set_channel_busy failed!");
280 if(cep->direction == DIR_OUT)
282 log(LL_CHD, "%05d %s outgoing call active (ctl %d, ch %d, %s%d)",
283 cep->cdid, cep->name,
284 cep->isdncontrollerused, cep->isdnchannelused,
285 bdrivername(cep->usrdevicename), cep->usrdeviceunit);
287 if(cep->budget_calltype)
289 if(cep->budget_calltype == BUDGET_TYPE_CBACK)
291 cep->budget_callback_done++;
292 cep->budget_callbackncalls_cnt--;
293 DBGL(DL_BDGT, (log(LL_DBG, "%s: new cback-budget = %d",
294 cep->name, cep->budget_callbackncalls_cnt)));
295 if(cep->budget_callbacks_file != NULL)
296 upd_callstat_file(cep->budget_callbacks_file, cep->budget_callbacksfile_rotate);
298 else if(cep->budget_calltype == BUDGET_TYPE_COUT)
300 cep->budget_callout_done++;
301 cep->budget_calloutncalls_cnt--;
302 DBGL(DL_BDGT, (log(LL_DBG, "%s: new cout-budget = %d",
303 cep->name, cep->budget_calloutncalls_cnt)));
304 if(cep->budget_callouts_file != NULL)
305 upd_callstat_file(cep->budget_callouts_file, cep->budget_calloutsfile_rotate);
307 cep->budget_calltype = 0;
310 else
312 log(LL_CHD, "%05d %s incoming call active (ctl %d, ch %d, %s%d)",
313 cep->cdid, cep->name,
314 cep->isdncontrollerused, cep->isdnchannelused,
315 bdrivername(cep->usrdevicename), cep->usrdeviceunit);
318 #ifdef USE_CURSES
319 if(do_fullscreen)
320 display_connect(cep);
321 #endif
322 #ifdef I4B_EXTERNAL_MONITOR
323 if(do_monitor && accepted)
324 monitor_evnt_connect(cep);
325 #endif
327 if(isdntime && (mp->datetime[0] != '\0'))
329 log(LL_DMN, "date/time from exchange = %s", mp->datetime);
332 next_state(cep, EV_MCAI);
335 /*---------------------------------------------------------------------------*
336 * handle incoming PROCEEDING_IND message
337 *---------------------------------------------------------------------------*/
338 void
339 msg_proceeding_ind(msg_proceeding_ind_t *mp)
341 cfg_entry_t *cep;
343 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
345 log(LL_WRN, "msg_proceeding_ind: cdid not found!");
346 return;
349 cep->isdncontrollerused = mp->controller;
350 cep->isdnchannelused = mp->channel;
352 /* set the B-channels active */
354 if((set_channel_busy(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
355 log(LL_ERR, "msg_proceeding_ind: set_channel_busy failed!");
357 log(LL_CHD, "%05d %s outgoing call proceeding (ctl %d, ch %d)",
358 cep->cdid, cep->name,
359 cep->isdncontrollerused, cep->isdnchannelused);
362 /*---------------------------------------------------------------------------*
363 * handle incoming ALERT_IND message
364 *---------------------------------------------------------------------------*/
365 void
366 msg_alert_ind(msg_alert_ind_t *mp)
368 cfg_entry_t *cep;
370 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
372 log(LL_WRN, "msg_alert_ind: cdid not found!");
373 return;
375 #ifdef NOTDEF
376 log(LL_CHD, "%05d %s incoming alert", cep->cdid, cep->name);
377 #endif
380 /*---------------------------------------------------------------------------*
381 * handle incoming L12STAT_IND message
382 *---------------------------------------------------------------------------*/
383 void
384 msg_l12stat_ind(msg_l12stat_ind_t *ml)
386 if((ml->controller < 0) || (ml->controller >= ncontroller))
388 log(LL_ERR, "msg_l12stat_ind: invalid controller number [%d]!", ml->controller);
389 return;
392 #ifdef USE_CURSES
393 if(do_fullscreen)
394 display_l12stat(ml->controller, ml->layer, ml->state);
395 #endif
396 #ifdef I4B_EXTERNAL_MONITOR
397 if(do_monitor && accepted)
398 monitor_evnt_l12stat(ml->controller, ml->layer, ml->state);
399 #endif
401 DBGL(DL_CNST, (log(LL_DBG, "msg_l12stat_ind: unit %d, layer %d, state %d",
402 ml->controller, ml->layer, ml->state)));
404 if(ml->layer == LAYER_ONE)
406 if(ml->state == LAYER_IDLE)
407 isdn_ctrl_tab[ml->controller].l2stat = ml->state;
408 isdn_ctrl_tab[ml->controller].l1stat = ml->state;
410 else if(ml->layer == LAYER_TWO)
412 if(ml->state == LAYER_ACTIVE)
413 isdn_ctrl_tab[ml->controller].l1stat = ml->state;
414 isdn_ctrl_tab[ml->controller].l2stat = ml->state;
416 else
418 log(LL_ERR, "msg_l12stat_ind: invalid layer number [%d]!", ml->layer);
422 /*---------------------------------------------------------------------------*
423 * handle incoming TEIASG_IND message
424 *---------------------------------------------------------------------------*/
425 void
426 msg_teiasg_ind(msg_teiasg_ind_t *mt)
428 if((mt->controller < 0) || (mt->controller >= ncontroller))
430 log(LL_ERR, "msg_teiasg_ind: invalid controller number [%d]!", mt->controller);
431 return;
434 #ifdef USE_CURSES
435 if(do_fullscreen)
436 display_tei(mt->controller, mt->tei);
437 #endif
438 #ifdef I4B_EXTERNAL_MONITOR
439 if(do_monitor && accepted)
440 monitor_evnt_tei(mt->controller, mt->tei);
441 #endif
443 DBGL(DL_CNST, (log(LL_DBG, "msg_teiasg_ind: unit %d, tei = %d",
444 mt->controller, mt->tei)));
446 isdn_ctrl_tab[mt->controller].tei = mt->tei;
449 /*---------------------------------------------------------------------------*
450 * handle incoming PDEACT_IND message
451 *---------------------------------------------------------------------------*/
452 void
453 msg_pdeact_ind(msg_pdeact_ind_t *md)
455 int i;
456 int ctrl = md->controller;
457 cfg_entry_t *cep;
459 #ifdef USE_CURSES
460 if(do_fullscreen)
462 display_l12stat(ctrl, LAYER_ONE, LAYER_IDLE);
463 display_l12stat(ctrl, LAYER_TWO, LAYER_IDLE);
464 display_tei(ctrl, -1);
466 #endif
467 #ifdef I4B_EXTERNAL_MONITOR
468 if(do_monitor && accepted)
470 monitor_evnt_l12stat(ctrl, LAYER_ONE, LAYER_IDLE);
471 monitor_evnt_l12stat(ctrl, LAYER_TWO, LAYER_IDLE);
472 monitor_evnt_tei(ctrl, -1);
474 #endif
476 DBGL(DL_CNST, (log(LL_DBG, "msg_pdeact_ind: unit %d, persistent deactivation", ctrl)));
478 isdn_ctrl_tab[ctrl].l1stat = LAYER_IDLE;
479 isdn_ctrl_tab[ctrl].l2stat = LAYER_IDLE;
480 isdn_ctrl_tab[ctrl].tei = -1;
482 for(i=0; i < nentries; i++)
484 if((cfg_entry_tab[i].cdid != CDID_UNUSED) &&
485 (cfg_entry_tab[i].isdncontrollerused == ctrl))
487 cep = &cfg_entry_tab[i];
489 if(cep->cdid == CDID_RESERVED)
491 cep->state = ST_IDLE;
492 cep->cdid = CDID_UNUSED;
493 continue;
496 cep->cdid = CDID_UNUSED;
498 cep->last_release_time = time(NULL);
500 SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
501 SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_L1ERROR);
503 if(cep->direction == DIR_OUT)
505 log(LL_CHD, "%05d %s outgoing call disconnected (local)",
506 cep->cdid, cep->name);
508 else
510 log(LL_CHD, "%05d %s incoming call disconnected (local)",
511 cep->cdid, cep->name);
514 log(LL_CHD, "%05d %s cause %s",
515 cep->cdid, cep->name, print_i4b_cause(cep->disc_cause));
517 #ifdef USE_CURSES
518 if(do_fullscreen && (cep->connect_time > 0))
519 display_disconnect(cep);
520 #endif
521 #ifdef I4B_EXTERNAL_MONITOR
522 if(do_monitor && accepted)
523 monitor_evnt_disconnect(cep);
524 #endif
526 if(cep->disconnectprog)
527 exec_connect_prog(cep, cep->disconnectprog, 1);
529 if(cep->connect_time > 0)
531 if(cep->direction == DIR_OUT)
533 log(LL_CHD, "%05d %s charging: %d units, %d seconds",
534 cep->cdid, cep->name, cep->charge,
535 (int)difftime(time(NULL), cep->connect_time));
537 else
539 log(LL_CHD, "%05d %s connected %d seconds",
540 cep->cdid, cep->name,
541 (int)difftime(time(NULL), cep->connect_time));
544 if((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
546 if((cep->ioutbytes != cep->outbytes) ||
547 (cep->iinbytes != cep->inbytes))
549 log(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
550 cep->cdid, cep->name,
551 cep->inbytes, cep->outbytes,
552 cep->iinbytes, cep->ioutbytes);
554 else
556 log(LL_CHD, "%05d %s accounting: in %d, out %d",
557 cep->cdid, cep->name,
558 cep->inbytes, cep->outbytes);
563 if(useacctfile && (cep->connect_time > 0))
565 int con_secs;
566 char logdatetime[41];
567 struct tm *tp;
569 con_secs = difftime(time(NULL), cep->connect_time);
571 tp = localtime(&cep->connect_time);
573 strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
575 if(cep->inbytes != INVALID && cep->outbytes != INVALID)
577 fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
578 logdatetime, getlogdatetime(),
579 cep->name, cep->charge, con_secs,
580 cep->inbytes, cep->outbytes);
582 else
584 fprintf(acctfp, "%s - %s %s %d (%d)\n",
585 logdatetime, getlogdatetime(),
586 cep->name, cep->charge, con_secs);
590 /* set the B-channel inactive */
592 if((set_channel_idle(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
593 log(LL_ERR, "msg_pdeact_ind: set_channel_idle failed!");
595 incr_free_channels(cep->isdncontrollerused);
597 cep->connect_time = 0;
599 cep->state = ST_IDLE;
604 /*---------------------------------------------------------------------------*
605 * handle incoming NEGCOMP_IND message
606 *---------------------------------------------------------------------------*/
607 void
608 msg_negcomplete_ind(msg_negcomplete_ind_t *mp)
610 cfg_entry_t *cep;
612 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
614 log(LL_WRN, "msg_negcomp_ind: cdid not found");
615 return;
618 if(cep->connectprog)
619 exec_connect_prog(cep, cep->connectprog, 0);
622 /*---------------------------------------------------------------------------*
623 * handle incoming IFSTATE_CHANGED indication
624 *---------------------------------------------------------------------------*/
625 void
626 msg_ifstatechg_ind(msg_ifstatechg_ind_t *mp)
628 cfg_entry_t *cep;
629 char *device;
631 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
633 log(LL_WRN, "msg_negcomp_ind: cdid not found");
634 return;
637 device = bdrivername(cep->usrdevicename);
638 log(LL_DBG, "%s%d: switched to state %d", device, cep->usrdeviceunit, mp->state);
641 /*---------------------------------------------------------------------------*
642 * handle incoming DISCONNECT_IND message
643 *---------------------------------------------------------------------------*/
644 void
645 msg_disconnect_ind(msg_disconnect_ind_t *mp)
647 cfg_entry_t *cep;
649 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
651 log(LL_WRN, "msg_disconnect_ind: cdid not found");
652 return;
655 /* is this an aborted out-call prematurely called back? */
656 if (cep->saved_call.cdid == mp->header.cdid)
658 DBGL(DL_CNST, (log(LL_DBG, "aborted outcall %05d disconnected",
659 mp->header.cdid)));
660 cep->saved_call.cdid = CDID_UNUSED;
662 set_channel_idle(cep->saved_call.controller, cep->saved_call.channel);
664 incr_free_channels(cep->saved_call.controller);
665 return;
668 cep->last_release_time = time(NULL);
669 cep->disc_cause = mp->cause;
671 if(cep->direction == DIR_OUT)
673 log(LL_CHD, "%05d %s outgoing call disconnected %s",
674 cep->cdid, cep->name,
675 cep->local_disconnect == DISCON_LOC ?
676 "(local)" : "(remote)");
678 else
680 log(LL_CHD, "%05d %s incoming call disconnected %s",
681 cep->cdid, cep->name,
682 cep->local_disconnect == DISCON_LOC ?
683 "(local)" : "(remote)");
686 log(LL_CHD, "%05d %s cause %s",
687 cep->cdid, cep->name, print_i4b_cause(mp->cause));
689 #ifdef USE_CURSES
690 if(do_fullscreen && (cep->connect_time > 0))
691 display_disconnect(cep);
692 #endif
693 #ifdef I4B_EXTERNAL_MONITOR
694 if(do_monitor && accepted)
695 monitor_evnt_disconnect(cep);
696 #endif
698 if(cep->disconnectprog)
699 exec_connect_prog(cep, cep->disconnectprog, 1);
701 if(cep->connect_time > 0)
703 if(cep->direction == DIR_OUT)
705 log(LL_CHD, "%05d %s charging: %d units, %d seconds",
706 cep->cdid, cep->name, cep->charge,
707 (int)difftime(time(NULL), cep->connect_time));
709 else
711 log(LL_CHD, "%05d %s connected %d seconds",
712 cep->cdid, cep->name,
713 (int)difftime(time(NULL), cep->connect_time));
716 if((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
718 if((cep->ioutbytes != cep->outbytes) ||
719 (cep->iinbytes != cep->inbytes))
721 log(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
722 cep->cdid, cep->name,
723 cep->inbytes, cep->outbytes,
724 cep->iinbytes, cep->ioutbytes);
726 else
728 log(LL_CHD, "%05d %s accounting: in %d, out %d",
729 cep->cdid, cep->name,
730 cep->inbytes, cep->outbytes);
735 if(useacctfile && (cep->connect_time > 0))
737 int con_secs;
738 char logdatetime[41];
739 struct tm *tp;
741 con_secs = difftime(time(NULL), cep->connect_time);
743 tp = localtime(&cep->connect_time);
745 strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
747 if(cep->inbytes != INVALID && cep->outbytes != INVALID)
749 fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
750 logdatetime, getlogdatetime(),
751 cep->name, cep->charge, con_secs,
752 cep->inbytes, cep->outbytes);
754 else
756 fprintf(acctfp, "%s - %s %s %d (%d)\n",
757 logdatetime, getlogdatetime(),
758 cep->name, cep->charge, con_secs);
762 /* set the B-channel inactive */
764 set_channel_idle(cep->isdncontrollerused, cep->isdnchannelused);
766 incr_free_channels(cep->isdncontrollerused);
768 cep->connect_time = 0;
769 cep->cdid = CDID_UNUSED;
771 next_state(cep, EV_MDI);
774 /*---------------------------------------------------------------------------*
775 * handle incoming DIALOUT message
776 *---------------------------------------------------------------------------*/
777 void
778 msg_dialout(msg_dialout_ind_t *mp)
780 cfg_entry_t *cep;
782 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: dial req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
784 if((cep = find_by_device_for_dialout(mp->driver, mp->driver_unit)) == NULL)
786 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: config entry reserved or no match")));
787 return;
790 if(cep->inout == DIR_INONLY)
792 dialresponse(cep, DSTAT_INONLY);
793 return;
796 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
798 cep->budget_calltype = 0;
799 cep->budget_callout_req++;
801 if(cep->budget_calloutncalls_cnt == 0)
803 log(LL_CHD, "%05d %s no budget for calling out", 0, cep->name);
804 cep->budget_callout_rej++;
805 dialresponse(cep, DSTAT_TFAIL);
806 return;
808 else
810 cep->budget_calltype = BUDGET_TYPE_COUT;
814 if((cep->cdid = get_cdid()) == 0)
816 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: get_cdid() returned 0!")));
817 return;
820 cep->charge = 0;
821 cep->last_charge = 0;
822 cep->hangup = 0;
824 next_state(cep, EV_MDO);
827 /*---------------------------------------------------------------------------*
828 * handle incoming DIALOUTNUMBER message
829 *---------------------------------------------------------------------------*/
830 void
831 msg_dialoutnumber(msg_dialoutnumber_ind_t *mp)
833 cfg_entry_t *cep;
835 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialoutnumber: dial req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
837 if((cep = find_by_device_for_dialoutnumber(mp->driver, mp->driver_unit, mp->cmdlen, mp->cmd)) == NULL)
839 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialoutnumber: config entry reserved or no match")));
840 return;
843 if(cep->inout == DIR_INONLY)
845 dialresponse(cep, DSTAT_INONLY);
846 return;
849 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
851 cep->budget_calltype = 0;
852 cep->budget_callout_req++;
854 if(cep->budget_calloutncalls_cnt == 0)
856 log(LL_CHD, "%05d %s no budget for calling out", 0, cep->name);
857 cep->budget_callout_rej++;
858 dialresponse(cep, DSTAT_TFAIL);
859 return;
861 else
863 cep->budget_calltype = BUDGET_TYPE_COUT;
867 if((cep->cdid = get_cdid()) == 0)
869 DBGL(DL_DRVR, (log(LL_DBG, "msg_dialoutnumber: get_cdid() returned 0!")));
870 return;
873 cep->keypad[0] = '\0';
874 cep->charge = 0;
875 cep->last_charge = 0;
876 cep->hangup = 0;
878 next_state(cep, EV_MDO);
881 /*---------------------------------------------------------------------------*
882 * handle incoming KEYPAD message
883 *---------------------------------------------------------------------------*/
884 void
885 msg_keypad(msg_keypad_ind_t *mp)
887 cfg_entry_t *cep;
889 DBGL(DL_DRVR, (log(LL_DBG, "msg_keypad: dial req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
891 if((cep = find_by_device_for_keypad(mp->driver, mp->driver_unit, mp->cmdlen, mp->cmd)) == NULL)
893 DBGL(DL_DRVR, (log(LL_DBG, "msg_keypad: config entry reserved or no match")));
894 return;
897 if(cep->inout == DIR_INONLY)
899 dialresponse(cep, DSTAT_INONLY);
900 return;
903 if(cep->budget_calloutperiod && cep->budget_calloutncalls)
905 cep->budget_calltype = 0;
906 cep->budget_callout_req++;
908 if(cep->budget_calloutncalls_cnt == 0)
910 log(LL_CHD, "%05d %s no budget for calling out", 0, cep->name);
911 cep->budget_callout_rej++;
912 dialresponse(cep, DSTAT_TFAIL);
913 return;
915 else
917 cep->budget_calltype = BUDGET_TYPE_COUT;
921 if((cep->cdid = get_cdid()) == 0)
923 DBGL(DL_DRVR, (log(LL_DBG, "msg_keypad: get_cdid() returned 0!")));
924 return;
927 cep->charge = 0;
928 cep->last_charge = 0;
929 cep->hangup = 0;
931 next_state(cep, EV_MDO);
934 /*---------------------------------------------------------------------------*
935 * handle incoming DRVRDISC_REQ message
936 *---------------------------------------------------------------------------*/
937 void
938 msg_drvrdisc_req(msg_drvrdisc_req_t *mp)
940 cfg_entry_t *cep;
942 DBGL(DL_DRVR, (log(LL_DBG, "msg_drvrdisc_req: req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
944 if((cep = get_cep_by_driver(mp->driver, mp->driver_unit)) == NULL)
946 DBGL(DL_DRVR, (log(LL_DBG, "msg_drvrdisc_req: config entry not found")));
947 return;
949 next_state(cep, EV_DRQ);
952 /*---------------------------------------------------------------------------*
953 * handle incoming ACCOUNTING message
954 *---------------------------------------------------------------------------*/
955 void
956 msg_accounting(msg_accounting_ind_t *mp)
958 cfg_entry_t *cep;
960 if((cep = find_active_entry_by_driver(mp->driver, mp->driver_unit)) == NULL)
962 log(LL_WRN, "msg_accounting: no config entry found!");
963 return;
966 cep->inbytes = mp->inbytes;
967 cep->iinbytes = mp->iinbytes;
968 cep->outbytes = mp->outbytes;
969 cep->ioutbytes = mp->ioutbytes;
970 cep->inbps = mp->inbps;
971 cep->outbps = mp->outbps;
973 if(mp->accttype == ACCT_DURING)
975 #ifdef USE_CURSES
976 if(do_fullscreen)
977 display_acct(cep);
978 #endif
979 #ifdef I4B_EXTERNAL_MONITOR
980 if(do_monitor && accepted)
981 monitor_evnt_acct(cep);
982 #endif
986 /*---------------------------------------------------------------------------*
987 * handle incoming CHARGING message
988 *---------------------------------------------------------------------------*/
989 void
990 msg_charging_ind(msg_charging_ind_t *mp)
992 static char *cttab[] = {
993 "invalid",
994 "AOCD",
995 "AOCE",
996 "estimated" };
998 cfg_entry_t *cep;
1000 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
1002 log(LL_WRN, "msg_charging_ind: cdid not found");
1003 return;
1006 if(mp->units_type < CHARGE_INVALID || mp->units_type > CHARGE_CALC)
1008 log(LL_ERR, "msg_charging: units_type %d out of range!", mp->units_type);
1009 error_exit(1, "msg_charging: units_type %d out of range!", mp->units_type);
1012 DBGL(DL_DRVR, (log(LL_DBG, "msg_charging: %d unit(s) (%s)",
1013 mp->units, cttab[mp->units_type])));
1015 cep->charge = mp->units;
1017 switch(mp->units_type)
1019 case CHARGE_AOCD:
1020 if((cep->unitlengthsrc == ULSRC_DYN) &&
1021 (cep->charge != cep->last_charge))
1023 cep->last_charge = cep->charge;
1024 handle_charge(cep);
1026 break;
1028 case CHARGE_CALC:
1029 #ifdef USE_CURSES
1030 if(do_fullscreen)
1031 display_ccharge(cep, mp->units);
1032 #endif
1033 #ifdef I4B_EXTERNAL_MONITOR
1034 if(do_monitor && accepted)
1035 monitor_evnt_charge(cep, mp->units, 1);
1036 #endif
1037 break;
1041 /*---------------------------------------------------------------------------*
1042 * handle incoming IDLE_TIMEOUT_IND message
1043 *---------------------------------------------------------------------------*/
1044 void
1045 msg_idle_timeout_ind(msg_idle_timeout_ind_t *mp)
1047 cfg_entry_t *cep;
1049 if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
1051 log(LL_WRN, "msg_idle_timeout_ind: cdid not found!");
1052 return;
1055 cep->local_disconnect = DISCON_LOC;
1057 DBGL(DL_DRVR, (log(LL_DBG, "msg_idle_timeout_ind: idletimeout, kernel sent disconnect!")));
1059 check_and_kill(cep);
1062 /*---------------------------------------------------------------------------*
1063 * handle incoming MSG_PACKET_IND message
1064 *---------------------------------------------------------------------------*/
1065 static char *
1066 strapp(char *buf, const char *txt)
1068 while(*txt)
1069 *buf++ = *txt++;
1070 *buf = '\0';
1071 return buf;
1074 /*---------------------------------------------------------------------------*
1075 * handle incoming MSG_PACKET_IND message
1076 *---------------------------------------------------------------------------*/
1077 static char *
1078 ipapp(char *buf, unsigned long a )
1080 unsigned long ma = ntohl( a );
1082 buf += sprintf(buf, "%lu.%lu.%lu.%lu",
1083 (ma>>24)&0xFF,
1084 (ma>>16)&0xFF,
1085 (ma>>8)&0xFF,
1086 (ma)&0xFF);
1087 return buf;
1090 /*---------------------------------------------------------------------------*
1091 * handle incoming MSG_PACKET_IND message
1092 *---------------------------------------------------------------------------*/
1093 void
1094 msg_packet_ind(msg_packet_ind_t *mp)
1096 cfg_entry_t *cep;
1097 struct ip *ip;
1098 u_char *proto_hdr;
1099 char tmp[80];
1100 char *cptr = tmp;
1101 char *name = "???";
1102 int i;
1104 for(i=0; i < nentries; i++)
1106 cep = &cfg_entry_tab[i]; /* ptr to config entry */
1108 if(cep->usrdevicename == mp->driver &&
1109 cep->usrdeviceunit == mp->driver_unit)
1111 name = cep->name;
1112 break;
1116 ip = (struct ip*)mp->pktdata;
1117 proto_hdr = mp->pktdata + ((ip->ip_hl)<<2);
1119 if( ip->ip_p == IPPROTO_TCP )
1121 struct tcphdr* tcp = (struct tcphdr*)proto_hdr;
1123 cptr = strapp( cptr, "TCP " );
1124 cptr = ipapp( cptr, ip->ip_src.s_addr );
1125 cptr += sprintf( cptr, ":%u -> ", ntohs( tcp->th_sport ) );
1126 cptr = ipapp( cptr, ip->ip_dst.s_addr );
1127 cptr += sprintf( cptr, ":%u", ntohs( tcp->th_dport ) );
1129 if(tcp->th_flags & TH_FIN) cptr = strapp( cptr, " FIN" );
1130 if(tcp->th_flags & TH_SYN) cptr = strapp( cptr, " SYN" );
1131 if(tcp->th_flags & TH_RST) cptr = strapp( cptr, " RST" );
1132 if(tcp->th_flags & TH_PUSH) cptr = strapp( cptr, " PUSH" );
1133 if(tcp->th_flags & TH_ACK) cptr = strapp( cptr, " ACK" );
1134 if(tcp->th_flags & TH_URG) cptr = strapp( cptr, " URG" );
1136 else if( ip->ip_p == IPPROTO_UDP )
1138 struct udphdr* udp = (struct udphdr*)proto_hdr;
1140 cptr = strapp( cptr, "UDP " );
1141 cptr = ipapp( cptr, ip->ip_src.s_addr );
1142 cptr += sprintf( cptr, ":%u -> ", ntohs( udp->uh_sport ) );
1143 cptr = ipapp( cptr, ip->ip_dst.s_addr );
1144 cptr += sprintf( cptr, ":%u", ntohs( udp->uh_dport ) );
1146 else if( ip->ip_p == IPPROTO_ICMP )
1148 struct icmp* icmp = (struct icmp*)proto_hdr;
1150 cptr += sprintf( cptr, "ICMP:%u.%u", icmp->icmp_type, icmp->icmp_code);
1151 cptr = ipapp( cptr, ip->ip_src.s_addr );
1152 cptr = strapp( cptr, " -> " );
1153 cptr = ipapp( cptr, ip->ip_dst.s_addr );
1155 else
1157 cptr += sprintf( cptr, "PROTO=%u ", ip->ip_p);
1158 cptr = ipapp( cptr, ip->ip_src.s_addr);
1159 cptr = strapp( cptr, " -> " );
1160 cptr = ipapp( cptr, ip->ip_dst.s_addr);
1163 log(LL_PKT, "%s %s %u %s",
1164 name, mp->direction ? "send" : "recv",
1165 ntohs( ip->ip_len ), tmp );
1168 /*---------------------------------------------------------------------------*
1169 * get a cdid from kernel
1170 *---------------------------------------------------------------------------*/
1172 get_cdid(void)
1174 msg_cdid_req_t mcr;
1176 mcr.cdid = 0;
1178 if((ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0)
1180 log(LL_ERR, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno));
1181 error_exit(1, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno));
1184 return(mcr.cdid);
1187 /*---------------------------------------------------------------------------*
1188 * send message "connect request" to kernel
1189 *---------------------------------------------------------------------------*/
1191 sendm_connect_req(cfg_entry_t *cep)
1193 msg_connect_req_t mcr;
1194 int ret;
1196 cep->local_disconnect = DISCON_REM;
1198 cep->unitlength = get_current_rate(cep, 1);
1200 mcr.cdid = cep->cdid;
1202 mcr.controller = cep->isdncontrollerused;
1203 mcr.channel = cep->isdnchannelused;
1204 mcr.txdelay = cep->isdntxdelout;
1206 mcr.bprot = cep->b1protocol;
1208 mcr.driver = cep->usrdevicename;
1209 mcr.driver_unit = cep->usrdeviceunit;
1211 /* setup the shorthold data */
1212 mcr.shorthold_data.shorthold_algorithm = cep->shorthold_algorithm;
1213 mcr.shorthold_data.unitlen_time = cep->unitlength;
1214 mcr.shorthold_data.idle_time = cep->idle_time_out;
1215 mcr.shorthold_data.earlyhup_time = cep->earlyhangup;
1217 if(cep->unitlengthsrc == ULSRC_DYN)
1218 mcr.unitlen_method = ULEN_METHOD_DYNAMIC;
1219 else
1220 mcr.unitlen_method = ULEN_METHOD_STATIC;
1222 strcpy(mcr.dst_telno, cep->remote_phone_dialout);
1223 strcpy(mcr.src_telno, cep->local_phone_dialout);
1224 strcpy(mcr.keypad, cep->keypad);
1226 cep->last_dial_time = time(NULL);
1227 cep->direction = DIR_OUT;
1229 DBGL(DL_CNST, (log(LL_DBG, "sendm_connect_req: ctrl = %d, chan = %d", cep->isdncontrollerused, cep->isdnchannelused)));
1231 if((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0)
1233 log(LL_ERR, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
1234 error_exit(1, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
1237 decr_free_channels(cep->isdncontrollerused);
1239 log(LL_CHD, "%05d %s dialing out from %s to %s",
1240 cep->cdid,
1241 cep->name,
1242 aliasing ? get_alias(cep->local_phone_dialout) : cep->local_phone_dialout,
1243 aliasing ? get_alias(cep->remote_phone_dialout) : cep->remote_phone_dialout);
1245 return(ret);
1248 /*---------------------------------------------------------------------------*
1249 * send message "connect response" to kernel
1250 *---------------------------------------------------------------------------*/
1252 sendm_connect_resp(cfg_entry_t *cep, int cdid, int response, cause_t cause)
1254 msg_connect_resp_t mcr;
1255 int ret;
1257 mcr.cdid = cdid;
1259 mcr.response = response;
1261 if(response == SETUP_RESP_REJECT)
1263 mcr.cause = cause;
1264 DBGL(DL_DRVR, (log(LL_DBG, "sendm_connect_resp: reject, cause=0x%x", cause)));
1266 else if(response == SETUP_RESP_ACCEPT)
1268 cep->direction = DIR_IN;
1270 mcr.txdelay = cep->isdntxdelin;
1272 mcr.bprot = cep->b1protocol;
1274 mcr.driver = cep->usrdevicename;
1275 mcr.driver_unit = cep->usrdeviceunit;
1277 mcr.max_idle_time = cep->idle_time_in;
1279 DBGL(DL_DRVR, (log(LL_DBG, "sendm_connect_resp: accept")));
1282 if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &mcr)) < 0)
1284 log(LL_ERR, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno));
1285 error_exit(1, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno));
1287 return(ret);
1290 /*---------------------------------------------------------------------------*
1291 * send message "disconnect request" to kernel
1292 *---------------------------------------------------------------------------*/
1294 sendm_disconnect_req(cfg_entry_t *cep, cause_t cause)
1296 msg_discon_req_t mcr;
1297 int ret = 0;
1299 mcr.cdid = cep->cdid;
1301 mcr.cause = cause;
1303 cep->local_disconnect = DISCON_LOC;
1305 if((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mcr)) < 0)
1307 log(LL_ERR, "sendm_disconnect_req: ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno));
1309 else
1311 DBGL(DL_DRVR, (log(LL_DBG, "sendm_disconnect_req: sent DISCONNECT_REQ")));
1313 return(ret);
1316 /*---------------------------------------------------------------------------*
1317 * send message "alert request" to kernel
1318 *---------------------------------------------------------------------------*/
1320 sendm_alert_req(cfg_entry_t *cep)
1322 msg_alert_req_t mar;
1323 int ret;
1325 mar.cdid = cep->cdid;
1327 if((ret = ioctl(isdnfd, I4B_ALERT_REQ, &mar)) < 0)
1329 log(LL_ERR, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno));
1330 error_exit(1, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno));
1332 else
1334 DBGL(DL_DRVR, (log(LL_DBG, "sendm_alert_req: sent ALERT_REQ")));
1336 return(ret);
1339 /* EOF */