patlooptest: Ignore the first buffered event
[dahdi/tools.git] / sethdlc.c
1 /*
2  * sethdlc.c
3  *
4  * Copyright (C) 1999 - 2002 Krzysztof Halasa <khc@pm.waw.pl>
5  *
6  */
7
8 /*
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2 as published by the
17  * Free Software Foundation. See the LICENSE file included with
18  * this program for more details.
19  */
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <asm/types.h>
28 #include <linux/hdlc.h>
29 #include <netinet/in.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
32 #include <linux/if.h>
33 #include <linux/sockios.h>
34
35 #include <dahdi/user.h>
36 #include "dahdi_tools_version.h"
37
38 #if GENERIC_HDLC_VERSION != 4
39 #error Generic HDLC layer version mismatch, please get correct sethdlc.c
40 #endif
41
42 #if !defined(IF_PROTO_HDLC_ETH) || !defined(IF_PROTO_FR_ETH_PVC)
43 #warning "No kernel support for Ethernet over Frame Relay / HDLC, skipping it"
44 #endif
45
46
47 static struct ifreq req;        /* for ioctl */
48 static int argc;
49 static char **argv;
50 int sock;
51
52
53 static void error(const char *format, ...) __attribute__ ((noreturn, format(printf, 1, 2)));
54
55 static void error(const char *format, ...)
56 {
57         va_list args;
58
59         va_start(args, format);
60         fprintf(stderr, "%s: ", req.ifr_name);
61         vfprintf(stderr, format, args);
62         va_end(args);
63         exit(1);
64 }
65
66
67
68 typedef struct {
69         const char *name;
70         const unsigned int value;
71 } parsertab;
72
73
74
75 static int checkkey(const char* name)
76 {
77         if (argc < 1)
78                 return -1;      /* no enough parameters */
79
80         if (strcmp(name, argv[0]))
81                 return -1;
82         argc--;
83         argv++;
84         return 0;
85 }
86
87
88
89 static int checktab(parsertab *tab, unsigned int *value)
90 {
91         int i;
92
93         if (argc < 1)
94                 return -1;      /* no enough parameters */
95         
96         for (i = 0; tab[i].name; i++)
97                 if (!strcmp(tab[i].name, argv[0])) {
98                         argc--;
99                         argv++;
100                         *value = tab[i].value;
101                         return 0;
102                 }
103
104         return -1;              /* Not found */
105 }
106
107
108
109 static const char* tabstr(unsigned int value, parsertab *tab,
110                           const char* unknown)
111 {
112         int i;
113         for (i = 0; tab[i].name; i++)
114                 if (tab[i].value == value)
115                         return tab[i].name;
116
117         return unknown;         /* Not found */
118 }
119
120
121
122 static unsigned int match(const char* name, unsigned int *value,
123                           unsigned int minimum, unsigned int maximum)
124 {
125         char test;
126
127         if (argc < 1)
128                 return -1;      /* no enough parameters */
129
130         if (name) {
131                 if (strcmp(name, argv[0]))
132                         return -1;
133                 argc--;
134                 argv++;
135         }
136
137         if (argc < 1)
138                 error("Missing parameter\n");
139
140         if (sscanf(argv[0], "%u%c", value, &test) != 1)
141                 error("Invalid parameter: %s\n", argv[0]);
142
143         if ((*value > maximum) || (*value < minimum))
144                 error("Parameter out of range [%u - %u]: %u\n",
145                       minimum, maximum, *value);
146
147         argc--;
148         argv++;
149         return 0;
150 }
151
152
153 static parsertab ifaces[] = {{ "v35", IF_IFACE_V35 },
154                              { "v24", IF_IFACE_V24 },
155                              { "x21", IF_IFACE_X21 },
156                              { "e1", IF_IFACE_E1 },
157                              { "t1", IF_IFACE_T1 },
158                              { NULL, 0 }};
159
160 static parsertab clocks[] = {{ "int", CLOCK_INT },
161                              { "ext", CLOCK_EXT },
162                              { "txint", CLOCK_TXINT },
163                              { "txfromrx", CLOCK_TXFROMRX },
164                              { NULL, 0 }};
165
166
167 static parsertab protos[] = {{ "hdlc", IF_PROTO_HDLC},
168                              { "cisco", IF_PROTO_CISCO},
169                              { "fr", IF_PROTO_FR},
170                              { "ppp", IF_PROTO_PPP},
171                              { "x25", IF_PROTO_X25},
172 #ifdef IF_PROTO_HDLC_ETH
173                              { "hdlc-eth", IF_PROTO_HDLC_ETH},
174 #endif
175                              { NULL, 0 }};
176
177
178 static parsertab hdlc_enc[] = {{ "nrz", ENCODING_NRZ },
179                                { "nrzi", ENCODING_NRZI },
180                                { "fm-mark", ENCODING_FM_MARK },
181                                { "fm-space", ENCODING_FM_SPACE },
182                                { "manchester", ENCODING_MANCHESTER },
183                                { NULL, 0 }};
184
185 static parsertab hdlc_par[] = {{ "no-parity", PARITY_NONE },
186                                { "crc16", PARITY_CRC16_PR1 },
187                                { "crc16-pr0", PARITY_CRC16_PR0 },
188                                { "crc16-itu", PARITY_CRC16_PR1_CCITT },
189                                { "crc16-itu-pr0", PARITY_CRC16_PR0_CCITT },
190                                { "crc32-itu", PARITY_CRC32_PR1_CCITT },
191                                { NULL, 0 }};
192
193 static parsertab lmi[] = {{ "none", LMI_NONE },
194                           { "ansi", LMI_ANSI },
195                           { "ccitt", LMI_CCITT },
196                           { NULL, 0 }};
197
198
199 static void set_iface(void)
200 {
201         int orig_argc = argc;
202         te1_settings te1;
203
204         memset(&te1, 0, sizeof(te1));
205         req.ifr_settings.type = IF_IFACE_SYNC_SERIAL;
206
207         while (argc > 0) {
208                 if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
209                         if (!checktab(ifaces, &req.ifr_settings.type))
210                                 continue;
211
212                 if (!te1.clock_type)
213                         if (!checkkey("clock")) {
214                                 if (!checktab(clocks, &te1.clock_type))
215                                         continue;
216                                 error("Invalid clock type\n");
217                         }
218
219                 if (!te1.clock_rate &&
220                     (te1.clock_type == CLOCK_INT ||
221                      te1.clock_type == CLOCK_TXINT))
222                         if (!match("rate", &te1.clock_rate, 1, 0xFFFFFFFF))
223                                 continue;
224                 if (!te1.loopback) {
225                         if (!checkkey("loopback") ||
226                             !checkkey("lb")) {
227                                 te1.loopback = 1;
228                                 continue;
229                         }
230                 }
231                 /* slotmap goes here */
232
233                 if (orig_argc == argc)
234                         return; /* not an iface definition */
235                 error("Invalid parameter: %s\n", argv[0]);
236         }
237
238         if (!te1.clock_rate &&
239             (te1.clock_type == CLOCK_INT ||
240              te1.clock_type == CLOCK_TXINT))
241                 te1.clock_rate = 64000;
242
243         /* FIXME stupid hack, will remove it later */
244         req.ifr_settings.ifs_ifsu.te1 = &te1;
245         if (req.ifr_settings.type == IF_IFACE_E1 ||
246             req.ifr_settings.type == IF_IFACE_T1)
247                 req.ifr_settings.size = sizeof(te1_settings);
248         else
249                 req.ifr_settings.size = sizeof(sync_serial_settings);
250
251         if (ioctl(sock, SIOCWANDEV, &req))
252                 error("Unable to set interface information: %s\n",
253                       strerror(errno));
254
255         exit(0);
256 }
257
258
259
260 static void set_proto_fr(void)
261 {
262         unsigned int lmi_type = 0;
263         fr_proto fr;
264
265         memset(&fr, 0, sizeof(fr));
266
267         while (argc > 0) {
268                 if (!lmi_type)
269                         if (!checkkey("lmi")) {
270                                 if (!checktab(lmi, &lmi_type))
271                                         continue;
272                                 error("Invalid LMI type: %s\n",
273                                       argv[0]);
274                         }
275
276                 if (lmi_type && lmi_type != LMI_NONE) {
277                         if (!fr.dce)
278                                 if (!checkkey("dce")) {
279                                         fr.dce = 1;
280                                         continue;
281                                 }
282
283                         if (!fr.t391)
284                                 if (!match("t391", &fr.t391,
285                                            1, 1000))
286                                         continue;
287                         if (!fr.t392)
288                                 if (!match("t392", &fr.t392,
289                                            1, 1000))
290                                         continue;
291                         if (!fr.n391)
292                                 if (!match("n391", &fr.n391,
293                                            1, 1000))
294                                         continue;
295                         if (!fr.n392)
296                                 if (!match("n392", &fr.n392,
297                                            1, 1000))
298                                         continue;
299                         if (!fr.n393)
300                                 if (!match("n393", &fr.n393,
301                                            1, 1000))
302                                         continue;
303                 }
304                 error("Invalid parameter: %s\n", argv[0]);
305         }
306
307          /* polling verification timer*/
308         if (!fr.t391) fr.t391 = 10;
309         /* link integrity verification polling timer */
310         if (!fr.t392) fr.t392 = 15;
311         /* full status polling counter*/
312         if (!fr.n391) fr.n391 = 6;
313         /* error threshold */
314         if (!fr.n392) fr.n392 = 3;
315         /* monitored events count */
316         if (!fr.n393) fr.n393 = 4;
317
318         if (!lmi_type)
319                 fr.lmi = LMI_DEFAULT;
320         else
321                 fr.lmi = lmi_type;
322
323         req.ifr_settings.ifs_ifsu.fr = &fr;
324         req.ifr_settings.size = sizeof(fr);
325
326         if (ioctl(sock, SIOCWANDEV, &req))
327                 error("Unable to set FR protocol information: %s\n",
328                       strerror(errno));
329 }
330
331
332
333 static void set_proto_hdlc(int eth)
334 {
335         unsigned int enc = 0, par = 0;
336         raw_hdlc_proto raw;
337
338         memset(&raw, 0, sizeof(raw));
339
340         while (argc > 0) {
341                 if (!enc)
342                         if (!checktab(hdlc_enc, &enc))
343                                 continue;
344                 if (!par)
345                         if (!checktab(hdlc_par, &par))
346                                 continue;
347
348                 error("Invalid parameter: %s\n", argv[0]);
349         }
350
351         if (!enc)
352                 raw.encoding = ENCODING_DEFAULT;
353         else
354                 raw.encoding = enc;
355
356         if (!par)
357                 raw.parity = ENCODING_DEFAULT;
358         else
359                 raw.parity = par;
360
361         req.ifr_settings.ifs_ifsu.raw_hdlc = &raw;
362         req.ifr_settings.size = sizeof(raw);
363
364         if (ioctl(sock, SIOCWANDEV, &req))
365                 error("Unable to set HDLC%s protocol information: %s\n",
366                       eth ? "-ETH" : "", strerror(errno));
367 }
368
369
370
371 static void set_proto_cisco(void)
372 {
373         cisco_proto cisco;
374         memset(&cisco, 0, sizeof(cisco));
375
376         while (argc > 0) {
377                 if (!cisco.interval)
378                         if (!match("interval", &cisco.interval,
379                                    1, 100))
380                                 continue;
381                 if (!cisco.timeout)
382                         if (!match("timeout", &cisco.timeout,
383                                    1, 100))
384                                 continue;
385
386                 error("Invalid parameter: %s\n",
387                       argv[0]);
388         }
389
390         if (!cisco.interval)
391                 cisco.interval = 10;
392         if (!cisco.timeout)
393                 cisco.timeout = 25;
394
395         req.ifr_settings.ifs_ifsu.cisco = &cisco;
396         req.ifr_settings.size = sizeof(cisco);
397
398         if (ioctl(sock, SIOCWANDEV, &req))
399                 error("Unable to set Cisco HDLC protocol information: %s\n",
400                       strerror(errno));
401 }
402
403
404
405 static void set_proto(void)
406 {
407         if (checktab(protos, &req.ifr_settings.type))
408                 return;
409
410         switch(req.ifr_settings.type) {
411         case IF_PROTO_HDLC: set_proto_hdlc(0); break;
412 #ifdef IF_PROTO_HDLC_ETH
413         case IF_PROTO_HDLC_ETH: set_proto_hdlc(1); break;
414 #endif
415         case IF_PROTO_CISCO: set_proto_cisco(); break;
416         case IF_PROTO_FR: set_proto_fr(); break;
417
418         case IF_PROTO_PPP:
419         case IF_PROTO_X25:
420                 req.ifr_settings.ifs_ifsu.sync = NULL; /* FIXME */
421                 req.ifr_settings.size = 0;
422
423                 if (!ioctl(sock, SIOCWANDEV, &req))
424                         break;
425
426                 error("Unable to set %s protocol information: %s\n",
427                       req.ifr_settings.type == IF_PROTO_PPP
428                       ? "PPP" : "X.25", strerror(errno));
429
430         default: error("Unknown protocol %u\n", req.ifr_settings.type);
431         }
432
433         if (argc > 0)
434                 error("Unexpected parameter: %s\n", argv[0]);
435
436         close(sock);
437         exit(0);
438 }
439
440
441
442 static void set_pvc(void)
443 {
444         char *op = argv[0];
445         parsertab ops[] = {{ "create", IF_PROTO_FR_ADD_PVC },
446                            { "delete", IF_PROTO_FR_DEL_PVC },
447                            { NULL, 0 }};
448         fr_proto_pvc pvc;
449
450         memset(&pvc, 0, sizeof(pvc));
451
452         if (checktab(ops, &req.ifr_settings.type))
453                 return;
454
455 #ifdef IF_PROTO_FR_ETH_PVC
456         if (!match("ether", &pvc.dlci, 0, 1023)) {
457                 if (req.ifr_settings.type == IF_PROTO_FR_ADD_PVC)
458                         req.ifr_settings.type = IF_PROTO_FR_ADD_ETH_PVC;
459                 else
460                         req.ifr_settings.type = IF_PROTO_FR_DEL_ETH_PVC;
461
462         } else
463 #endif
464                 if (match(NULL, &pvc.dlci, 0, 1023))
465                         return;
466
467         if (argc != 0)
468                 return;
469
470         req.ifr_settings.ifs_ifsu.fr_pvc = &pvc;
471         req.ifr_settings.size = sizeof(pvc);
472
473         if (ioctl(sock, SIOCWANDEV, &req))
474                 error("Unable to %s PVC: %s\n", op, strerror(errno));
475         exit(0);
476 }
477
478
479
480 static void private(void)
481 {
482         if (argc < 1)
483                 return;
484
485         if (!strcmp(argv[0], "private")) {
486                 if (argc != 1)
487                         return;
488                 if (ioctl(sock, SIOCDEVPRIVATE, &req))
489                         error("SIOCDEVPRIVATE: %s\n", strerror(errno));
490                 exit(0);
491         }
492 }
493
494
495
496 static void show_port(void)
497 {
498         const char *s;
499         char buffer[128];
500         const te1_settings *te1 = (void*)buffer;
501         const raw_hdlc_proto *raw = (void*)buffer;
502         const cisco_proto *cisco = (void*)buffer;
503         const fr_proto *fr = (void*)buffer;
504 #ifdef IF_PROTO_FR_PVC
505         const fr_proto_pvc_info *pvc = (void*)buffer;
506 #endif
507         req.ifr_settings.ifs_ifsu.sync = (void*)buffer; /* FIXME */
508
509         printf("%s: ", req.ifr_name);
510
511         req.ifr_settings.size = sizeof(buffer);
512         req.ifr_settings.type = IF_GET_IFACE;
513
514         if (ioctl(sock, SIOCWANDEV, &req))
515                 if (errno != EINVAL) {
516                         printf("unable to get interface information: %s\n",
517                                strerror(errno));
518                         close(sock);
519                         exit(1);
520                 }
521         
522         /* Get and print physical interface settings */
523         if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
524                 s = "";         /* Unspecified serial interface */
525         else
526                 s = tabstr(req.ifr_settings.type, ifaces, NULL);
527
528         if (!s)
529                 printf("unknown interface 0x%x\n", req.ifr_settings.type);
530         else {
531                 if (*s)
532                         printf("interface %s ", s);
533
534                 printf("clock %s", tabstr(te1->clock_type, clocks,
535                                           "type unknown"));
536                 if (te1->clock_type == CLOCK_INT ||
537                     te1->clock_type == CLOCK_TXINT)
538                         printf(" rate %u", te1->clock_rate);
539
540                 if (te1->loopback)
541                         printf(" loopback");
542
543                 if (req.ifr_settings.type == IF_IFACE_E1 ||
544                     req.ifr_settings.type == IF_IFACE_T1) {
545                         unsigned int u;
546                         printf(" slotmap ");
547                         for (u = te1->slot_map; u != 0; u /= 2)
548                                 printf("%u", u % 2);
549                 }
550                 printf("\n");
551         }
552
553         /* Get and print protocol settings */
554         do {
555                 printf("\t");
556                 req.ifr_settings.size = sizeof(buffer);
557                 req.ifr_settings.type = IF_GET_PROTO;
558
559                 if (ioctl(sock, SIOCWANDEV, &req)) {
560                         if (errno == EINVAL)
561                                 printf("no protocol set\n");
562                         else
563                                 printf("unable to get protocol information: "
564                                        "%s\n", strerror(errno));
565                         break;
566                 }
567
568                 switch(req.ifr_settings.type) {
569                 case IF_PROTO_FR:
570                         printf("protocol fr lmi %s",
571                                tabstr(fr->lmi, lmi, "unknown"));
572                         if (fr->lmi == LMI_ANSI ||
573                             fr->lmi == LMI_CCITT)
574                                 printf("%s t391 %u t392 %u n391 %u n392 %u "
575                                        "n393 %u\n",
576                                        fr->dce ? " dce" : "",
577                                        fr->t391,
578                                        fr->t392,
579                                        fr->n391,
580                                        fr->n392,
581                                        fr->n393);
582                         else
583                                 putchar('\n');
584                         break;
585
586 #ifdef IF_PROTO_FR_PVC
587                 case IF_PROTO_FR_PVC:
588                         printf("Frame-Relay PVC: DLCI %u, master device %s\n",
589                                pvc->dlci, pvc->master);
590                         break;
591 #endif
592
593 #ifdef IF_PROTO_FR_ETH_PVC
594                 case IF_PROTO_FR_ETH_PVC:
595                         printf("Frame-Relay PVC (Ethernet emulation): DLCI %u,"
596                                " master device %s\n", pvc->dlci, pvc->master);
597                         break;
598 #endif
599
600                 case IF_PROTO_HDLC:
601                         printf("protocol hdlc %s %s\n",
602                                tabstr(raw->encoding, hdlc_enc, "unknown"),
603                                tabstr(raw->parity, hdlc_par, "unknown"));
604                         break;
605
606 #ifdef IF_PROTO_HDLC_ETH
607                 case IF_PROTO_HDLC_ETH:
608                         printf("protocol hdlc-eth %s %s\n",
609                                tabstr(raw->encoding, hdlc_enc, "unknown"),
610                                tabstr(raw->parity, hdlc_par, "unknown"));
611                         break;
612 #endif
613
614                 case IF_PROTO_CISCO:
615                         printf("protocol cisco interval %u timeout %u\n",
616                                cisco->interval,
617                                cisco->timeout);
618                         break;
619
620                 case IF_PROTO_PPP:
621                         printf("protocol ppp\n");
622                         break;
623
624                 case IF_PROTO_X25:
625                         printf("protocol x25\n");
626                         break;
627
628                 default:
629                         printf("unknown protocol %u\n", req.ifr_settings.type);
630                 }
631         }while(0);
632
633         close(sock);
634         exit(0);
635 }
636
637
638
639 static void usage(void)
640 {
641         fprintf(stderr, "sethdlc version 1.15\n"
642                 "Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>\n"
643                 "\n"
644                 "Usage: sethdlc INTERFACE [PHYSICAL] [clock CLOCK] [LOOPBACK] "
645                 "[slotmap SLOTMAP]\n"
646                 "       sethdlc INTERFACE [PROTOCOL]\n"
647                 "       sethdlc INTERFACE create | delete"
648 #ifdef IF_PROTO_FR_ETH_PVC
649                 " [ether]"
650 #endif
651                 " DLCI\n"
652                 "       sethdlc INTERFACE private...\n"
653                 "\n"
654                 "PHYSICAL := v24 | v35 | x21 | e1 | t1\n"
655                 "CLOCK := int [rate RATE] | ext | txint [rate RATE] | txfromrx\n"
656                 "LOOPBACK := loopback | lb\n"
657                 "\n"
658                 "PROTOCOL := hdlc [ENCODING] [PARITY] |\n"
659 #ifdef IF_PROTO_HDLC_ETH
660                 "            hdlc-eth [ENCODING] [PARITY] |\n"
661 #endif
662                 "            cisco [interval val] [timeout val] |\n"
663                 "            fr [lmi LMI] |\n"
664                 "            ppp |\n"
665                 "            x25\n"
666                 "\n"
667                 "ENCODING := nrz | nrzi | fm-mark | fm-space | manchester\n"
668                 "PARITY := no-parity | crc16 | crc16-pr0 | crc16-itu | crc16-itu-pr0 | crc32-itu\n"
669                 "LMI := none | ansi [LMI_SPEC] | ccitt [LMI_SPEC]\n"
670                 "LMI_SPEC := [dce] [t391 val] [t392 val] [n391 val] [n392 val] [n393 val]\n");
671         exit(0);
672 }
673
674
675
676 int main(int arg_c, char *arg_v[])
677 {
678         argc = arg_c;
679         argv = arg_v;
680
681         if (argc <= 1)
682                 usage();
683   
684         sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
685         if (sock < 0)
686                 error("Unable to create socket: %s\n", strerror(errno));
687   
688         dahdi_copy_string(req.ifr_name, argv[1], sizeof(req.ifr_name)); /* Device name */
689
690         if (argc == 2)
691                 show_port();
692
693         argc -= 2;
694         argv += 2;
695
696         set_iface();
697         set_proto();
698         set_pvc();
699         private();
700
701         close(sock);
702         usage();
703         exit(0);
704 }