Reported by Trent Creekmore
[dahdi/tools.git] / dahdi_cfg.c
1 /*
2  * Configuration program for DAHDI Telephony Interface
3  *
4  * Written by Mark Spencer <markster@digium.com>
5  * Based on previous works, designs, and architectures conceived and
6  * written by Jim Dixon <jim@lambdatel.com>.
7  *
8  * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
9  * Copyright (C) 2001-2008 Digium, Inc.
10  *
11  * All rights reserved.
12  *
13  * Primary Author: Mark Spencer <markster@digium.com>
14  * Radio Support by Jim Dixon <jim@lambdatel.com>
15  */
16
17 /*
18  * See http://www.asterisk.org for more information about
19  * the Asterisk project. Please do not directly contact
20  * any of the maintainers of this project for assistance;
21  * the project provides a web site, mailing lists and IRC
22  * channels for your use.
23  *
24  * This program is free software, distributed under the terms of
25  * the GNU General Public License Version 2 as published by the
26  * Free Software Foundation. See the LICENSE file included with
27  * this program for more details.
28  */
29
30 #include <stdio.h> 
31 #include <getopt.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/ioctl.h>
38 #include <fcntl.h>
39 #include <sys/stat.h>
40 #include <semaphore.h>
41 #include <errno.h>
42 #include <dirent.h>
43 #include <stdbool.h>
44
45 #include <dahdi/user.h>
46 #include "tonezone.h"
47 #include "dahdi_tools_version.h"
48
49 #define CONFIG_FILENAME "/etc/dahdi/system.conf"
50 #define MASTER_DEVICE   "/dev/dahdi/ctl"
51
52 #define NUM_SPANS DAHDI_MAX_SPANS
53
54 #define NUM_TONES 15
55
56 /*! A sanity check for the timing parameter of the span. 
57  *
58  * Note that each driver using it is still responsible for validating
59  * that value.
60  */
61 #define MAX_TIMING 255 
62
63 /* Assume no more than 1024 dynamics */
64 #define NUM_DYNAMIC     1024
65
66 static int lineno=0;
67
68 static FILE *cf;
69
70 static char *filename=CONFIG_FILENAME;
71
72 int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
73 int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
74 int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
75
76 int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
77
78 static int toneindex = 1;
79
80 #define DEBUG_READER (1 << 0)
81 #define DEBUG_PARSER (1 << 1)
82 #define DEBUG_APPLY  (1 << 2)
83 static int debug = 0;
84
85 static int errcnt = 0;
86
87 static int deftonezone = -1;
88
89 static struct dahdi_lineconfig lc[DAHDI_MAX_SPANS];
90
91 static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS];
92
93 static int only_span = 0;
94 static int restrict_channels = 0;
95 static int selected_channels[DAHDI_MAX_CHANNELS];
96 static int declared_spans[DAHDI_MAX_SPANS];
97
98 static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS];
99
100 static struct dahdi_dynamic_span zds[NUM_DYNAMIC];
101
102 static const char *sig[DAHDI_MAX_CHANNELS];             /* Signalling */
103
104 static int slineno[DAHDI_MAX_CHANNELS]; /* Line number where signalling specified */
105
106 static int fiftysixkhdlc[DAHDI_MAX_CHANNELS];
107
108 static int spans=0;
109
110 static int dry_run = 0;
111
112 static int verbose = 0;
113
114 static int force = 0;
115
116 static int stopmode = 0;
117
118 static int numdynamic = 0;
119
120 static char zonestoload[DAHDI_TONE_ZONE_MAX][10];
121
122 static int numzones = 0;
123
124 static int fd = -1;
125
126 static const char *lbostr[] = {
127 "0 db (CSU)/0-133 feet (DSX-1)",
128 "133-266 feet (DSX-1)",
129 "266-399 feet (DSX-1)",
130 "399-533 feet (DSX-1)",
131 "533-655 feet (DSX-1)",
132 "-7.5db (CSU)",
133 "-15db (CSU)",
134 "-22.5db (CSU)"
135 };
136
137 static const char *laws[] = {
138         "Default",
139         "Mu-law",
140         "A-law"
141 };
142
143 static bool _are_all_spans_assigned(const char *device_path)
144 {
145         char attribute[1024];
146         int res;
147         FILE *fp;
148         int span_count;
149         DIR *dirp;
150         struct dirent *dirent;
151
152         snprintf(attribute, sizeof(attribute) - 1,
153                  "%s/span_count", device_path);
154         fp = fopen(attribute, "r");
155         if (NULL == fp) {
156                 fprintf(stderr, "Failed to open '%s'.\n", attribute);
157                 return false;
158         }
159         res = fscanf(fp, "%d", &span_count);
160         fclose(fp);
161
162         if (EOF == res) {
163                 fprintf(stderr, "Failed to read '%s'.\n", attribute);
164                 return false;
165         }
166
167         dirp = opendir(device_path);
168         while (span_count) {
169                 dirent = readdir(dirp);
170                 if (NULL == dirent)
171                         break;
172                 if (!strncmp("span-", dirent->d_name, 5)) {
173                         --span_count;
174                 }
175         }
176         closedir(dirp);
177         return (span_count > 0) ? false : true;
178 }
179
180 /**
181  * are_all_spans_assigned - Look in sysfs to see if all spans for a device are assigned.
182  *
183  * Returns true if there are $span_count child spans of all devices, or false
184  *  otherwise.
185  */
186 static bool are_all_spans_assigned(void)
187 {
188         DIR *dirp;
189         struct dirent *dirent;
190         bool res = true;
191         char device_path[1024];
192
193         dirp = opendir("/sys/bus/dahdi_devices/devices");
194         if (!dirp) {
195                 /* If we cannot open dahdi_devices, either dahdi isn't loaded,
196                  * or we're using an older version of DAHDI that doesn't use
197                  * sysfs. */
198                 return true;
199         }
200
201         while (true && res) {
202
203                 dirent = readdir(dirp);
204                 if (NULL == dirent)
205                         break;
206
207                 if (!strcmp(dirent->d_name, ".") ||
208                     !strcmp(dirent->d_name, ".."))
209                         continue;
210
211                 snprintf(device_path, sizeof(device_path)-1,
212                          "/sys/bus/dahdi_devices/devices/%s", dirent->d_name);
213                 res = _are_all_spans_assigned(device_path);
214         }
215
216         closedir(dirp);
217         errno = 0;
218         return res;
219 }
220
221 static bool wait_for_all_spans_assigned(unsigned long timeout_sec)
222 {
223         bool all_assigned = are_all_spans_assigned();
224         unsigned int timeout = 10*timeout_sec;
225
226         while (!all_assigned && --timeout) {
227                 usleep(100000);
228                 all_assigned = are_all_spans_assigned();
229         }
230
231         return all_assigned;
232 }
233
234 static const char *sigtype_to_str(const int sig)
235 {
236         switch (sig) {
237         case 0:
238                 return "Unused";
239         case DAHDI_SIG_EM:
240                 return "E & M";
241         case DAHDI_SIG_EM_E1:
242                 return "E & M E1";
243         case DAHDI_SIG_FXSLS:
244                 return "FXS Loopstart";
245         case DAHDI_SIG_FXSGS:
246                 return "FXS Groundstart";
247         case DAHDI_SIG_FXSKS:
248                 return "FXS Kewlstart";
249         case DAHDI_SIG_FXOLS:
250                 return "FXO Loopstart";
251         case DAHDI_SIG_FXOGS:
252                 return "FXO Groundstart";
253         case DAHDI_SIG_FXOKS:
254                 return "FXO Kewlstart";
255         case DAHDI_SIG_CAS:
256                 return "CAS / User";
257         case DAHDI_SIG_DACS:
258                 return "DACS";
259         case DAHDI_SIG_DACS_RBS:
260                 return "DACS w/RBS";
261         case DAHDI_SIG_CLEAR:
262                 return "Clear channel";
263         case DAHDI_SIG_SLAVE:
264                 return "Slave channel";
265         case DAHDI_SIG_HDLCRAW:
266                 return "Raw HDLC";
267         case DAHDI_SIG_HDLCNET:
268                 return "Network HDLC";
269         case DAHDI_SIG_HDLCFCS:
270                 return "HDLC with FCS check";
271         case DAHDI_SIG_HARDHDLC:
272                 return "Hardware assisted D-channel";
273         case DAHDI_SIG_MTP2:
274                 return "MTP2";
275         default:
276                 return "Unknown";
277         }
278 }
279
280 static void clear_fields()
281 {
282
283         memset(rxtones,0,sizeof(rxtones));
284         memset(rxtags,0,sizeof(rxtags));
285         memset(txtones,0,sizeof(txtones));
286         bursttime = 0;
287         debouncetime = 0;
288         invertcor = 0;
289         exttone = 0;
290         txgain = 0;
291         rxgain = 0;
292         deemp = 0;
293         preemp = 0;
294 }
295
296 static int error(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
297
298 static int error(char *fmt, ...)
299 {
300         int res;
301         static int shown=0;
302         va_list ap;
303         if (!shown) {
304                 fprintf(stderr, "Notice: Configuration file is %s\n", filename);
305                 shown++;
306         }
307         res = fprintf(stderr, "line %d: ", lineno);
308         va_start(ap, fmt);
309         vfprintf(stderr, fmt, ap);
310         va_end(ap);
311         errcnt++;
312         return res;
313 }
314
315 static char *trim(char *buf)
316 {
317         size_t len;
318
319         while (*buf && (*buf < 33)) {
320                 buf++;
321         }
322
323         len = strlen(buf);
324
325         while (len && buf[len-1] < 33) {
326                 buf[--len] = '\0';
327         }
328
329         return buf;
330 }
331
332 static int skip_channel(int x)
333 {
334         if (restrict_channels) {
335                 if (!selected_channels[x])
336                         return 1;
337         } else {
338                 if (only_span && !declared_spans[only_span]) {
339                         fprintf(stderr,
340                                 "Error: analog span %d given to '-S', without '-C' restriction.\n",
341                                 only_span);
342                         exit(1);
343                 }
344         }
345         return 0;
346 }
347
348 static int parseargs(char *input, char *output[], int maxargs, char sep)
349 {
350         char *c;
351         int pos=0;
352         c = input;
353         output[pos++] = c;
354         while(*c) {
355                 while(*c && (*c != sep)) c++;
356                 if (*c) {
357                         *c = '\0';
358                         c++;
359                         while(*c && (*c < 33)) c++;
360                         if (*c)  {
361                                 if (pos >= maxargs)
362                                         return -1;
363                                 output[pos] = c;
364                                 trim(output[pos]);
365                                 pos++;
366                                 output[pos] = NULL;
367                                 /* Return error if we have too many */
368                         } else
369                                 return pos;
370                 }
371         }
372         return pos;
373 }
374
375 int dspanconfig(char *keyword, char *args)
376 {
377         static char *realargs[10];
378         int res;
379         int chans;
380         int timing;
381         res = parseargs(args, realargs, 4, ',');
382         if (res != 4) {
383                 error("Incorrect number of arguments to 'dynamic' (should be <driver>,<address>,<num channels>, <timing>)\n");
384                 return -1;
385         }
386         res = sscanf(realargs[2], "%d", &chans);
387         if ((res == 1) && (chans < 1))
388                 res = -1;
389         if (res != 1) {
390                 error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]);
391                 return -1;
392         }
393
394         res = sscanf(realargs[3], "%d", &timing);
395         if ((res == 1) && (timing < 0))
396                 res = -1;
397         if (res != 1) {
398                 error("Invalid timing '%s', should be a number > 0.\n", realargs[3]);
399                 return -1;
400         }
401
402
403         dahdi_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver));
404         dahdi_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr));
405         zds[numdynamic].numchans = chans;
406         zds[numdynamic].timing = timing;
407         
408         numdynamic++;
409         return 0;
410 }
411
412 int spanconfig(char *keyword, char *args)
413 {
414         static char *realargs[10];
415         int res;
416         int argc;
417         int span;
418         int timing;
419         int i;
420         argc = res = parseargs(args, realargs, 9, ',');
421         if ((res < 5) || (res > 9)) {
422                 error("Incorrect number of arguments to 'span' (should be <spanno>,<timing>,<lbo>,<framing>,<coding>[, crc4 | yellow [, yellow]])\n");
423                 return -1;
424         }
425         res = sscanf(realargs[0], "%d", &span);
426         if (res != 1) {
427                 error("Span number should be a valid span number, not '%s'\n", realargs[0]);
428                 return -1;
429         }
430         declared_spans[span] = 1;
431         res = sscanf(realargs[1], "%d", &timing);
432         if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) {
433                 error("Timing should be a number from 0 to %d, not '%s'\n", 
434                                 MAX_TIMING,  realargs[1]);
435                 return -1;
436         }
437         res = sscanf(realargs[2], "%d", &lc[spans].lbo);
438         if (res != 1) {
439                 error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]);
440                 return -1;
441         }
442         if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) {
443                 error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo);
444                 return -1;
445         }
446         if (!strcasecmp(realargs[3], "d4")) {
447                 lc[spans].lineconfig |= DAHDI_CONFIG_D4;
448                 lc[spans].lineconfig &= ~DAHDI_CONFIG_ESF;
449                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
450         } else if (!strcasecmp(realargs[3], "esf")) {
451                 lc[spans].lineconfig |= DAHDI_CONFIG_ESF;
452                 lc[spans].lineconfig &= ~DAHDI_CONFIG_D4;
453                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
454         } else if (!strcasecmp(realargs[3], "ccs")) {
455                 lc[spans].lineconfig |= DAHDI_CONFIG_CCS;
456                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
457         } else if (!strcasecmp(realargs[3], "cas")) {
458                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
459                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
460         } else {
461                 error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]);
462                 return -1;
463         }
464         if (!strcasecmp(realargs[4], "ami")) {
465                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_HDB3);
466                 lc[spans].lineconfig |= DAHDI_CONFIG_AMI;
467         } else if (!strcasecmp(realargs[4], "b8zs")) {
468                 lc[spans].lineconfig |= DAHDI_CONFIG_B8ZS;
469                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3);
470         } else if (!strcasecmp(realargs[4], "hdb3")) {
471                 lc[spans].lineconfig |= DAHDI_CONFIG_HDB3;
472                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS);
473         } else {
474                 error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]);
475                 return -1;
476         }
477         for (i = 5; i < argc; i++) {
478                 if (!strcasecmp(realargs[i], "yellow"))
479                         lc[spans].lineconfig |= DAHDI_CONFIG_NOTOPEN;
480                 else if (!strcasecmp(realargs[i], "crc4"))
481                         lc[spans].lineconfig |= DAHDI_CONFIG_CRC4;
482                 else if (!strcasecmp(realargs[i], "nt"))
483                         lc[spans].lineconfig |= DAHDI_CONFIG_NTTE;
484                 else if (!strcasecmp(realargs[i], "te"))
485                         lc[spans].lineconfig &= ~DAHDI_CONFIG_NTTE;
486                 else if (!strcasecmp(realargs[i], "term"))
487                         lc[spans].lineconfig |= DAHDI_CONFIG_TERM;
488                 else {
489                         error("Remaining arguments may be any of: 'yellow', 'crc4', 'nt', 'te', 'term', not '%s'\n", realargs[i]);
490                         return -1;
491                 }
492
493         }
494         lc[spans].span = span;
495         lc[spans].sync = timing;
496         /* Valid span */
497         spans++;
498         return 0;
499 }
500
501 int apply_channels(int chans[], char *argstr)
502 {
503         char *args[DAHDI_MAX_CHANNELS+1];
504         char *range[3];
505         int res,x, res2,y;
506         int chan;
507         int start, finish;
508         char argcopy[256];
509         res = parseargs(argstr, args, DAHDI_MAX_CHANNELS, ',');
510         if (res < 0) {
511                 error("Too many arguments...  Max is %d\n", DAHDI_MAX_CHANNELS);
512                 return -1;
513         }
514         for (x=0;x<res;x++) {
515                 if (strchr(args[x], '-')) {
516                         /* It's a range */
517                         dahdi_copy_string(argcopy, args[x], sizeof(argcopy));
518                         res2 = parseargs(argcopy, range, 2, '-');
519                         if (res2 != 2) {
520                                 error("Syntax error in range '%s'.  Should be <val1>-<val2>.\n", args[x]);
521                                 return -1;
522                         }
523                         res2 =sscanf(range[0], "%d", &start);
524                         if (res2 != 1) {
525                                 error("Syntax error.  Start of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
526                                 return -1;
527                         } else if ((start < 1) || (start >= DAHDI_MAX_CHANNELS)) {
528                                 error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, start);
529                                 return -1;
530                         }
531                         res2 =sscanf(range[1], "%d", &finish);
532                         if (res2 != 1) {
533                                 error("Syntax error.  End of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
534                                 return -1;
535                         } else if ((finish < 1) || (finish >= DAHDI_MAX_CHANNELS)) {
536                                 error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, finish);
537                                 return -1;
538                         }
539                         if (start > finish) {
540                                 error("Range '%s' should start before it ends\n", args[x]);
541                                 return -1;
542                         }
543                         for (y=start;y<=finish;y++)
544                                 chans[y]=1;
545                 } else {
546                         /* It's a single channel */
547                         res2 =sscanf(args[x], "%d", &chan);
548                         if (res2 != 1) {
549                                 error("Syntax error.  Channel should be a number from 1 to %d, not '%s'\n", DAHDI_MAX_CHANNELS - 1, args[x]);
550                                 return -1;
551                         } else if ((chan < 1) || (chan >= DAHDI_MAX_CHANNELS)) {
552                                 error("Channel must be between 1 and %d (not '%d')\n", DAHDI_MAX_CHANNELS - 1, chan);
553                                 return -1;
554                         }
555                         chans[chan]=1;
556                 }               
557         }
558         return res;
559 }
560
561 int parse_idle(int *i, char *s)
562 {
563         char a,b,c,d;
564         if (s) {
565                 if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) {
566                         if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) {
567                                 *i = 0;
568                                 if (a == '1') 
569                                         *i |= DAHDI_ABIT;
570                                 if (b == '1')
571                                         *i |= DAHDI_BBIT;
572                                 if (c == '1')
573                                         *i |= DAHDI_CBIT;
574                                 if (d == '1')
575                                         *i |= DAHDI_DBIT;
576                                 return 0;
577                         }
578                 }
579         }
580         error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n");
581         return -1;
582 }
583
584 static int parse_channel(char *channel, int *startchan)
585 {
586         if (!channel || (sscanf(channel, "%d", startchan) != 1) || 
587                 (*startchan < 1)) {
588                 error("DACS requires a starting channel in the form ':x' where x is the channel\n");
589                 return -1;
590         }
591         return 0;
592 }
593
594 static int chanconfig(char *keyword, char *args)
595 {
596         int chans[DAHDI_MAX_CHANNELS];
597         int res = 0;
598         int x;
599         int master=0;
600         int dacschan = 0;
601         char *idle;
602         bzero(chans, sizeof(chans));
603         strtok(args, ":");
604         idle = strtok(NULL, ":");
605         if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) {
606                 res = parse_channel(idle, &dacschan);
607         }
608         if (!res)
609                 res = apply_channels(chans, args);
610         if (res <= 0)
611                 return -1;
612         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
613                 if (chans[x]) {
614                         if (slineno[x]) {
615                                 error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
616                                 continue;
617                         }
618                         if ((!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) && slineno[dacschan]) {
619                                 error("DACS Destination channel %d already configured as '%s' at line %d\n", dacschan, sig[dacschan], slineno[dacschan]);
620                                 continue;
621                         } else {
622                                 cc[dacschan].chan = dacschan;
623                                 cc[dacschan].master = dacschan;
624                                 slineno[dacschan] = lineno;
625                         }
626                         cc[x].chan = x;
627                         cc[x].master = x;
628                         slineno[x] = lineno;
629                         if (!strcasecmp(keyword, "e&m")) {
630                                 cc[x].sigtype = DAHDI_SIG_EM;
631                                 sig[x] = sigtype_to_str(cc[x].sigtype);
632                         } else if (!strcasecmp(keyword, "e&me1")) {
633                                 cc[x].sigtype = DAHDI_SIG_EM_E1;
634                                 sig[x] = sigtype_to_str(cc[x].sigtype);
635                         } else if (!strcasecmp(keyword, "fxsls")) {
636                                 cc[x].sigtype = DAHDI_SIG_FXSLS;
637                                 sig[x] = sigtype_to_str(cc[x].sigtype);
638                         } else if (!strcasecmp(keyword, "fxsgs")) {
639                                 cc[x].sigtype = DAHDI_SIG_FXSGS;
640                                 sig[x] = sigtype_to_str(cc[x].sigtype);
641                         } else if (!strcasecmp(keyword, "fxsks")) {
642                                 cc[x].sigtype = DAHDI_SIG_FXSKS;
643                                 sig[x] = sigtype_to_str(cc[x].sigtype);
644                         } else if (!strcasecmp(keyword, "fxols")) {
645                                 cc[x].sigtype = DAHDI_SIG_FXOLS;
646                                 sig[x] = sigtype_to_str(cc[x].sigtype);
647                         } else if (!strcasecmp(keyword, "fxogs")) {
648                                 cc[x].sigtype = DAHDI_SIG_FXOGS;
649                                 sig[x] = sigtype_to_str(cc[x].sigtype);
650                         } else if (!strcasecmp(keyword, "fxoks")) {
651                                 cc[x].sigtype = DAHDI_SIG_FXOKS;
652                                 sig[x] = sigtype_to_str(cc[x].sigtype);
653                         } else if (!strcasecmp(keyword, "cas") || !strcasecmp(keyword, "user")) {
654                                 if (parse_idle(&cc[x].idlebits, idle))
655                                         return -1;
656                                 cc[x].sigtype = DAHDI_SIG_CAS;
657                                 sig[x] = sigtype_to_str(cc[x].sigtype);
658                         } else if (!strcasecmp(keyword, "dacs")) {
659                                 /* Setup channel for monitor */
660                                 cc[x].idlebits = dacschan;
661                                 cc[x].sigtype = DAHDI_SIG_DACS;
662                                 sig[x] = sigtype_to_str(cc[x].sigtype);
663                                 /* Setup inverse */
664                                 cc[dacschan].idlebits = x;
665                                 cc[dacschan].sigtype = DAHDI_SIG_DACS;
666                                 sig[x] = sigtype_to_str(cc[dacschan].sigtype);
667                                 dacschan++;
668                         } else if (!strcasecmp(keyword, "dacsrbs")) {
669                                 /* Setup channel for monitor */
670                                 cc[x].idlebits = dacschan;
671                                 cc[x].sigtype = DAHDI_SIG_DACS_RBS;
672                                 sig[x] = sigtype_to_str(cc[x].sigtype);
673                                 /* Setup inverse */
674                                 cc[dacschan].idlebits = x;
675                                 cc[dacschan].sigtype = DAHDI_SIG_DACS_RBS;
676                                 sig[x] = sigtype_to_str(cc[dacschan].sigtype);
677                                 dacschan++;
678                         } else if (!strcasecmp(keyword, "unused")) {
679                                 cc[x].sigtype = 0;
680                                 sig[x] = sigtype_to_str(cc[x].sigtype);
681                         } else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
682                                 cc[x].sigtype = DAHDI_SIG_CLEAR;
683                                 sig[x] = sigtype_to_str(cc[x].sigtype);
684                         } else if (!strcasecmp(keyword, "clear")) {
685                                 sig[x] = sigtype_to_str(DAHDI_SIG_CLEAR);
686                                 if (master) {
687                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
688                                         cc[x].master = master;
689                                 } else {
690                                         cc[x].sigtype = DAHDI_SIG_CLEAR;
691                                         master = x;
692                                 }
693                         } else if (!strcasecmp(keyword, "rawhdlc")) {
694                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCRAW);
695                                 if (master) {
696                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
697                                         cc[x].master = master;
698                                 } else {
699                                         cc[x].sigtype = DAHDI_SIG_HDLCRAW;
700                                         master = x;
701                                 }
702                         } else if (!strcasecmp(keyword, "nethdlc")) {
703                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCNET);
704                                 memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
705                                 if (master) {
706                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
707                                         cc[x].master = master;
708                                 } else {
709                                         cc[x].sigtype = DAHDI_SIG_HDLCNET;
710                                         if (idle) {
711                                             dahdi_copy_string(cc[x].netdev_name, idle, sizeof(cc[x].netdev_name));
712                                         }
713                                         master = x;
714                                 }
715                         } else if (!strcasecmp(keyword, "fcshdlc")) {
716                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCFCS);
717                                 if (master) {
718                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
719                                         cc[x].master = master;
720                                 } else {
721                                         cc[x].sigtype = DAHDI_SIG_HDLCFCS;
722                                         master = x;
723                                 }
724                         } else if (!strcasecmp(keyword, "dchan")) {
725                                 sig[x] = "D-channel";
726                                 cc[x].sigtype = DAHDI_SIG_HDLCFCS;
727                         } else if (!strcasecmp(keyword, "hardhdlc")) {
728                                 sig[x] = "Hardware assisted D-channel";
729                                 cc[x].sigtype = DAHDI_SIG_HARDHDLC;
730                         } else if (!strcasecmp(keyword, "mtp2")) {
731                                 sig[x] = "MTP2";
732                                 cc[x].sigtype = DAHDI_SIG_MTP2;
733                         } else {
734                                 fprintf(stderr, "Huh? (%s)\n", keyword);
735                         }
736
737                         if (cc[x].sigtype != DAHDI_SIG_CAS &&
738                             cc[x].sigtype != DAHDI_SIG_DACS &&
739                             cc[x].sigtype != DAHDI_SIG_DACS_RBS) {
740                                 if (NULL != idle) {
741                                         fprintf(stderr, "WARNING: idlebits are not valid on %s channels.\n", sig[x]);
742                                 }
743                         }
744                 }
745         }
746         return 0;
747 }
748
749 static int setlaw(char *keyword, char *args)
750 {
751         int res;
752         int law;
753         int x;
754         int chans[DAHDI_MAX_CHANNELS];
755
756         bzero(chans, sizeof(chans));
757         res = apply_channels(chans, args);
758         if (res <= 0)
759                 return -1;
760         if (!strcasecmp(keyword, "alaw")) {
761                 law = DAHDI_LAW_ALAW;
762         } else if (!strcasecmp(keyword, "mulaw")) {
763                 law = DAHDI_LAW_MULAW;
764         } else if (!strcasecmp(keyword, "deflaw")) {
765                 law = DAHDI_LAW_DEFAULT;
766         } else {
767                 fprintf(stderr, "Huh??? Don't know about '%s' law\n", keyword);
768                 return -1;
769         }
770         for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
771                 if (chans[x])
772                         cc[x].deflaw = law;
773         }
774         return 0;
775 }
776
777 static int setfiftysixkhdlc(char *keyword, char *args)
778 {
779         int res;
780
781         res = apply_channels(fiftysixkhdlc, args);
782         if (res <= 0)
783                 return -1;
784
785         return 0;
786 }
787
788 static int apply_fiftysix(void)
789 {
790         int x;
791         int rate;
792         int chanfd;
793
794         for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
795                 if (skip_channel(x) || !cc[x].sigtype)
796                         continue;
797
798                 chanfd = open("/dev/dahdi/channel", O_RDWR);
799                 if (chanfd == -1) {
800                         fprintf(stderr, 
801                             "Couldn't open /dev/dahdi/channel: %s\n", 
802                             strerror(errno));
803                         return -1;      
804                 }
805
806                 if (ioctl(chanfd, DAHDI_SPECIFY, &x)) {
807                         close(chanfd);
808                         continue;
809                 }
810
811                 if (fiftysixkhdlc[x]) {
812                         printf("Setting channel %d to 56K mode (only valid on HDLC channels)\n", x);
813                         rate = 56;
814                 } else {
815                         rate = 64;
816                 }
817
818                 if (ioctl(chanfd, DAHDI_HDLC_RATE, &rate)) {
819                         fprintf(stderr, "Error setting HDLC rate\n");
820                         exit(-1);
821                 }
822                 close(chanfd);
823         }
824         return 0;
825 }
826
827 static int setechocan(char *keyword, char *args)
828 {
829         int res;
830         int chans[DAHDI_MAX_CHANNELS] = { 0, };
831         char *echocan, *chanlist;
832         unsigned int x;
833
834         echocan = strtok(args, ",");
835
836         while ((chanlist = strtok(NULL, ","))) {
837                 res = apply_channels(chans, chanlist);
838                 if (res <= 0) {
839                         return -1;
840                 }
841         }
842
843         for (x = 0; x < DAHDI_MAX_CHANNELS; x++) {
844                 if (chans[x]) {
845                         dahdi_copy_string(ae[x].echocan, echocan, sizeof(ae[x].echocan));
846                 }
847         }
848
849         return 0;
850 }
851
852 static int registerzone(char *keyword, char *args)
853 {
854         if (numzones >= DAHDI_TONE_ZONE_MAX) {
855                 error("Too many tone zones specified\n");
856                 return 0;
857         }
858         dahdi_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0]));
859         return 0;
860 }
861
862 static int defaultzone(char *keyword, char *args)
863 {
864         struct tone_zone *z;
865         if (!(z = tone_zone_find(args))) {
866                 error("No such tone zone known: %s\n", args);
867                 return 0;
868         }
869         deftonezone = z->zone;
870         return 0;
871 }
872
873 #if 0
874 static int unimplemented(char *keyword, char *args)
875 {
876         fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword);
877         return 0;
878 }
879 #endif
880
881
882 /* Radio functions */
883
884 int ctcss(char *keyword, char *args)
885 {
886         static char *realargs[10];
887         int res;
888         int rxtone;
889         int rxtag;
890         int txtone;
891         int isdcs = 0;
892         res = parseargs(args, realargs, 3, ',');
893         if (res != 3) {
894                 error("Incorrect number of arguments to 'ctcss' (should be <rxtone>,<rxtag>,<txtone>)\n");
895                 return -1;
896         }
897         res = sscanf(realargs[0], "%d", &rxtone);
898         if ((res == 1) && (rxtone < 1))
899                 res = -1;
900         if (res != 1) {
901                 error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
902                 return -1;
903         }
904         res = sscanf(realargs[1], "%d", &rxtag);
905         if ((res == 1) && (rxtag < 0))
906                 res = -1;
907         if (res != 1) {
908                 error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]);
909                 return -1;
910         }
911         if ((*realargs[2] == 'D') || (*realargs[2] == 'd'))
912         {
913                 realargs[2]++;
914                 isdcs = 0x8000;
915         }
916         res = sscanf(realargs[2], "%d", &txtone);
917         if ((res == 1) && (rxtag < 0))
918                 res = -1;
919         if (res != 1) {
920                 error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]);
921                 return -1;
922         }
923
924         if (toneindex >= NUM_TONES)
925         {
926                 error("Cannot specify more then %d CTCSS tones\n",NUM_TONES);
927                 return -1;
928         }
929         rxtones[toneindex] = rxtone;
930         rxtags[toneindex] = rxtag;
931         txtones[toneindex] = txtone | isdcs;
932         toneindex++;
933         return 0;
934 }
935
936 int dcsrx(char *keyword, char *args)
937 {
938         static char *realargs[10];
939         int res;
940         int rxtone;
941         res = parseargs(args, realargs, 1, ',');
942         if (res != 1) {
943                 error("Incorrect number of arguments to 'dcsrx' (should be <rxtone>)\n");
944                 return -1;
945         }
946         res = sscanf(realargs[0], "%d", &rxtone);
947         if ((res == 1) && (rxtone < 1))
948                 res = -1;
949         if (res != 1) {
950                 error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
951                 return -1;
952         }
953
954         rxtones[0] = rxtone;
955         return 0;
956 }
957
958 int tx(char *keyword, char *args)
959 {
960         static char *realargs[10];
961         int res;
962         int txtone;
963         int isdcs = 0;
964         res = parseargs(args, realargs, 1, ',');
965         if (res != 1) {
966                 error("Incorrect number of arguments to 'tx' (should be <txtone>)\n");
967                 return -1;
968         }
969         if ((*realargs[0] == 'D') || (*realargs[0] == 'd'))
970         {
971                 realargs[0]++;
972                 isdcs = 0x8000;
973         }
974         res = sscanf(realargs[0], "%d", &txtone);
975         if ((res == 1) && (txtone < 1))
976                 res = -1;
977         if (res != 1) {
978                 error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]);
979                 return -1;
980         }
981
982         txtones[0] = txtone | isdcs;
983         return 0;
984 }
985
986 int debounce_time(char *keyword, char *args)
987 {
988         static char *realargs[10];
989         int res;
990         int val;
991         res = parseargs(args, realargs, 1, ',');
992         if (res != 1) {
993                 error("Incorrect number of arguments to 'debouncetime' (should be <value>)\n");
994                 return -1;
995         }
996         res = sscanf(realargs[0], "%d", &val);
997         if ((res == 1) && (val < 1))
998                 res = -1;
999         if (res != 1) {
1000                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1001                 return -1;
1002         }
1003
1004         debouncetime = val;
1005         return 0;
1006 }
1007
1008 int burst_time(char *keyword, char *args)
1009 {
1010         static char *realargs[10];
1011         int res;
1012         int val;
1013         res = parseargs(args, realargs, 1, ',');
1014         if (res != 1) {
1015                 error("Incorrect number of arguments to 'bursttime' (should be <value>)\n");
1016                 return -1;
1017         }
1018         res = sscanf(realargs[0], "%d", &val);
1019         if ((res == 1) && (val < 1))
1020                 res = -1;
1021         if (res != 1) {
1022                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1023                 return -1;
1024         }
1025
1026         bursttime = val;
1027         return 0;
1028 }
1029
1030 int tx_gain(char *keyword, char *args)
1031 {
1032         static char *realargs[10];
1033         int res;
1034         int val;
1035         res = parseargs(args, realargs, 1, ',');
1036         if (res != 1) {
1037                 error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
1038                 return -1;
1039         }
1040         res = sscanf(realargs[0], "%d", &val);
1041         if (res != 1) {
1042                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1043                 return -1;
1044         }
1045
1046         txgain = val;
1047         return 0;
1048 }
1049
1050 int rx_gain(char *keyword, char *args)
1051 {
1052         static char *realargs[10];
1053         int res;
1054         int val;
1055         res = parseargs(args, realargs, 1, ',');
1056         if (res != 1) {
1057                 error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
1058                 return -1;
1059         }
1060         res = sscanf(realargs[0], "%d", &val);
1061         if (res != 1) {
1062                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1063                 return -1;
1064         }
1065
1066         rxgain = val;
1067         return 0;
1068 }
1069
1070 int de_emp(char *keyword, char *args)
1071 {
1072         static char *realargs[10];
1073         int res;
1074         int val;
1075         res = parseargs(args, realargs, 1, ',');
1076         if (res != 1) {
1077                 error("Incorrect number of arguments to 'de-emp' (should be <value>)\n");
1078                 return -1;
1079         }
1080         res = sscanf(realargs[0], "%d", &val);
1081         if ((res == 1) && (val < 1))
1082                 res = -1;
1083         if (res != 1) {
1084                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1085                 return -1;
1086         }
1087
1088         deemp = val;
1089         return 0;
1090 }
1091
1092 int pre_emp(char *keyword, char *args)
1093 {
1094         static char *realargs[10];
1095         int res;
1096         int val;
1097         res = parseargs(args, realargs, 1, ',');
1098         if (res != 1) {
1099                 error("Incorrect number of arguments to 'pre_emp' (should be <value>)\n");
1100                 return -1;
1101         }
1102         res = sscanf(realargs[0], "%d", &val);
1103         if ((res == 1) && (val < 1))
1104                 res = -1;
1105         if (res != 1) {
1106                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1107                 return -1;
1108         }
1109
1110         preemp = val;
1111         return 0;
1112 }
1113
1114 int invert_cor(char *keyword, char *args)
1115 {
1116         static char *realargs[10];
1117         int res;
1118         int val;
1119         res = parseargs(args, realargs, 1, ',');
1120         if (res != 1) {
1121                 error("Incorrect number of arguments to 'invertcor' (should be <value>)\n");
1122                 return -1;
1123         }
1124         if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
1125         else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
1126         else
1127         {
1128                 res = sscanf(realargs[0], "%d", &val);
1129                 if ((res == 1) && (val < 0))
1130                         res = -1;
1131                 if (res != 1) {
1132                         error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1133                         return -1;
1134                 }
1135         }
1136         invertcor = (val > 0);
1137         return 0;
1138 }
1139
1140 int ext_tone(char *keyword, char *args)
1141 {
1142         static char *realargs[10];
1143         int res;
1144         int val;
1145         res = parseargs(args, realargs, 1, ',');
1146         if (res != 1) {
1147                 error("Incorrect number of arguments to 'exttone' (should be <value>)\n");
1148                 return -1;
1149         }
1150         if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
1151         else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
1152         else if ((*realargs[0] == 'i') || (*realargs[0] == 'I')) val = 2;
1153         else
1154         {
1155                 res = sscanf(realargs[0], "%d", &val);
1156                 if ((res == 1) && (val < 0))
1157                         res = -1;
1158                 if (val > 2) res = -1;
1159                 if (res != 1) {
1160                         error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1161                         return -1;
1162                 }
1163         }
1164         exttone = val;
1165         return 0;
1166 }
1167
1168 int cor_thresh(char *keyword, char *args)
1169 {
1170         static char *realargs[10];
1171         int res;
1172         int val;
1173         int x = 0;
1174         res = parseargs(args, realargs, 1, ',');
1175         if (res != 1) {
1176                 error("Incorrect number of arguments to 'corthresh' (should be <value>)\n");
1177                 return -1;
1178         }
1179         res = sscanf(realargs[0], "%d", &val);
1180         if ((res == 1) && (val < 1))
1181                 res = -1;
1182         for(x = 0; corthreshes[x]; x++)
1183         {
1184                 if (corthreshes[x] == val) break;
1185         }
1186         if (!corthreshes[x]) res = -1;
1187         if (res != 1) {
1188                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1189                 return -1;
1190         }
1191         corthresh = x + 1;
1192         return 0;
1193 }
1194
1195 static int rad_chanconfig(char *keyword, char *args)
1196 {
1197         int chans[DAHDI_MAX_CHANNELS];
1198         int res = 0;
1199         int x,i,n;
1200         struct dahdi_radio_param p;
1201         int chanfd;
1202
1203         toneindex = 1;
1204         bzero(chans, sizeof(chans));
1205         res = apply_channels(chans, args);
1206         if (res <= 0)
1207                 return -1;
1208         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1209                 if (chans[x]) {
1210                         const char *CHANNEL_FILENAME = "/dev/dahdi/channel";
1211                         chanfd = open(CHANNEL_FILENAME, O_RDWR);
1212                         if (-1 == chanfd) {
1213                                 error("Failed to open '%s'.\n", CHANNEL_FILENAME);
1214                                 exit(-1);
1215                         }
1216
1217                         res = ioctl(chanfd, DAHDI_SPECIFY, &x);
1218                         if (res) {
1219                                 error("Failed to open channel %d.\n", x);
1220                                 close(chanfd);
1221                                 continue;
1222                         }
1223                         p.radpar = DAHDI_RADPAR_NUMTONES;
1224                         if (ioctl(chanfd,DAHDI_RADIO_GETPARAM,&p) == -1)
1225                                 n = 0;
1226                         else
1227                                 n = p.data;
1228
1229                         if (n)
1230                         {
1231                                 p.radpar = DAHDI_RADPAR_INITTONE;
1232                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1) {
1233                                         error("Cannot init tones for channel %d\n",x);
1234                                 }
1235                                 if (!rxtones[0]) for(i = 1; i <= n; i++)
1236                                 {
1237                                         if (rxtones[i])
1238                                         {
1239                                                 p.radpar = DAHDI_RADPAR_RXTONE;
1240                                                 p.index = i;
1241                                                 p.data = rxtones[i];
1242                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1243                                                         error("Cannot set rxtone on channel %d\n",x);
1244                                         }
1245                                         if (rxtags[i])
1246                                         {
1247                                                 p.radpar = DAHDI_RADPAR_RXTONECLASS;
1248                                                 p.index = i;
1249                                                 p.data = rxtags[i];
1250                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1251                                                         error("Cannot set rxtag on channel %d\n",x);
1252                                         }
1253                                         if (txtones[i])
1254                                         {
1255                                                 p.radpar = DAHDI_RADPAR_TXTONE;
1256                                                 p.index = i;
1257                                                 p.data = txtones[i];
1258                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1259                                                         error("Cannot set txtone on channel %d\n",x);
1260                                         }
1261                                 } else { /* if we may have DCS receive */
1262                                         if (rxtones[0])
1263                                         {
1264                                                 p.radpar = DAHDI_RADPAR_RXTONE;
1265                                                 p.index = 0;
1266                                                 p.data = rxtones[0];
1267                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1268                                                         error("Cannot set DCS rxtone on channel %d\n",x);
1269                                         }
1270                                 }
1271                                 if (txtones[0])
1272                                 {
1273                                         p.radpar = DAHDI_RADPAR_TXTONE;
1274                                         p.index = 0;
1275                                         p.data = txtones[0];
1276                                         if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1277                                                 error("Cannot set default txtone on channel %d\n",x);
1278                                 }
1279                         }
1280                         if (debouncetime)
1281                         {
1282                                 p.radpar = DAHDI_RADPAR_DEBOUNCETIME;
1283                                 p.data = debouncetime;
1284                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1285                                         error("Cannot set debouncetime on channel %d\n",x);
1286                         }
1287                         if (bursttime)
1288                         {
1289                                 p.radpar = DAHDI_RADPAR_BURSTTIME;
1290                                 p.data = bursttime;
1291                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1292                                         error("Cannot set bursttime on channel %d\n",x);
1293                         }
1294                         p.radpar = DAHDI_RADPAR_DEEMP;
1295                         p.data = deemp;
1296                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1297                         p.radpar = DAHDI_RADPAR_PREEMP;
1298                         p.data = preemp;
1299                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1300                         p.radpar = DAHDI_RADPAR_TXGAIN;
1301                         p.data = txgain;
1302                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1303                         p.radpar = DAHDI_RADPAR_RXGAIN;
1304                         p.data = rxgain;
1305                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1306                         p.radpar = DAHDI_RADPAR_INVERTCOR;
1307                         p.data = invertcor;
1308                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1309                         p.radpar = DAHDI_RADPAR_EXTRXTONE;
1310                         p.data = exttone;
1311                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1312                         if (corthresh)
1313                         {
1314                                 p.radpar = DAHDI_RADPAR_CORTHRESH;
1315                                 p.data = corthresh - 1;
1316                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1317                                         error("Cannot set corthresh on channel %d\n",x);
1318                         }
1319
1320                         close(chanfd);
1321                 }
1322         }
1323         clear_fields();
1324         return 0;
1325 }
1326
1327 /* End Radio functions */
1328
1329 static void printconfig(int fd)
1330 {
1331         int x,y;
1332         int ps;
1333         int configs=0;
1334         struct dahdi_versioninfo vi;
1335
1336         strcpy(vi.version, "Unknown");
1337         strcpy(vi.echo_canceller, "Unknown");
1338
1339         if (ioctl(fd, DAHDI_GETVERSION, &vi))
1340                 error("Unable to read DAHDI version information.\n");
1341
1342         printf("\nDAHDI Version: %s\n"
1343                "Echo Canceller(s): %s\n"
1344                "Configuration\n"
1345                "======================\n\n", vi.version, vi.echo_canceller);
1346         for (x = 0; x < spans; x++) {
1347                 if (only_span && only_span != lc[x].span)
1348                         continue;
1349                 printf("SPAN %d: %3s/%4s Build-out: %s\n",
1350                        lc[x].span,
1351                        (lc[x].lineconfig & DAHDI_CONFIG_D4 ? "D4" :
1352                         lc[x].lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
1353                         lc[x].lineconfig & DAHDI_CONFIG_CCS ? "CCS" : "CAS"),
1354                        (lc[x].lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
1355                         lc[x].lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
1356                         lc[x].lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : "???"),
1357                        lbostr[lc[x].lbo]);
1358         }
1359         for (x=0;x<numdynamic;x++) {
1360                 printf("Dynamic span %d: driver %s, addr %s, channels %d, timing %d\n",
1361                        x +1, zds[x].driver, zds[x].addr, zds[x].numchans, zds[x].timing);
1362         }
1363         if (verbose > 1) {
1364                 printf("\nChannel map:\n\n");
1365                 for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1366                         if (skip_channel(x))
1367                                 continue;
1368                         if ((cc[x].sigtype != DAHDI_SIG_SLAVE) && (cc[x].sigtype)) {
1369                                 configs++;
1370                                 ps = 0;
1371                                 if ((cc[x].sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
1372                                         printf("Channel %02d %s to %02d", x, sig[x], cc[x].idlebits);
1373                                 else {
1374                                         printf("Channel %02d: %s (%s)", x, sig[x], laws[cc[x].deflaw]);
1375                                         printf(" (Echo Canceler: %s)", ae[x].echocan[0] ? ae[x].echocan : "none");
1376                                         for (y=1;y<DAHDI_MAX_CHANNELS;y++) {
1377                                                 if (cc[y].master == x)  {
1378                                                         printf("%s%02d", ps++ ? " " : " (Slaves: ", y);
1379                                                 }
1380                                         }
1381                                 }
1382                                 if (ps)
1383                                         printf(")\n");
1384                                 else
1385                                         printf("\n");
1386                         } else
1387                                 if (cc[x].sigtype) configs++;
1388                 }
1389         } else {
1390                 for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1391                         if (skip_channel(x))
1392                                 continue;
1393                         if (cc[x].sigtype)
1394                                 configs++;
1395                 }
1396         }
1397         printf("\n%d channels to configure.\n\n", configs);
1398 }
1399
1400 static struct handler {
1401         char *keyword;
1402         int (*func)(char *keyword, char *args);
1403 } handlers[] = {
1404         { "span", spanconfig },
1405         { "dynamic", dspanconfig },
1406         { "loadzone", registerzone },
1407         { "defaultzone", defaultzone },
1408         { "e&m", chanconfig },
1409         { "e&me1", chanconfig },
1410         { "fxsls", chanconfig },
1411         { "fxsgs", chanconfig },
1412         { "fxsks", chanconfig },
1413         { "fxols", chanconfig },
1414         { "fxogs", chanconfig },
1415         { "fxoks", chanconfig },
1416         { "rawhdlc", chanconfig },
1417         { "nethdlc", chanconfig },
1418         { "fcshdlc", chanconfig },
1419         { "hardhdlc", chanconfig },
1420         { "mtp2", chanconfig },
1421         { "dchan", chanconfig },
1422         { "bchan", chanconfig },
1423         { "indclear", chanconfig },
1424         { "clear", chanconfig },
1425         { "unused", chanconfig },
1426         { "cas", chanconfig },
1427         { "dacs", chanconfig },
1428         { "dacsrbs", chanconfig },
1429         { "user", chanconfig },
1430         { "alaw", setlaw },
1431         { "mulaw", setlaw },
1432         { "deflaw", setlaw },
1433         { "ctcss", ctcss },
1434         { "dcsrx", dcsrx },
1435         { "rxdcs", dcsrx },
1436         { "tx", tx },
1437         { "debouncetime", debounce_time },
1438         { "bursttime", burst_time },
1439         { "exttone", ext_tone },
1440         { "invertcor", invert_cor },
1441         { "corthresh", cor_thresh },
1442         { "rxgain", rx_gain },
1443         { "txgain", tx_gain },
1444         { "deemp", de_emp },
1445         { "preemp", pre_emp },
1446         { "channel", rad_chanconfig },
1447         { "channels", rad_chanconfig },
1448         { "echocanceller", setechocan },
1449         { "56k", setfiftysixkhdlc },
1450 };
1451
1452 static char *readline()
1453 {
1454         static char buf[256];
1455         char *c;
1456         do {
1457                 if (!fgets(buf, sizeof(buf), cf)) 
1458                         return NULL;
1459                 /* Strip comments */
1460                 c = strchr(buf, '#');
1461                 if (c)
1462                         *c = '\0';
1463                 trim(buf);
1464                 lineno++;
1465         } while (!strlen(buf));
1466         return buf;
1467 }
1468
1469 static void usage(char *argv0, int exitcode)
1470 {
1471         char *c;
1472         c = strrchr(argv0, '/');
1473         if (!c)
1474                 c = argv0;
1475         else
1476                 c++;
1477         fprintf(stderr, "%s\n", dahdi_tools_version);
1478         fprintf(stderr, 
1479                 "Usage: %s [options]\n"
1480                 "    Valid options are:\n"
1481                 "  -c <filename>     -- Use <filename> instead of " CONFIG_FILENAME "\n"
1482                 "  -d [level]        -- Generate debugging output. (Default level is 1.)\n"
1483                 "  -f                -- Always reconfigure every channel\n"
1484                 "  -h                -- Generate this help statement\n"
1485                 "  -s                -- Shutdown spans only\n"
1486                 "  -t                -- Test mode only, do not apply\n"
1487                 "  -C <chan_list>    -- Only configure specified channels\n"
1488                 "  -S <spanno>       -- Only configure specified span\n"
1489                 "  -v                -- Verbose (more -v's means more verbose)\n"
1490         ,c);
1491         exit(exitcode);
1492 }
1493
1494 static int chan_restrict(char *str)
1495 {
1496         if (apply_channels(selected_channels, str) < 0)
1497                 return 0;
1498         restrict_channels = 1;
1499         return 1;
1500 }
1501
1502 static int span_restrict(char *str)
1503 {
1504         long    spanno;
1505         char    *endptr;
1506
1507         spanno = strtol(str, &endptr, 10);
1508         if (endptr == str) {
1509                 fprintf(stderr, "Missing valid span number after '-S'\n");
1510                 return 0;
1511         }
1512         if (*endptr != '\0') {
1513                 fprintf(stderr, "Extra garbage after span number in '-S'\n");
1514                 return 0;
1515         }
1516         only_span = spanno;
1517         return 1;
1518 }
1519
1520 static const char *SEM_NAME = "dahdi_cfg";
1521 static sem_t *lock = SEM_FAILED;
1522
1523 static void signal_handler(int signal)
1524 {
1525         if (SEM_FAILED != lock) {
1526                 sem_unlink(SEM_NAME);
1527         }
1528         /* The default handler should have been restored before this handler was
1529          * called, so we can let the "normal" processing finish the cleanup. */
1530         raise(signal);
1531 }
1532
1533 int main(int argc, char *argv[])
1534 {
1535         int c;
1536         char *buf;
1537         char *key, *value;
1538         int x,found;
1539         int exit_code = 0;
1540         struct sigaction act;
1541
1542         while((c = getopt(argc, argv, "fthc:vsd::C:S:")) != -1) {
1543                 switch(c) {
1544                 case 'c':
1545                         filename=optarg;
1546                         break;
1547                 case 'h':
1548                         usage(argv[0], 0);
1549                         break;
1550                 case '?':
1551                         usage(argv[0], 1);
1552                         break;
1553                 case 'v':
1554                         verbose++;
1555                         break;
1556                 case 'f':
1557                         force++;
1558                         break;
1559                 case 't':
1560                         dry_run = 1;
1561                         break;
1562                 case 's':
1563                         stopmode = 1;
1564                         break;
1565                 case 'C':
1566                         if (!chan_restrict(optarg))
1567                                 usage(argv[0], 1);
1568                         break;
1569                 case 'S':
1570                         if (!span_restrict(optarg))
1571                                 usage(argv[0], 1);
1572                         break;
1573                 case 'd':
1574                         if (optarg)
1575                                 debug = atoi(optarg);
1576                         else
1577                                 debug = 1;      
1578                         break;
1579                 }
1580         }
1581         
1582         if (verbose) {
1583                 fprintf(stderr, "%s\n", dahdi_tools_version);
1584         }
1585
1586         if (!restrict_channels && only_span) {
1587                 error("-S requires -C\n");
1588                 goto finish;
1589         }
1590         if (!restrict_channels && !only_span) {
1591                 bool all_assigned = wait_for_all_spans_assigned(5);
1592
1593                 if (!all_assigned) {
1594                         fprintf(stderr,
1595                                 "Timeout waiting for all spans to be assigned.\n");
1596                 }
1597         }
1598
1599         if (fd == -1) fd = open(MASTER_DEVICE, O_RDWR);
1600         if (fd < 0) {
1601                 error("Unable to open master device '%s'\n", MASTER_DEVICE);
1602                 goto finish;
1603         }
1604         if (strcmp(filename, "-") == 0)
1605                 cf = fdopen(STDIN_FILENO, "r");
1606         else
1607                 cf = fopen(filename, "r");
1608         if (cf) {
1609                 while((buf = readline())) {
1610                         if (*buf == 10) /* skip new line */
1611                                 continue;
1612
1613                         if (debug & DEBUG_READER) 
1614                                 fprintf(stderr, "Line %d: %s\n", lineno, buf);
1615
1616                         if ((value = strchr(buf, '='))) {
1617                                 *value++ = '\0';
1618                                 value = trim(value);
1619                                 key = trim(buf);
1620                         }
1621
1622                         if (!value || !*value || !*key) {
1623                                 error("Syntax error. Should be <keyword>=<value>\n");
1624                                 continue;
1625                         }
1626
1627                         if (debug & DEBUG_PARSER)
1628                                 fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value);
1629
1630                         found = 0;
1631                         for (x = 0; x < sizeof(handlers) / sizeof(handlers[0]); x++) {
1632                                 if (!strcasecmp(key, handlers[x].keyword)) {
1633                                         found++;
1634                                         handlers[x].func(key, value);
1635                                         break;
1636                                 }
1637                         }
1638
1639                         if (!found) 
1640                                 error("Unknown keyword '%s'\n", key);
1641                 }
1642                 if (debug & DEBUG_READER)
1643                         fprintf(stderr, "<End of File>\n");
1644                 /* fclose(cf); // causes seg fault (double free) */
1645         } else {
1646                 error("Unable to open configuration file '%s'\n", filename);
1647         }
1648
1649 finish:
1650         if (errcnt) {
1651                 fprintf(stderr, "\n%d error(s) detected\n\n", errcnt);
1652                 exit(1);
1653         }
1654         if (verbose) {
1655                 printconfig(fd);
1656         }
1657
1658         if (dry_run)
1659                 exit(0);
1660         
1661         if (debug & DEBUG_APPLY) {
1662                 printf("About to open Master device\n");
1663                 fflush(stdout);
1664         }
1665
1666         sigemptyset(&act.sa_mask);
1667         act.sa_handler = signal_handler;
1668         act.sa_flags = SA_RESETHAND;
1669
1670         if (sigaction(SIGTERM, &act, NULL) == -1) {
1671                 perror("Failed to install SIGTERM handler.");
1672                 exit(1);
1673         }
1674         if (sigaction(SIGINT, &act, NULL) == -1) {
1675                 perror("Failed to install SIGINT handler.");
1676                 exit(1);
1677         }
1678
1679         lock = sem_open(SEM_NAME, O_CREAT, O_RDWR, 1);
1680         if (SEM_FAILED == lock) {
1681                 perror("Unable to create 'dahdi_cfg' mutex");
1682                 exit_code = 1;
1683                 goto release_sem;
1684         }
1685
1686         if (-1 == sem_wait(lock)) {
1687                 perror("Failed to wait for 'dahdi_cfg' mutex");
1688                 exit_code = 1;
1689                 goto unlink_sem;
1690         }
1691
1692         if (!restrict_channels && !only_span) {
1693                 for (x=0;x<numdynamic;x++) {
1694                         /* destroy them all */
1695                         ioctl(fd, DAHDI_DYNAMIC_DESTROY, &zds[x]);
1696                 }
1697         }
1698
1699         if (stopmode) {
1700                 for (x=0;x<spans;x++) {
1701                         if (only_span && lc[x].span != only_span)
1702                                 continue;
1703                         if (ioctl(fd, DAHDI_SHUTDOWN, &lc[x].span)) {
1704                                 fprintf(stderr, "DAHDI shutdown failed: %s\n", strerror(errno));
1705                                 close(fd);
1706                                 exit_code = 1;
1707                                 goto release_sem;
1708                         }
1709                 }
1710                 exit_code = 1;
1711                 goto release_sem;
1712         }
1713         for (x=0;x<spans;x++) {
1714                 if (only_span && lc[x].span != only_span)
1715                         continue;
1716                 if (ioctl(fd, DAHDI_SPANCONFIG, lc + x)) {
1717                         fprintf(stderr, "DAHDI_SPANCONFIG failed on span %d: %s (%d)\n", lc[x].span, strerror(errno), errno);
1718                         close(fd);
1719                         exit_code = 1;
1720                         goto release_sem;
1721                 }
1722         }
1723
1724         if (!restrict_channels && !only_span) {
1725
1726                 sem_post(lock);
1727
1728                 for (x=0;x<numdynamic;x++) {
1729                         if (ioctl(fd, DAHDI_DYNAMIC_CREATE, &zds[x])) {
1730                                 fprintf(stderr, "DAHDI dynamic span creation failed: %s\n", strerror(errno));
1731                                 close(fd);
1732                                 exit_code = 1;
1733                                 goto release_sem;
1734                         }
1735                         wait_for_all_spans_assigned(1);
1736                 }
1737
1738                 if (-1 == sem_wait(lock)) {
1739                         perror("Failed to wait for 'dahdi_cfg' mutex after creating dynamic spans");
1740                         exit_code = 1;
1741                         goto unlink_sem;
1742                 }
1743         }
1744
1745         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1746                 struct dahdi_params current_state;
1747                 int master;
1748                 int needupdate = force;
1749
1750                 if (skip_channel(x)) {
1751                         if (debug & DEBUG_APPLY) {
1752                                 printf("Skip device %d\n", x);
1753                                 fflush(stdout);
1754                         }
1755                         continue;
1756                 }
1757                 if (debug & DEBUG_APPLY) {
1758                         printf("Configuring device %d\n", x);
1759                         fflush(stdout);
1760                 }
1761                 if (!cc[x].sigtype)
1762                         continue;
1763                 
1764                 if (!needupdate) {
1765                         memset(&current_state, 0, sizeof(current_state));
1766                         current_state.channo = cc[x].chan | DAHDI_GET_PARAMS_RETURN_MASTER;
1767                         if (ioctl(fd, DAHDI_GET_PARAMS, &current_state))
1768                                 needupdate = 1;
1769                 }
1770                 
1771                 if (!needupdate) {
1772                         master = current_state.channo >> 16;
1773                         
1774                         if (cc[x].sigtype != current_state.sigtype) {
1775                                 needupdate++;
1776                                 if (verbose > 1)
1777                                         printf("Changing signalling on channel %d from %s to %s\n",
1778                                                cc[x].chan, sigtype_to_str(current_state.sigtype),
1779                                                sigtype_to_str(cc[x].sigtype));
1780                         }
1781                         
1782                         if ((cc[x].deflaw != DAHDI_LAW_DEFAULT) && (cc[x].deflaw != current_state.curlaw)) {
1783                                 needupdate++;
1784                                 if (verbose > 1)
1785                                         printf("Changing law on channel %d from %s to %s\n",
1786                                                cc[x].chan, laws[current_state.curlaw],
1787                                                laws[cc[x].deflaw]);
1788                         }
1789                         
1790                         if (cc[x].master != master) {
1791                                 needupdate++;
1792                                 if (verbose > 1)
1793                                         printf("Changing master of channel %d from %d to %d\n",
1794                                                cc[x].chan, master,
1795                                                cc[x].master);
1796                         }
1797                         
1798                         if (cc[x].idlebits != current_state.idlebits) {
1799                                 needupdate++;
1800                                 if (verbose > 1)
1801                                         printf("Changing idle bits of channel %d from %d to %d\n",
1802                                                cc[x].chan, current_state.idlebits,
1803                                                cc[x].idlebits);
1804                         }
1805                 }
1806                 
1807                 if (needupdate && ioctl(fd, DAHDI_CHANCONFIG, &cc[x])) {
1808                         fprintf(stderr, "DAHDI_CHANCONFIG failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
1809                         if (errno == EINVAL) {
1810                                 /* give helpful suggestions on signaling errors */
1811                                 fprintf(stderr, "Selected signaling not "
1812                                                 "supported\n");
1813                                 fprintf(stderr, "Possible causes:\n");
1814                                 switch(cc[x].sigtype) {
1815                                 case DAHDI_SIG_FXOKS:
1816                                 case DAHDI_SIG_FXOLS:
1817                                 case DAHDI_SIG_FXOGS:
1818                                         fprintf(stderr, "\tFXO signaling is "
1819                                                 "being used on a FXO interface"
1820                                                 " (use a FXS signaling variant"
1821                                                 ")\n");
1822                                         fprintf(stderr, "\tRBS signaling is "
1823                                                 "being used on a E1 CCS span"
1824                                                 "\n");
1825                                         break;
1826                                 case DAHDI_SIG_FXSKS:
1827                                 case DAHDI_SIG_FXSLS:
1828                                 case DAHDI_SIG_FXSGS:
1829                                         fprintf(stderr, "\tFXS signaling is "
1830                                                 "being used on a FXS interface"
1831                                                 " (use a FXO signaling variant"
1832                                                 ")\n");
1833                                         fprintf(stderr, "\tRBS signaling is "
1834                                                 "being used on a E1 CCS span"
1835                                                 "\n");
1836                                         break;
1837                                 case DAHDI_SIG_EM:
1838                                         fprintf(stderr, "\te&m signaling is "
1839                                                 "being used on a E1 line (use"
1840                                                 " e&me1)\n");
1841                                         break;
1842                                 case DAHDI_SIG_EM_E1:
1843                                         fprintf(stderr, "\te&me1 signaling is "
1844                                                 "being used on a T1 line (use "
1845                                                 "e&m)\n");
1846                                         fprintf(stderr, "\tRBS signaling is "
1847                                                 "being used on a E1 CCS span"
1848                                                 "\n");
1849                                         break;
1850                                 case DAHDI_SIG_HARDHDLC:
1851                                         fprintf(stderr, "\thardhdlc is being "
1852                                                 "used on a TE12x (use dchan)\n"
1853                                                 );
1854                                         break;
1855                                 case DAHDI_SIG_HDLCFCS:
1856                                         fprintf(stderr, "\tdchan is being used"
1857                                                 " on a BRI span (use hardhdlc)"
1858                                                 "\n");
1859                                         break;
1860                                 default:
1861                                         break;
1862                                 }
1863                                 fprintf(stderr, "\tSignaling is being assigned"
1864                                         " to channel 16 of an E1 CAS span\n");
1865                         }
1866                         close(fd);
1867                         exit_code = 1;
1868                         goto release_sem;
1869                 }
1870
1871                 ae[x].chan = x;
1872                 if (verbose) {
1873                         printf("Setting echocan for channel %d to %s\n", ae[x].chan, ae[x].echocan[0] ? ae[x].echocan : "none");
1874                 }
1875
1876                 if (ioctl(fd, DAHDI_ATTACH_ECHOCAN, &ae[x])) {
1877                         fprintf(stderr, "DAHDI_ATTACH_ECHOCAN failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
1878                         close(fd);
1879                         exit_code = 1;
1880                         goto release_sem;
1881                 }
1882         }
1883         if (0 == numzones) {
1884                 /* Default to the us zone if one wasn't specified. */
1885                 dahdi_copy_string(zonestoload[numzones++], "us", sizeof(zonestoload[0]));
1886                 deftonezone = 0;
1887         }
1888
1889         for (x=0;x<numzones;x++) {
1890                 if (debug & DEBUG_APPLY) {
1891                         printf("Loading tone zone for %s\n", zonestoload[x]);
1892                         fflush(stdout);
1893                 }
1894                 if (tone_zone_register(fd, zonestoload[x])) {
1895                         if (errno != EBUSY)
1896                                 error("Unable to register tone zone '%s'\n", zonestoload[x]);
1897                 }
1898         }
1899         if (debug & DEBUG_APPLY) {
1900                 printf("Doing startup\n");
1901                 fflush(stdout);
1902         }
1903         if (deftonezone > -1) {
1904                 if (ioctl(fd, DAHDI_DEFAULTZONE, &deftonezone)) {
1905                         fprintf(stderr, "DAHDI_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno);
1906                         close(fd);
1907                         exit_code = 1;
1908                         goto release_sem;
1909                 }
1910         }
1911         for (x=0;x<spans;x++) {
1912                 if (only_span && lc[x].span != only_span)
1913                         continue;
1914                 if (ioctl(fd, DAHDI_STARTUP, &lc[x].span)) {
1915                         fprintf(stderr, "DAHDI startup failed: %s\n", strerror(errno));
1916                         close(fd);
1917                         exit_code = 1;
1918                         goto release_sem;
1919                 }
1920         }
1921         exit_code = apply_fiftysix();
1922
1923 release_sem:
1924         if (SEM_FAILED != lock)
1925                 sem_post(lock);
1926
1927 unlink_sem:
1928         if (SEM_FAILED != lock)
1929                 sem_unlink(SEM_NAME);
1930         exit(exit_code);
1931 }