1815 lines
54 KiB
C
1815 lines
54 KiB
C
/* $Id: isdnctrl.c,v 1.52 2003/03/11 13:46:56 paul Exp $
|
|
* ISDN driver for Linux. (Control-Utility)
|
|
*
|
|
* Copyright 1994,95 by Fritz Elfert (fritz@isdn4linux.de)
|
|
* Copyright 1995 Thinking Objects Software GmbH Wuerzburg
|
|
*
|
|
* This file is part of Isdn4Linux.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
* $Log: isdnctrl.c,v $
|
|
* Revision 1.52 2003/03/11 13:46:56 paul
|
|
* "status all" would show also non-ISDN interfaces, this is now fixed.
|
|
* "status active" added, this shows only those interfaces that are connected.
|
|
*
|
|
* Revision 1.51 2003/02/24 17:22:22 keil
|
|
* - don't allow users to change setup
|
|
*
|
|
* Revision 1.50 2002/01/31 19:53:41 paul
|
|
* Fixed error messages when opening /dev/isdnctrl - /dev/isdn/isdnctrl etc.,
|
|
* only /dev/isdnctrl was mentioned and people assumed that isdnctrl wasn't
|
|
* devfs-compliant yet when the open failed due to other reasons.
|
|
* Zero the phone struct before use.
|
|
*
|
|
* Revision 1.49 2001/06/11 17:55:58 paul
|
|
* Added 'break' statement after handling data version 5 (otherwise fallthrough
|
|
* into data version 6 handling!!)
|
|
*
|
|
* Revision 1.48 2001/05/23 14:59:23 kai
|
|
* removed traces of TIMRU. I hope it's been dead for a long enough time now.
|
|
*
|
|
* Revision 1.47 2001/05/23 14:48:23 kai
|
|
* make isdnctrl independent of the version of installed kernel headers,
|
|
* we have our own copy now.
|
|
*
|
|
* Revision 1.46 2001/03/15 22:02:44 kai
|
|
* fixed a stack overflow when using isdnctrl status
|
|
*
|
|
* Revision 1.45 2001/03/01 14:59:15 paul
|
|
* Various patches to fix errors when using the newest glibc,
|
|
* replaced use of insecure tempnam() function
|
|
* and to remove warnings etc.
|
|
*
|
|
* Revision 1.44 2000/08/17 09:24:06 paul
|
|
* Added --version option to display (isdn4k-utils) version,
|
|
* and fixed a compile warning on alpha.
|
|
*
|
|
* Revision 1.43 2000/06/29 17:38:26 akool
|
|
* - Ported "imontty", "isdnctrl", "isdnlog", "xmonisdn" and "hisaxctrl" to
|
|
* Linux-2.4 "devfs" ("/dev/isdnctrl" -> "/dev/isdn/isdnctrl")
|
|
*
|
|
* Revision 1.42 2000/04/27 06:32:28 calle
|
|
* DriverId can be longer than 8 for "mapping" and "busreject".
|
|
*
|
|
* Revision 1.41 2000/04/12 21:49:40 detabc
|
|
* add test for maybe undefined IIOCNETDWRSET define
|
|
*
|
|
* Revision 1.40 2000/01/27 15:08:09 paul
|
|
* Error messages from addlink/removelink are now userfriendly.
|
|
*
|
|
* Revision 1.39 1999/11/23 10:17:27 paul
|
|
* Made error message for 'status' command clearer if IIOCNETGPN
|
|
* is not implemented in kernel (e.g. 2.0.x kernels).
|
|
*
|
|
* Revision 1.38 1999/11/20 22:23:53 detabc
|
|
* added netinterface abc-secure-counter reset (clear) support.
|
|
*
|
|
* Revision 1.37 1999/11/07 22:04:05 detabc
|
|
* add dwabc-udpinfo-utilitys in isdnctrl
|
|
*
|
|
* Revision 1.36 1999/11/02 20:41:21 keil
|
|
* make phonenumber ioctl compatible for ctrlconf too
|
|
*
|
|
* Revision 1.35 1999/10/27 14:36:19 keil
|
|
* make the phone number struct compatible between NET_DV 5 and 6
|
|
*
|
|
* Revision 1.34 1999/09/06 08:03:25 fritz
|
|
* Changed my mail-address.
|
|
*
|
|
* Revision 1.33 1999/06/07 19:25:38 paul
|
|
* isdnctrl.man.in
|
|
*
|
|
* Revision 1.32 1998/12/23 12:51:44 paul
|
|
* didn't compile with old kernel source
|
|
*
|
|
* Revision 1.31 1998/11/24 18:18:57 paul
|
|
* detect kernel < 2.0.36; warn if dialmode is accessed with older kernels
|
|
*
|
|
* Revision 1.30 1998/11/18 13:20:07 fritz
|
|
* Fixed display of dialmode.
|
|
*
|
|
* Revision 1.29 1998/11/17 18:29:31 paul
|
|
* isdnctrl.c now compiles with kernel sources without dialmode stuff.
|
|
*
|
|
* Revision 1.28 1998/11/11 23:53:02 fritz
|
|
* Make isdnctrl compile without TIMRU in kernel (2.0.36-pre20/21)
|
|
*
|
|
* Revision 1.27 1998/10/28 16:12:18 paul
|
|
* Implemented "dialmode all" mode.
|
|
*
|
|
* Revision 1.26 1998/10/21 16:18:45 paul
|
|
* Implementation of "dialmode" (successor of "status")
|
|
*
|
|
* Revision 1.25 1998/07/22 19:07:20 keil
|
|
* Make it compiling with older I4L versions
|
|
*
|
|
* Revision 1.24 1998/06/27 00:36:19 fritz
|
|
* Misc. Fixes.
|
|
* Added fallback to libdb for isdnctrl.
|
|
* Added -V version check in isdnctrl.
|
|
*
|
|
* Revision 1.23 1998/06/12 12:09:53 detabc
|
|
* cleanup abc
|
|
*
|
|
* Revision 1.22 1998/06/09 18:11:31 cal
|
|
* added the command "isdnctrl name ifdefaults": the named device is reset
|
|
* to some reasonable defaults.
|
|
*
|
|
* Internally, isdnctrl.c contains a list of functions (defs_fcns []), which
|
|
* are called one after the other with the interface-name as a patameter.
|
|
* Each function returns a char* to a string containing iscnctrl-commands
|
|
* to be executed. Example:
|
|
*
|
|
* char *
|
|
* defs_budget(char *id) {
|
|
* static char r [1024];
|
|
* char *p = r;
|
|
*
|
|
* p += sprintf(p, "budget %s dial 10 1min\n", id);
|
|
* p += sprintf(p, "budget %s charge 100 1day\n", id);
|
|
* p += sprintf(p, "budget %s online 8hour 1day\n", id);
|
|
*
|
|
* return(r);
|
|
* }
|
|
*
|
|
* The advantage of this approach is, that even complex commands can be executed.
|
|
*
|
|
* PS: The function defs_basic() in isdnctrl.c is not complete.
|
|
*
|
|
* Revision 1.21 1998/06/02 12:17:15 detabc
|
|
* wegen einer einstweiliger verfuegung gegen DW ist zur zeit
|
|
* die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
|
|
*
|
|
* Revision 1.20 1998/04/28 08:34:28 paul
|
|
* Fixed compiler warnings from egcs.
|
|
*
|
|
* Revision 1.19 1998/04/18 17:36:13 detabc
|
|
* modify display of callbackdelay (cbdelay) value to %.1f sec.
|
|
* if abc-extension is enabled
|
|
*
|
|
* Revision 1.18 1998/03/21 17:10:36 detabc
|
|
* change to use the abc-ext-options -TU on all encapsulations
|
|
* the option -A (abc-router) will only works with rawip
|
|
*
|
|
* Revision 1.17 1998/03/19 15:39:02 detabc
|
|
* change define CONFIG_ISDN_WITH_ABC to HAVE_ABCEXT.
|
|
* HAVE_ABCEXT will be set with the configure utility.
|
|
* to enable isdnctrl with ABC-Extension-support please make
|
|
* first a kernelconfig with ABC-Extension enabled.
|
|
* Thanks
|
|
*
|
|
* Revision 1.16 1998/03/12 15:10:11 hipp
|
|
* Cosmetic. Changed 'addlink' error message.
|
|
*
|
|
* Revision 1.15 1998/03/08 01:04:19 fritz
|
|
* Fix: Did not compile without TIMRU in kernel.
|
|
*
|
|
* Revision 1.14 1998/03/08 00:18:25 detabc
|
|
* include config-support for abc-extension
|
|
* only isdnctrl encap will be used and only use the options [-ATU]rawip
|
|
* thanks
|
|
*
|
|
* Revision 1.13 1998/03/07 18:25:57 cal
|
|
* added support for dynamic timeout-rules vs. 971110
|
|
*
|
|
* Revision 1.12 1997/10/26 23:12:20 fritz
|
|
* Get rid of including ../.config in Makefile
|
|
* Now all configuration is done in configure.
|
|
*
|
|
* Revision 1.11 1997/09/26 09:07:18 fritz
|
|
* Check for missing triggercps in configuration.
|
|
*
|
|
* Revision 1.10 1997/09/11 19:03:32 fritz
|
|
* Bugfix: Tried to get Version-Info on wrong device.
|
|
*
|
|
* Revision 1.9 1997/08/21 14:47:00 fritz
|
|
* Added Version-Checking of NET_DV.
|
|
*
|
|
* Revision 1.8 1997/07/30 20:09:24 luethje
|
|
* the call "isdnctrl pppbind ipppX" will be bound the interface to X
|
|
*
|
|
* Revision 1.7 1997/07/23 20:39:15 luethje
|
|
* added the option "force" for the commands delif and reset
|
|
*
|
|
* Revision 1.6 1997/07/22 22:36:10 luethje
|
|
* isdnrep: Use " " for blanks
|
|
* isdnctrl: Add the option "reset"
|
|
*
|
|
* Revision 1.5 1997/07/20 16:36:26 calle
|
|
* isdnctrl trigger was not working.
|
|
*
|
|
* Revision 1.4 1997/06/24 23:35:26 luethje
|
|
* isdnctrl can use a config file
|
|
*
|
|
* Revision 1.3 1997/06/22 11:58:21 fritz
|
|
* Added ability to adjust slave triggerlevel.
|
|
*
|
|
* Revision 1.2 1997/03/10 09:51:24 fritz
|
|
* Bugfix: mapping was broken.
|
|
*
|
|
* Revision 1.1 1997/02/17 00:09:21 fritz
|
|
* New CVS tree
|
|
*
|
|
* Revision 1.14 1996/06/06 22:08:46 fritz
|
|
* Bugfix: verbose and getconf checked wrong number of parameters.
|
|
* thanks to Andreas Jaeger <aj@arthur.pfalz.de>
|
|
*
|
|
* Revision 1.13 1996/04/30 12:48:35 fritz
|
|
* Added Michael's ippp-bind patch.
|
|
*
|
|
* Revision 1.12 1996/04/30 12:43:18 fritz
|
|
* Changed ioctl-names according to kernel-version
|
|
*
|
|
* Revision 1.11 1996/01/04 02:44:52 fritz
|
|
* Changed copying policy to GPL
|
|
* Added addslave, dial, sdelay and mapping.
|
|
*
|
|
* Revision 1.10 1995/12/18 18:03:19 fritz
|
|
* New License, minor cleanups.
|
|
*
|
|
* Revision 1.9 1995/10/29 21:38:51 fritz
|
|
* Changed all references to driver-numbers to new DriverId's
|
|
*
|
|
* Revision 1.8 1995/07/15 20:39:56 fritz
|
|
* Added support for cisco_h Encapsulation.
|
|
* Added suppurt for pre-binding an interface to a channel.
|
|
*
|
|
* Revision 1.7 1995/04/29 13:13:44 fritz
|
|
* Added new command verbose.
|
|
*
|
|
* Revision 1.6 1995/04/23 13:38:34 fritz
|
|
* Adapted addphone and delphone to support changes in isdn.c
|
|
*
|
|
* Revision 1.5 1995/03/25 23:35:35 fritz
|
|
* Added ihup-Feature.
|
|
*
|
|
* Revision 1.4 1995/03/15 12:44:15 fritz
|
|
* Added generic conversion-routines for keyword<->value conversion.
|
|
* Added display of phone-numbers in list-routine
|
|
* Corrected some typos
|
|
*
|
|
* Revision 1.3 1995/02/20 03:38:59 fritz
|
|
* Added getmax and rmax for performance-tests of tty-driver.
|
|
*
|
|
* Revision 1.2 1995/01/29 23:27:52 fritz
|
|
* Added keywords: list, l2_proto, l3_proto, huptimeout, chargehup and
|
|
* encap.
|
|
*
|
|
* Revision 1.1 1995/01/09 07:35:35 fritz
|
|
* Initial revision
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#include "config.h"
|
|
#define _ISDNCTRL_C_
|
|
#include "isdnctrl.h"
|
|
|
|
#ifdef I4L_DWABC_UDPINFO
|
|
#include <isdn_dwabclib.h>
|
|
#endif
|
|
|
|
#ifdef I4L_CTRL_CONF
|
|
# include "../lib/libisdn.h"
|
|
# include "ctrlconf.h"
|
|
#endif /* I4L_CTRL_CONF */
|
|
|
|
#define CMD_IFCONFIG "ifconfig"
|
|
#define CMD_OPT_IFCONFIG "down"
|
|
|
|
|
|
/* list of functions to obtain default-configuration of interface */
|
|
typedef char *(*defs_fcn_t)();
|
|
|
|
defs_fcn_t defs_fcns [] = {
|
|
defs_basic,
|
|
NULL
|
|
};
|
|
|
|
char nextslaveif[10];
|
|
|
|
int set_isdn_net_ioctl_phone(isdn_net_ioctl_phone *ph, char *name,
|
|
char *phone, int outflag)
|
|
{
|
|
switch (data_version) {
|
|
case 0x04:
|
|
case 0x05:
|
|
if (strlen(phone) > 19) {
|
|
fprintf(stderr, "phone-number must not exceed %d characters\n", 19);
|
|
return -1;
|
|
}
|
|
/*
|
|
* null termination happens automatically because
|
|
* we clear the entire struct first
|
|
*/
|
|
strncpy(ph->phone_5.name, name, sizeof(ph->phone_5.name)-1);
|
|
strncpy(ph->phone_5.phone, phone, sizeof(ph->phone_5.phone)-1);
|
|
ph->phone_5.outgoing = outflag;
|
|
break;
|
|
case 0x06:
|
|
if (strlen(phone) > 31) {
|
|
fprintf(stderr, "phone-number must not exceed %d characters\n", 31);
|
|
return -1;
|
|
}
|
|
strncpy(ph->phone_6.name, name, sizeof(ph->phone_6.name)-1);
|
|
strncpy(ph->phone_6.phone, phone, sizeof(ph->phone_6.phone)-1);
|
|
ph->phone_6.outgoing = outflag;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int exec_args(int fd, int argc, char **argv);
|
|
|
|
void usage(void)
|
|
{
|
|
fprintf(stderr, "%s version %s\n", cmd, VERSION);
|
|
fprintf(stderr, "usage: %s <command> <options>\n", cmd);
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "where <command> is one of the following:\n");
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, " addif [name] add net-interface\n");
|
|
fprintf(stderr, " delif name [force] remove net-interface\n");
|
|
fprintf(stderr, " reset [force] remove all net-interfaces\n");
|
|
fprintf(stderr, " dialmode name [off|manual|auto] set the dial mode\n");
|
|
fprintf(stderr, " addphone name in|out num add phone-number to interface\n");
|
|
fprintf(stderr, " delphone name in|out num remove phone-number from interface\n");
|
|
fprintf(stderr, " eaz name [eaz|msn] get/set eaz for interface\n");
|
|
fprintf(stderr, " huptimeout name [seconds] get/set hangup-timeout for interface\n");
|
|
fprintf(stderr, " ihup name [on|off] get/set incoming-hangup for interface\n");
|
|
fprintf(stderr, " chargehup name [on|off] get/set charge-hangup for interface\n");
|
|
fprintf(stderr, " chargeint name [seconds] get/set charge-interval if not given by telco\n");
|
|
fprintf(stderr, " secure name [on|off] get/set secure-feature for interface\n");
|
|
fprintf(stderr, " callback name [in|outon|off]\n");
|
|
fprintf(stderr, " get/set active callback-feature for interface\n");
|
|
fprintf(stderr, " cbhup name [on|off] get/set reject-before-callback for interface\n");
|
|
fprintf(stderr, " cbdelay name [seconds] get/set delay before callback for interface\n");
|
|
fprintf(stderr, " dialmax name [num] get/set number of dial-atempts for interface\n");
|
|
fprintf(stderr, " dialtimeout name [seconds] get/set timeout for successful dial-attempt\n");
|
|
fprintf(stderr, " dialwait name [seconds] get/set waittime after failed dial-attempt\n");
|
|
fprintf(stderr, " encap name [encapname] get/set packet-encapsulation for interface\n");
|
|
fprintf(stderr, " l2_prot name [protocol] get/set layer-2-protocol for interface\n");
|
|
fprintf(stderr, " l3_prot name [protocol] get/set layer-3-protocol for interface\n");
|
|
fprintf(stderr, " bind name [drvId,channel [exclusive]]\n");
|
|
fprintf(stderr, " pre-bind interface to a channel\n");
|
|
fprintf(stderr, " unbind name delete pre-binding\n");
|
|
fprintf(stderr, " list name|all show current setup of interface(s)\n");
|
|
fprintf(stderr, " verbose num set verbose-level\n");
|
|
fprintf(stderr, " hangup name force hangup of interface\n");
|
|
fprintf(stderr, " busreject drvId on|off set bus-reject-mode\n");
|
|
fprintf(stderr, " mapping drvId [MSN,MSN...] set MSN<->EAZ-Mapping\n");
|
|
fprintf(stderr, " addslave name slavename add slave-interface\n");
|
|
fprintf(stderr, " sdelay mastername delay set slave-activation delay\n");
|
|
fprintf(stderr, " trigger mastername cps set slave trigger level\n");
|
|
fprintf(stderr, " dial name force dialing of interface\n");
|
|
fprintf(stderr, " system on|off switch isdn-system on or off\n");
|
|
fprintf(stderr, " addlink name MPPP, increase number of links (dial)\n");
|
|
fprintf(stderr, " removelink name MPPP, decrease number of links (hangup)\n");
|
|
fprintf(stderr, " pppbind name [devicenum] PPP, bind interface to ippp-device (exclusive)\n");
|
|
fprintf(stderr, " pppunbind name PPP, remove ippp-device binding\n");
|
|
fprintf(stderr, " addrule name rule ... add timeout-rule\n");
|
|
fprintf(stderr, " insrule name rule ... insert timeout-rule\n");
|
|
fprintf(stderr, " delrule name rule ... delete timeout-rule\n");
|
|
fprintf(stderr, " showrules name show all timeout-rules\n");
|
|
fprintf(stderr, " flushrules name rule-type delete all timeout-rules of a spec. type\n");
|
|
fprintf(stderr, " flushallrules name delete all timeout-rules\n");
|
|
fprintf(stderr, " default name rule-type ... set default for a spec. rule-type\n");
|
|
fprintf(stderr, " budget name type ... set various budgets\n");
|
|
fprintf(stderr, " showbudgets name show budget-settings\n");
|
|
fprintf(stderr, " savebudgets name output budget-settings for later restore\n");
|
|
fprintf(stderr, " restorebudgets name ... restore budget-settings\n");
|
|
#ifdef I4L_CTRL_CONF
|
|
fprintf(stderr, " writeconf [file] write the settings to file\n");
|
|
fprintf(stderr, " readconf [file] read the settings from file\n");
|
|
#endif /* I4L_CTRL_CONF */
|
|
fprintf(stderr, " status name show interface status (connected or not)\n");
|
|
#ifdef I4L_DWABC_UDPINFO
|
|
fprintf(stderr, " abcclear name reset (clear) abc-secure-counter\n");
|
|
#endif
|
|
#ifdef I4L_DWABC_UDPINFO
|
|
fprintf(stderr," -udpisisdn destination-host or ip-number\n");
|
|
fprintf(stderr," -udponline destination-host or ip-number\n");
|
|
fprintf(stderr," -udphangup destination-host or ip-number\n");
|
|
fprintf(stderr," -udpdial destination-host or ip-number\n");
|
|
fprintf(stderr," -udpclear destination-host-or ip-number\n");
|
|
#endif
|
|
fprintf(stderr, " -V display API versions\n");
|
|
fprintf(stderr, " --version display isdnctrl version\n");
|
|
exit(-2);
|
|
}
|
|
|
|
int key2num(char *key, char **keytable, int *numtable)
|
|
{
|
|
int i = -1;
|
|
while (strlen(keytable[++i]))
|
|
if (!strcmp(keytable[i], key))
|
|
return numtable[i];
|
|
return -1;
|
|
}
|
|
|
|
int reset_interfaces(int fd, char *option)
|
|
{
|
|
FILE *iflst;
|
|
char *p;
|
|
char s[255];
|
|
char name[255];
|
|
char *argv[4] = {cmds[DELIF].cmd, name, option, NULL};
|
|
isdn_net_ioctl_cfg cfg;
|
|
|
|
|
|
if (option != NULL && strcmp(option, "force"))
|
|
{
|
|
usage();
|
|
return -1;
|
|
}
|
|
|
|
if ((iflst = fopen(FILE_PROC, "r")) == NULL) {
|
|
perror(FILE_PROC);
|
|
return -1;
|
|
}
|
|
|
|
while (!feof(iflst)) {
|
|
if (fgets(s, sizeof(s), iflst)==NULL)
|
|
break;
|
|
if ((p = strchr(s, ':'))) {
|
|
*p = 0;
|
|
|
|
sscanf(s, "%s", name);
|
|
strcpy(cfg.name, name);
|
|
|
|
if (ioctl(fd, IIOCNETGCF, &cfg) < 0)
|
|
continue;
|
|
|
|
if (exec_args(fd, 2 + (option?1:0), argv) == -2)
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
fclose(iflst);
|
|
return 0;
|
|
}
|
|
|
|
char * num2key(int num, char **keytable, int *numtable)
|
|
{
|
|
int i = -1;
|
|
while (numtable[++i] >= 0)
|
|
if (numtable[i] == num)
|
|
return keytable[i];
|
|
return "???";
|
|
}
|
|
|
|
static void listbind(char *s, int e)
|
|
{
|
|
if (strlen(s)) {
|
|
char *p = strchr(s, ',');
|
|
int ch;
|
|
sscanf(p + 1, "%d", &ch);
|
|
*p = '\0';
|
|
printf("%s, channel %d%s\n", s, ch, (e > 0) ? ", exclusive" : "");
|
|
} else
|
|
printf("Nothing\n");
|
|
}
|
|
|
|
static void listif(int isdnctrl, char *name, int errexit)
|
|
{
|
|
isdn_net_ioctl_cfg cfg;
|
|
char ph_in[1024], ph_out[1024];
|
|
|
|
memset(&cfg, 0, sizeof cfg); /* clear in case of older kernel */
|
|
cfg.dialmode = 0xDEADBEEF;
|
|
strcpy(cfg.name, name);
|
|
if (ioctl(isdnctrl, IIOCNETGCF, &cfg) < 0) {
|
|
if (errexit) {
|
|
perror(name);
|
|
exit(-1);
|
|
} else
|
|
return;
|
|
}
|
|
set_isdn_net_ioctl_phone((isdn_net_ioctl_phone *) ph_in,
|
|
name, "", 0);
|
|
if (ioctl(isdnctrl, IIOCNETGNM, &ph_in) < 0) {
|
|
if (errexit) {
|
|
perror(name);
|
|
exit(-1);
|
|
} else
|
|
return;
|
|
}
|
|
set_isdn_net_ioctl_phone((isdn_net_ioctl_phone *) ph_out,
|
|
name, "", 1);
|
|
if (ioctl(isdnctrl, IIOCNETGNM, &ph_out) < 0) {
|
|
if (errexit) {
|
|
perror(name);
|
|
exit(-1);
|
|
} else
|
|
return;
|
|
}
|
|
printf("\nCurrent setup of interface '%s':\n\n", cfg.name);
|
|
printf("EAZ/MSN: %s\n", cfg.eaz);
|
|
printf("Phone number(s):\n");
|
|
printf(" Outgoing: %s\n", ph_out);
|
|
printf(" Incoming: %s\n", ph_in);
|
|
printf("Dial mode: ");
|
|
if (cfg.dialmode == ISDN_NET_DM_OFF)
|
|
puts("off");
|
|
else if (cfg.dialmode == ISDN_NET_DM_AUTO)
|
|
puts("auto");
|
|
else if (cfg.dialmode == ISDN_NET_DM_MANUAL)
|
|
puts("manual");
|
|
else if (cfg.dialmode == 0xDEADBEEF)
|
|
puts("not in kernel (please upgrade your kernel)");
|
|
else
|
|
printf("unknown value (0x%x)\n", cfg.dialmode);
|
|
printf("Secure: %s\n", cfg.secure ? "on" : "off");
|
|
printf("Callback: %s\n", num2callb[cfg.callback]);
|
|
if (cfg.callback == 2)
|
|
printf("Hangup after Dial %s\n", cfg.cbdelay ? "on" : "off");
|
|
else
|
|
printf("Reject before Callback: %s\n", cfg.cbhup ? "on" : "off");
|
|
printf("Callback-delay: %d\n",cfg.cbdelay / 5);
|
|
printf("Dialmax: %d\n", cfg.dialmax);
|
|
printf("Hangup-Timeout: %d\n", cfg.onhtime);
|
|
printf("Incoming-Hangup: %s\n", cfg.ihup ? "on" : "off");
|
|
printf("ChargeHangup: %s\n", cfg.chargehup ? "on" : "off");
|
|
printf("Charge-Units: %d\n", cfg.charge);
|
|
if (data_version < 2)
|
|
printf("Charge-Interval: n.a.\n");
|
|
else
|
|
printf("Charge-Interval: %d\n", cfg.chargeint);
|
|
printf("Layer-2-Protocol: %s\n", num2key(cfg.l2_proto, l2protostr, l2protoval));
|
|
printf("Layer-3-Protocol: %s\n", num2key(cfg.l3_proto, l3protostr, l3protoval));
|
|
printf("Encapsulation: %s\n", num2key(cfg.p_encap, pencapstr, pencapval));
|
|
printf("Slave Interface: %s\n", strlen(cfg.slave) ? cfg.slave : "None");
|
|
printf("Slave delay: %d\n", cfg.slavedelay);
|
|
if (data_version < 3)
|
|
printf("Slave trigger: n.a.\n");
|
|
#if HAVE_TRIGGERCPS
|
|
else
|
|
printf("Slave trigger: %d cps\n", cfg.triggercps);
|
|
#endif
|
|
printf("Master Interface: %s\n", strlen(cfg.master) ? cfg.master : "None");
|
|
printf("Pre-Bound to: ");
|
|
listbind(cfg.drvid, cfg.exclusive);
|
|
printf("PPP-Bound to: ");
|
|
if (cfg.pppbind >= 0)
|
|
printf("%d\n", cfg.pppbind);
|
|
else
|
|
printf("Nothing\n");
|
|
|
|
if (cfg.slave && *cfg.slave) {
|
|
strncpy(nextslaveif, cfg.slave, 9);
|
|
nextslaveif[9] = 0;
|
|
}
|
|
else
|
|
nextslaveif[0] = 0;
|
|
}
|
|
|
|
|
|
/* mode = 0: nothing special */
|
|
/* mode = 1: exit 0 if connected, exit 1 otherwise */
|
|
/* mode = 2: show only active connections */
|
|
|
|
static void statusif(int isdnctrl, char *name, int mode)
|
|
{
|
|
isdn_net_ioctl_phone phone;
|
|
int rc;
|
|
static int isdninfo = -1;
|
|
|
|
if (isdninfo < 0) {
|
|
isdninfo = open("/dev/isdn/isdninfo", O_RDONLY);
|
|
if (isdninfo < 0)
|
|
isdninfo = open("/dev/isdninfo", O_RDONLY);
|
|
if (isdninfo < 0) {
|
|
perror("Can't open /dev/isdninfo or /dev/isdn/isdninfo");
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
memset(&phone, 0, sizeof phone);
|
|
set_isdn_net_ioctl_phone(&phone, name, "", 0);
|
|
rc = ioctl(isdninfo, IIOCNETGPN, &phone);
|
|
if (rc < 0) {
|
|
if (errno == ENOTCONN) {
|
|
if (mode != 2) {
|
|
printf("%s is not connected\n", name);
|
|
if (mode == 1) {
|
|
exit(1); /* exit 1 if interface specified & not conn. */
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (mode == 1) {
|
|
perror(name);
|
|
exit(-1);
|
|
}
|
|
return;
|
|
}
|
|
switch (data_version) {
|
|
case 0x04:
|
|
case 0x05:
|
|
printf("%s connected %s %s\n",
|
|
name, phone.phone_5.outgoing?"to":"from", phone.phone_5.phone);
|
|
return;
|
|
case 0x06:
|
|
printf("%s connected %s %s\n",
|
|
name, phone.phone_6.outgoing?"to":"from", phone.phone_6.phone);
|
|
return;
|
|
}
|
|
}
|
|
|
|
int findcmd(char *str)
|
|
{
|
|
int i;
|
|
|
|
if (str != NULL)
|
|
for (i = 0; cmds[i].cmd; i++)
|
|
if (!strcmp(cmds[i].cmd, str))
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
* do_dialmode() - handle dialmode settings
|
|
* parameters:
|
|
* args - number of args given
|
|
* dialmode - what to set it to
|
|
* fd - fd for ioctl
|
|
* id - name of interface
|
|
* errexit - exit if error (useful for nonisdn interfaces)
|
|
*
|
|
* If called with args == 2, set the value of interface id,
|
|
* else show the setting.
|
|
*/
|
|
|
|
static void
|
|
do_dialmode(int args, int dialmode, int fd, char *id, int errexit)
|
|
{
|
|
isdn_net_ioctl_cfg cfg;
|
|
|
|
memset(&cfg, 0, sizeof cfg); /* clear in case of older kernel */
|
|
cfg.dialmode = 0xDEADBEEF;
|
|
/* first get settings */
|
|
strcpy(cfg.name, id);
|
|
if (ioctl(fd, IIOCNETGCF, &cfg) < 0) {
|
|
if (!errexit)
|
|
return;
|
|
perror(id);
|
|
exit(-1);
|
|
}
|
|
if (cfg.dialmode == 0xDEADBEEF) {
|
|
fputs("dialmode setting not in kernel\n", stderr);
|
|
/*
|
|
* exit true if setting "auto"
|
|
* I want to be able to "isdnctrl dialmode if auto" without
|
|
* error if kernel has no dialmode, as then the behaviour is
|
|
* equivalent to "auto".
|
|
*/
|
|
exit((args == 2 && dialmode == ISDN_NET_DM_AUTO) ? 0 : -1);
|
|
}
|
|
/* hack for following a chain of interfaces */
|
|
if (cfg.slave && *cfg.slave) {
|
|
strncpy(nextslaveif, cfg.slave, 9);
|
|
nextslaveif[9] = 0;
|
|
}
|
|
else
|
|
nextslaveif[0] = 0;
|
|
|
|
if (args == 2) { /* set a value */
|
|
cfg.dialmode = dialmode;
|
|
if (ioctl(fd, IIOCNETSCF, &cfg) < 0) {
|
|
perror(id);
|
|
exit(-1);
|
|
}
|
|
return;
|
|
}
|
|
|
|
printf("Dial mode for %s: ", id);
|
|
/* no args specified, so show dialmode */
|
|
if (cfg.dialmode == ISDN_NET_DM_OFF)
|
|
puts("off");
|
|
else if (cfg.dialmode == ISDN_NET_DM_AUTO)
|
|
puts("auto");
|
|
else if (cfg.dialmode == ISDN_NET_DM_MANUAL)
|
|
puts("manual");
|
|
else
|
|
puts("illegal value (wrong kernel version?)");
|
|
}
|
|
|
|
int exec_args(int fd, int argc, char **argv)
|
|
{
|
|
int i,
|
|
n,
|
|
args;
|
|
int result;
|
|
FILE *iflst;
|
|
char *p;
|
|
char s[255], dummy[255];
|
|
isdn_net_ioctl_phone phone;
|
|
isdn_net_ioctl_cfg cfg;
|
|
isdn_ioctl_struct iocts;
|
|
unsigned long j;
|
|
char nstring[255];
|
|
#ifdef I4L_CTRL_CONF
|
|
char conffile[PATH_MAX];
|
|
#endif /* I4L_CTRL_CONF */
|
|
char *id;
|
|
char *arg1;
|
|
char *arg2;
|
|
int outflag;
|
|
|
|
for (; *argv != NULL; argv++, argc--) {
|
|
if ((i = findcmd(argv[0])) < 0) { /* Unknown command */
|
|
fprintf(stderr, "The given command \"%s\" is unknown.\n\n", argv[0]);
|
|
usage();
|
|
return -1;
|
|
}
|
|
|
|
args = cmds[i].argno[0] - '0';
|
|
id = argv[1];
|
|
|
|
if (args > argc - 1) {
|
|
fprintf(stderr, "Too few arguments given for \"%s\".\n\n", argv[0]);
|
|
usage();
|
|
return -1;
|
|
}
|
|
|
|
#ifdef I4L_CTRL_CONF
|
|
if (id != NULL && i != RESET && i != WRITECONF && i != READCONF)
|
|
#else
|
|
if (id != NULL && i != RESET)
|
|
#endif /* I4L_CTRL_CONF */
|
|
{
|
|
if (i == BUSREJECT || i == MAPPING) {
|
|
if (strlen(id) > sizeof(iocts.drvid)-1) {
|
|
fprintf(stderr, "DriverId must not exceed %u characters!\n", (unsigned int)sizeof(iocts.drvid)-1);
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
} else if (strlen(id) > 8) {
|
|
fprintf(stderr, "Interface name must not exceed 8 characters!\n");
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (n = 1; cmds[i].argno[n]; n++) {
|
|
args = cmds[i].argno[n] - '0';
|
|
if (((args > argc - 1) || findcmd(argv[args]) >= 0)) {
|
|
args = cmds[i].argno[n - 1] - '0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
arg1 = (args > 1) ? argv[2] : "";
|
|
arg2 = (args > 2) ? argv[3] : "";
|
|
argc -= args;
|
|
argv += args;
|
|
|
|
memset(&cfg, 0, sizeof cfg); /* clear in case of older kernel */
|
|
|
|
switch (i) {
|
|
#ifdef I4L_DWABC_UDPINFO
|
|
case ABCCLEAR:
|
|
if ((result = ioctl(fd, IIOCNETDWRSET, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("ABC secure-counter for %s now clear\n", id);
|
|
break;
|
|
#endif
|
|
case ADDIF:
|
|
strcpy(s, args?id:"");
|
|
if ((result = ioctl(fd, IIOCNETAIF, s)) < 0) {
|
|
perror("addif");
|
|
return -1;
|
|
}
|
|
printf("%s added\n", s);
|
|
break;
|
|
|
|
case ADDSLAVE:
|
|
if (strlen(arg1) > 8) {
|
|
fprintf(stderr, "slavename must not exceed 8 characters\n");
|
|
return -1;
|
|
}
|
|
sprintf(s, "%s,%s", id, arg1);
|
|
if ((result = ioctl(fd, IIOCNETASL, s)) < 0) {
|
|
perror("addslave");
|
|
return -1;
|
|
}
|
|
printf("%s added as slave to %s\n", s, id);
|
|
break;
|
|
|
|
case DELIF:
|
|
if (args == 2) {
|
|
if (!strcmp(arg1, "force")) {
|
|
char command[255];
|
|
sprintf(command,"%s %s %s",CMD_IFCONFIG, id, CMD_OPT_IFCONFIG);
|
|
|
|
if (system(command))
|
|
return -2;
|
|
} else
|
|
usage();
|
|
}
|
|
if ((result = ioctl(fd, IIOCNETDIF, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("%s deleted\n", id);
|
|
break;
|
|
|
|
case DIAL:
|
|
if ((result = ioctl(fd, IIOCNETDIL, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("Dialing of %s triggered\n", id);
|
|
break;
|
|
|
|
case BIND:
|
|
if (args == 3)
|
|
if (strncmp(arg2, "excl", 4))
|
|
usage();
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args > 1)
|
|
{
|
|
sscanf(arg1, "%s", cfg.drvid);
|
|
cfg.exclusive = (args == 3);
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
sprintf(s, "%s or %s", id, arg2);
|
|
perror(s);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("%s bound to ", id);
|
|
listbind(cfg.drvid, cfg.exclusive);
|
|
break;
|
|
|
|
case UNBIND:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (!strlen(cfg.drvid)) {
|
|
printf("%s was not bound to anything\n", id);
|
|
return -1;
|
|
}
|
|
cfg.drvid[0] = '\0';
|
|
cfg.exclusive = -1;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("%s unbound successfully\n", id);
|
|
break;
|
|
|
|
case PPPBIND:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if ((args == 2 && sscanf(arg1, "%d%s", &cfg.pppbind,dummy) == 1) ||
|
|
(args == 1 && sscanf(id, "ippp%d%s", &cfg.pppbind,dummy) == 1)) {
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
sprintf(s, "%s or %s", id, arg1);
|
|
perror(s);
|
|
return -1;
|
|
}
|
|
} else {
|
|
if (args == 1)
|
|
fprintf(stderr,"Unknown interface `%s', use ipppX\n", id);
|
|
else
|
|
fprintf(stderr,"Unknown argument `%s'\n", arg1);
|
|
return -1;
|
|
}
|
|
printf("%s bound to ", id);
|
|
if (cfg.pppbind >= 0)
|
|
printf("%d\n", cfg.pppbind);
|
|
else
|
|
printf("nothing\n");
|
|
break;
|
|
|
|
case PPPUNBIND:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (cfg.pppbind < 0) {
|
|
printf("%s was not bound to anything\n", id);
|
|
return -1;
|
|
}
|
|
cfg.pppbind = -1;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("%s unbound successfully\n", id);
|
|
break;
|
|
|
|
case BUSREJECT:
|
|
strcpy(iocts.drvid, id);
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off")) {
|
|
fprintf(stderr, "Bus-Reject must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
iocts.arg = strcmp(arg1, "off");
|
|
if ((result = ioctl(fd, IIOCSETBRJ, &iocts)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case MAPPING:
|
|
strcpy(iocts.drvid, id);
|
|
if (args == 1) {
|
|
iocts.arg = (unsigned long) &nstring;
|
|
if ((result = ioctl(fd, IIOCGETMAP, &iocts)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
printf("MSN/EAZ-mapping for %s:\n%s\n", id, nstring);
|
|
} else {
|
|
char buf[400];
|
|
strncpy(buf, arg1, sizeof(buf) - 1);
|
|
buf[399] = 0;
|
|
iocts.arg = (unsigned long) buf;
|
|
if ((result = ioctl(fd, IIOCSETMAP, &iocts)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SYSTEM:
|
|
if (strcmp(id, "on") && strcmp(id, "off")) {
|
|
fprintf(stderr, "System-Mode must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
j = strcmp(id, "on");
|
|
if ((result = ioctl(fd, IIOCSETGST, j)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case HANGUP:
|
|
if ((result = ioctl(fd, IIOCNETHUP, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (result)
|
|
printf("%s not connected\n", id);
|
|
else
|
|
printf("%s hung up\n", id);
|
|
break;
|
|
|
|
case ADDPHONE:
|
|
if (strcmp(arg1, "in") && strcmp(arg1, "out")) {
|
|
fprintf(stderr, "Direction must be \"in\" or \"out\"\n");
|
|
return -1;
|
|
}
|
|
outflag = strcmp(arg1, "out") ? 0 : 1;
|
|
if (set_isdn_net_ioctl_phone(&phone, id, arg2, outflag))
|
|
return -1;
|
|
if ((result = ioctl(fd, IIOCNETANM, &phone)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case DELPHONE:
|
|
if (strcmp(arg1, "in") && strcmp(arg1, "out")) {
|
|
fprintf(stderr, "Direction must be \"in\" or \"out\"\n");
|
|
return -1;
|
|
}
|
|
outflag = strcmp(arg1, "out") ? 0 : 1;
|
|
if (set_isdn_net_ioctl_phone(&phone, id, arg2, outflag))
|
|
return -1;
|
|
if ((result = ioctl(fd, IIOCNETDNM, &phone)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case LIST:
|
|
if (!strcmp(id, "all")) {
|
|
char name[10];
|
|
if ((iflst = fopen(FILE_PROC, "r")) == NULL) {
|
|
perror(FILE_PROC);
|
|
return -1;
|
|
}
|
|
while (!feof(iflst)) {
|
|
fgets(s, sizeof(s), iflst);
|
|
if ((p = strchr(s, ':'))) {
|
|
*p = 0;
|
|
sscanf(s, "%s", name);
|
|
listif(fd, name, 0);
|
|
while (*nextslaveif)
|
|
listif(fd, nextslaveif, 0);
|
|
}
|
|
}
|
|
fclose(iflst);
|
|
} else
|
|
listif(fd, id, 1);
|
|
break;
|
|
|
|
case STATUS:
|
|
if (!strcmp(id, "all") || !strcmp(id, "active")) {
|
|
char name[10];
|
|
int show_only_active;
|
|
if ((iflst = fopen(FILE_PROC, "r")) == NULL) {
|
|
perror(FILE_PROC);
|
|
return -1;
|
|
}
|
|
show_only_active = (strcmp(id, "active") ? 0 : 2);
|
|
while (!feof(iflst)) {
|
|
fgets(s, sizeof(s), iflst);
|
|
if ((p = strchr(s, ':'))) {
|
|
*p = 0;
|
|
sscanf(s, "%s", name);
|
|
statusif(fd, name, show_only_active);
|
|
while (*nextslaveif)
|
|
statusif(fd, nextslaveif, show_only_active);
|
|
}
|
|
}
|
|
fclose(iflst);
|
|
} else {
|
|
statusif(fd, id, 1);
|
|
}
|
|
break;
|
|
|
|
case EAZ:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
strncpy(cfg.eaz, arg1, sizeof(cfg.eaz) - 1);
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("EAZ/MSN for %s is %s\n", cfg.name, cfg.eaz);
|
|
break;
|
|
|
|
case VERBOSE:
|
|
i = -1;
|
|
sscanf(id, "%d", &i);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Verbose-level must be >= 0\n");
|
|
return -1;
|
|
}
|
|
if ((result = ioctl(fd, IIOCSETVER, i)) < 0) {
|
|
perror("IIOCSETVER");
|
|
return -1;
|
|
}
|
|
printf("Verbose-level set to %d.\n", i);
|
|
break;
|
|
|
|
case HUPTIMEOUT:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Hangup-Timeout must be >= 0\n");
|
|
return -1;
|
|
}
|
|
cfg.onhtime = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Hangup-Timeout for %s is %d sec.\n", cfg.name, cfg.onhtime);
|
|
break;
|
|
|
|
case CBDELAY:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Callback delay must be >= 0\n");
|
|
return -1;
|
|
}
|
|
cfg.cbdelay = i * 5;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Callback delay for %s is %d sec.\n", cfg.name, cfg.cbdelay / 5);
|
|
break;
|
|
|
|
case CHARGEINT:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Charge interval must be >= 0\n");
|
|
return -1;
|
|
}
|
|
cfg.chargeint = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
if (data_version < 2)
|
|
printf("Option 'chargeint' IGNORED!\n");
|
|
else
|
|
printf("Charge Interval for %s is %d sec.\n", cfg.name, cfg.chargeint);
|
|
break;
|
|
|
|
case DIALMAX:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 1) {
|
|
fprintf(stderr, "Dialmax must be > 0\n");
|
|
return -1;
|
|
}
|
|
cfg.dialmax = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Dialmax for %s is %d times.\n", cfg.name, cfg.dialmax);
|
|
break;
|
|
|
|
case SDELAY:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 1) {
|
|
fprintf(stderr, "Slave-activation delay must be >= 1\n");
|
|
return -1;
|
|
}
|
|
cfg.slavedelay = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Slave-activation delay for %s is %d sec.\n", cfg.name,
|
|
cfg.slavedelay);
|
|
break;
|
|
|
|
case TRIGGER:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
exit(-1);
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
sscanf(arg1, "%d", &i);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Slave triggerlevel must be >= 0 (%s)\n", arg1);
|
|
exit(-1);
|
|
}
|
|
cfg.triggercps = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
exit(-1);
|
|
}
|
|
}
|
|
if (data_version < 3)
|
|
printf("Option 'trigger' IGNORED!\n");
|
|
else
|
|
printf("Slave triggerlevel for %s is %d cps.\n",
|
|
cfg.name, cfg.triggercps);
|
|
break;
|
|
|
|
case CHARGEHUP:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off")) {
|
|
fprintf(stderr, "Charge-Hangup must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
cfg.chargehup = strcmp(arg1, "off");
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Charge-Hangup for %s is %s\n", cfg.name, cfg.chargehup ? "on" : "off");
|
|
break;
|
|
|
|
case CBHUP:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off")) {
|
|
fprintf(stderr, "Callback-Hangup must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
cfg.cbhup = strcmp(arg1, "off");
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Reject before Callback for %s is %s\n", cfg.name, cfg.cbhup ? "on" : "off");
|
|
break;
|
|
|
|
case IHUP:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off")) {
|
|
fprintf(stderr, "Incoming-Hangup must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
cfg.ihup = strcmp(arg1, "off");
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Incoming-Hangup for %s is %s\n", cfg.name, cfg.ihup ? "on" : "off");
|
|
break;
|
|
|
|
case SECURE:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off")) {
|
|
fprintf(stderr, "Secure-parameter must be 'on' or 'off'\n");
|
|
return -1;
|
|
}
|
|
cfg.secure = strcmp(arg1, "off");
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Security for %s is %s\n", cfg.name, cfg.secure ? "on" : "off");
|
|
break;
|
|
|
|
case CALLBACK:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = -1;
|
|
if (strcmp(arg1, "on") && strcmp(arg1, "off") &&
|
|
strcmp(arg1, "in") && strcmp(arg1, "out")) {
|
|
fprintf(stderr, "Callback-parameter must be 'on', 'in', 'out' or 'off'\n");
|
|
return -1;
|
|
}
|
|
cfg.callback = strcmp(arg1, "off") ? 1 : 0;
|
|
if (!strcmp(arg1, "out"))
|
|
cfg.callback = 2;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Callback for %s is %s\n", cfg.name, num2callb[cfg.callback]);
|
|
break;
|
|
|
|
case L2_PROT:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = key2num(arg1, l2protostr, l2protoval);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Layer-2-Protocol must be one of the following:\n");
|
|
i = 0;
|
|
while (strlen(l2protostr[i]))
|
|
fprintf(stderr, "\t\"%s\"\n", l2protostr[i++]);
|
|
return -1;
|
|
}
|
|
cfg.l2_proto = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Layer-2-Protocol for %s is %s\n", cfg.name,
|
|
num2key(cfg.l2_proto, l2protostr, l2protoval));
|
|
break;
|
|
|
|
case L3_PROT:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = key2num(arg1, l3protostr, l3protoval);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Layer-3-Protocol must be one of the following:\n");
|
|
i = 0;
|
|
while (strlen(l3protostr[i]))
|
|
fprintf(stderr, "\t\"%s\"\n", l3protostr[i++]);
|
|
return -1;
|
|
}
|
|
cfg.l3_proto = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Layer-3-Protocol for %s is %s\n", cfg.name,
|
|
num2key(cfg.l3_proto, l3protostr, l3protoval));
|
|
break;
|
|
|
|
case ADDLINK:
|
|
if ((result = ioctl(fd, IIOCNETALN, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (result) {
|
|
printf("Can't increase the number of links:\n\t");
|
|
switch (result) {
|
|
case -1: printf("MPPP not in the kernel config.\n");
|
|
break;
|
|
case 1: printf("%s doesn't exist\n", id);
|
|
break;
|
|
case 2: printf("no slave devices configured for %s\n", id);
|
|
break;
|
|
case 5: printf("%s not currently connected.\n", id);
|
|
break;
|
|
default: printf("unknown error %d\n", result);
|
|
}
|
|
}
|
|
else
|
|
printf("Ok, added a new link. (dialing)\n");
|
|
break;
|
|
|
|
case REMOVELINK:
|
|
if ((result = ioctl(fd, IIOCNETDLN, id)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (result) {
|
|
printf("Can't decrease the number of links:\n\t");
|
|
switch (result) {
|
|
case -1: printf("MPPP not in the kernel config.\n");
|
|
break;
|
|
case 1: printf("%s doesn't exist\n", id);
|
|
break;
|
|
case 2: printf("no slave devices configured for %s\n", id);
|
|
break;
|
|
case 5: printf("%s not currently connected.\n", id);
|
|
break;
|
|
default: printf("unknown error %d\n", result);
|
|
}
|
|
}
|
|
else
|
|
printf("Ok, removed a link. (hangup)\n");
|
|
break;
|
|
|
|
case ENCAP:
|
|
strcpy(cfg.name, id);
|
|
if ((result = ioctl(fd, IIOCNETGCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
if (args == 2) {
|
|
i = key2num(arg1, pencapstr, pencapval);
|
|
if (i < 0) {
|
|
fprintf(stderr, "Encapsulation must be one of the following:\n");
|
|
i = 0;
|
|
while (strlen(pencapstr[i]))
|
|
fprintf(stderr, "\t\"%s\"\n", pencapstr[i++]);
|
|
return -1;
|
|
}
|
|
cfg.p_encap = i;
|
|
if ((result = ioctl(fd, IIOCNETSCF, &cfg)) < 0) {
|
|
perror(id);
|
|
return -1;
|
|
}
|
|
}
|
|
printf("Encapsulation for %s is %s\n", cfg.name,
|
|
num2key(cfg.p_encap, pencapstr, pencapval));
|
|
break;
|
|
|
|
case RESET:
|
|
reset_interfaces(fd, args?id:NULL);
|
|
break;
|
|
|
|
case DIALMODE:
|
|
if(args == 2) {
|
|
if (!strcmp(arg1, "on") || !strcmp(arg1, "manual"))
|
|
cfg.dialmode = ISDN_NET_DM_MANUAL;
|
|
else if (!strcmp(arg1, "off"))
|
|
cfg.dialmode = ISDN_NET_DM_OFF;
|
|
else if (!strncmp(arg1, "auto", 4))
|
|
/* also automatic, autodial, ... */
|
|
cfg.dialmode = ISDN_NET_DM_AUTO;
|
|
else {
|
|
fprintf(stderr, "dialmode must be 'off', 'manual' or 'auto'\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
if (!strcmp(id, "all")) { /* do all interfaces*/
|
|
if ((iflst = fopen(FILE_PROC, "r")) == NULL) {
|
|
perror(FILE_PROC);
|
|
return -1;
|
|
}
|
|
while (!feof(iflst)) {
|
|
fgets(s, sizeof(s), iflst);
|
|
if ((p = strchr(s, ':'))) {
|
|
*p = 0;
|
|
p = s;
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
do_dialmode(args, cfg.dialmode, fd, p, 0);
|
|
while (*nextslaveif)
|
|
do_dialmode(args, cfg.dialmode, fd, nextslaveif, 0);
|
|
}
|
|
}
|
|
fclose(iflst);
|
|
}
|
|
else {
|
|
do_dialmode(args, cfg.dialmode, fd, id, 1);
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef I4L_CTRL_CONF
|
|
case WRITECONF:
|
|
if (args == 0) {
|
|
sprintf(conffile, "%s%c%s", confdir(), C_SLASH, CONFFILE);
|
|
id = conffile;
|
|
}
|
|
|
|
if (writeconfig(fd, id))
|
|
return -1;
|
|
|
|
if (!strcmp(id, "-"))
|
|
id = "stdout";
|
|
printf("ISDN Configuration written to %s.\n", id);
|
|
break;
|
|
|
|
case READCONF:
|
|
if (args == 0) {
|
|
sprintf(conffile, "%s%c%s", confdir(), C_SLASH, CONFFILE);
|
|
id = conffile;
|
|
}
|
|
|
|
if (readconfig(fd, id))
|
|
return -1;
|
|
|
|
if (!strcmp(id, "-"))
|
|
id = "stdin";
|
|
printf("ISDN Configuration read from %s.\n", id);
|
|
break;
|
|
#endif /* I4L_CTRL_CONF */
|
|
|
|
case IFDEFAULTS: {
|
|
#define MAX_DEFS_ARGS 64
|
|
|
|
int defs_argc;
|
|
char *defs_argv [MAX_DEFS_ARGS + 1];
|
|
defs_fcn_t defs_fcn_p;
|
|
int i;
|
|
char *s, *s0, *t, *u;
|
|
|
|
|
|
i = 0;
|
|
while((defs_fcn_p = defs_fcns [i++]) != NULL) {
|
|
|
|
s = (*defs_fcn_p)(id);
|
|
|
|
if(!s || !*s)
|
|
continue;
|
|
|
|
s0 = s = strdup(s);
|
|
|
|
while(s && *s) {
|
|
t = strdup(strtok(s, "\n"));
|
|
s += strlen(t) + 1;
|
|
|
|
if(!t || !*t)
|
|
continue;
|
|
|
|
defs_argc = 0;
|
|
defs_argv [defs_argc] = NULL;
|
|
|
|
u = strtok(t, " \t");
|
|
|
|
while(u && *u) {
|
|
if(++defs_argc >= MAX_DEFS_ARGS) {
|
|
fprintf(stderr, "default-values overflow.");
|
|
exit(1);
|
|
}
|
|
|
|
defs_argv [defs_argc - 1] = strdup(u);
|
|
defs_argv [defs_argc] = NULL;
|
|
|
|
u = strtok(NULL, " \t");
|
|
}
|
|
|
|
if(defs_argc) {
|
|
exec_args(fd, defs_argc, defs_argv);
|
|
|
|
while(defs_argc--)
|
|
free(defs_argv [defs_argc]);
|
|
}
|
|
|
|
free(t);
|
|
}
|
|
|
|
free(s0);
|
|
}
|
|
|
|
}
|
|
break;
|
|
default:
|
|
printf("here %d\n",i);
|
|
}
|
|
|
|
#if DEBUG
|
|
if (argc > 1) {
|
|
printf("args=%d nextcmd %s\n",args, argv[1]);
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
char *defs_basic(char *id) {
|
|
static char r [1024];
|
|
char *p = r;
|
|
|
|
p += sprintf(p, "dialmode %s off\n", id);
|
|
p += sprintf(p, "huptimeout %s 60\n", id);
|
|
|
|
return(r);
|
|
}
|
|
|
|
void check_version(int report) {
|
|
int fd;
|
|
|
|
if (report) {
|
|
printf("isdnctrl version %s\n", VERSION);
|
|
}
|
|
fd = open("/dev/isdn/isdninfo", O_RDWR);
|
|
if (fd < 0)
|
|
fd = open("/dev/isdninfo", O_RDONLY);
|
|
if (fd < 0) {
|
|
perror("Can't open /dev/isdninfo or /dev/isdn/isdninfo");
|
|
exit(-1);
|
|
}
|
|
data_version = ioctl(fd, IIOCGETDVR, 0);
|
|
if (data_version < 0) {
|
|
fprintf(stderr, "Could not get version of kernel ioctl structs!\n");
|
|
fprintf(stderr, "Make sure that you are using the correct version.\n");
|
|
fprintf(stderr, "(Try recompiling isdnctrl).\n");
|
|
exit(-1);
|
|
}
|
|
close(fd);
|
|
if (report) {
|
|
printf("Kernel's view of API-versions:\n");
|
|
printf("ttyI: %d, net: %d, info: %d\n",
|
|
data_version & 0xff,
|
|
(data_version >> 8) & 0xff,
|
|
(data_version >> 16) & 0xff);
|
|
return;
|
|
}
|
|
data_version = (data_version >> 8) & 0xff;
|
|
|
|
if (data_version < 4) {
|
|
fprintf(stderr, "Kernel-version too old, terminating.\n");
|
|
fprintf(stderr, "UPDATE YOUR KERNEL.\n");
|
|
exit(-1);
|
|
}
|
|
if (data_version > 6) {
|
|
fprintf(stderr, "Kernel-version newer than isdnctrl-version, terminating.\n");
|
|
fprintf(stderr, "GET A NEW VERSION OF isdn4k-utils.\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int fd;
|
|
int rc;
|
|
|
|
/*
|
|
* Security check. Mere mortals mustn't do anything except
|
|
* isdnctrl dial <devicename>. --okir
|
|
* hangup addlink removelink and status are also needed --kkeil
|
|
*/
|
|
if (getuid()) {
|
|
if (argc != 3 ||
|
|
(strcmp(argv[1], "dial")
|
|
&& strcmp(argv[1], "hangup")
|
|
&& strcmp(argv[1], "addlink")
|
|
&& strcmp(argv[1], "removelink")
|
|
&& strcmp(argv[1], "status"))) {
|
|
fprintf(stderr,
|
|
"Only the dial,hangup,addlink,removelink and status\n"
|
|
"commands are allowed for none root users\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if ((cmd = strrchr(argv[0], '/')) != NULL)
|
|
*cmd++ = '\0';
|
|
else
|
|
cmd = argv[0];
|
|
|
|
if (argc == 1) {
|
|
usage();
|
|
exit(-1);
|
|
}
|
|
if ((argc == 2) && (!strcmp(argv[1], "-V"))) {
|
|
check_version(1);
|
|
exit(0);
|
|
}
|
|
if ((argc == 2) && (!strcmp(argv[1], "--version"))) {
|
|
printf("isdnctrl version %s\n", VERSION);
|
|
exit(0);
|
|
}
|
|
#ifdef I4L_DWABC_UDPINFO
|
|
{
|
|
int art = 0;
|
|
char *p = argv[1];
|
|
|
|
if(!strcmp(p,"-udpisisdn")) {
|
|
art = 1;
|
|
} else if(!strcmp(p,"-udponline")) {
|
|
art = 2;
|
|
} else if(!strcmp(p,"-udphangup")) {
|
|
art = 3;
|
|
} else if(!strcmp(p,"-udpdial")) {
|
|
art = 4;
|
|
} else if(!strcmp(p,"-udpclear")) {
|
|
art = 5;
|
|
}
|
|
|
|
if(art) {
|
|
|
|
char *err = NULL;
|
|
int retw = 0;
|
|
p = argv[2];
|
|
|
|
if(argc != 3) {
|
|
|
|
usage();
|
|
exit(1);
|
|
}
|
|
|
|
switch(art) {
|
|
case 1: retw = isdn_udp_isisdn(p,&err); break;
|
|
case 2: retw = isdn_udp_online(p,&err); break;
|
|
case 3: retw = isdn_udp_hangup(p,&err); break;
|
|
case 4: retw = isdn_udp_dial(p,&err); break;
|
|
case 5: retw = isdn_udp_clear_ggau(p,&err); break;
|
|
}
|
|
|
|
if(err != NULL) {
|
|
|
|
fprintf(stderr,"%s\n",err);
|
|
free(err);
|
|
err = NULL;
|
|
}
|
|
|
|
if(!retw) {
|
|
|
|
switch(art) {
|
|
case 1:
|
|
printf("destination %s is NOT over i4l routed\n",p);
|
|
break;
|
|
case 2:
|
|
printf("destination %s is NOT online\n",p);
|
|
break;
|
|
case 3:
|
|
printf("destination %s CANNOT hangup the line\n",p);
|
|
break;
|
|
case 4:
|
|
printf("destination %s CANNOT dialing\n",p);
|
|
break;
|
|
case 5:
|
|
printf("CANNOT reset (clear) abc-secure-counter's for destination %s\n",p);
|
|
}
|
|
|
|
} else {
|
|
|
|
switch(art) {
|
|
case 1:
|
|
printf("destination %s is over i4l routed\n",p);
|
|
break;
|
|
case 2:
|
|
printf("destination %s is online\n",p);
|
|
break;
|
|
case 3:
|
|
printf("destination %s trigger hangup \n",p);
|
|
break;
|
|
case 4:
|
|
printf("destination %s trigger dialing\n",p);
|
|
break;
|
|
case 5:
|
|
printf("reset (clear) abc-secure-counter's for destination %s\n",p);
|
|
}
|
|
}
|
|
|
|
exit(!retw);
|
|
}
|
|
}
|
|
#endif
|
|
check_version(0);
|
|
|
|
fd = open("/dev/isdn/isdnctrl", O_RDWR);
|
|
if (fd < 0)
|
|
fd = open("/dev/isdnctrl", O_RDWR);
|
|
if (fd < 0) {
|
|
perror("Can't open /dev/isdnctrl or /dev/isdn/isdnctrl");
|
|
exit(-1);
|
|
}
|
|
|
|
|
|
rc = exec_args(fd,argc-1,argv+1);
|
|
close(fd);
|
|
return rc;
|
|
}
|