/* * sethdlc.c * * Copyright (C) 1999 - 2002 Krzysztof Halasa * */ /* * See http://www.asterisk.org for more information about * the Asterisk project. Please do not directly contact * any of the maintainers of this project for assistance; * the project provides a web site, mailing lists and IRC * channels for your use. * * This program is free software, distributed under the terms of * the GNU General Public License Version 2 as published by the * Free Software Foundation. See the LICENSE file included with * this program for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dahdi_tools_version.h" #if GENERIC_HDLC_VERSION != 4 #error Generic HDLC layer version mismatch, please get correct sethdlc.c #endif #if !defined(IF_PROTO_HDLC_ETH) || !defined(IF_PROTO_FR_ETH_PVC) #warning "No kernel support for Ethernet over Frame Relay / HDLC, skipping it" #endif static struct ifreq req; /* for ioctl */ static int argc; static char **argv; int sock; static void error(const char *format, ...) __attribute__ ((noreturn, format(printf, 1, 2))); static void error(const char *format, ...) { va_list args; va_start(args, format); fprintf(stderr, "%s: ", req.ifr_name); vfprintf(stderr, format, args); va_end(args); exit(1); } typedef struct { const char *name; const unsigned int value; } parsertab; static int checkkey(const char* name) { if (argc < 1) return -1; /* no enough parameters */ if (strcmp(name, argv[0])) return -1; argc--; argv++; return 0; } static int checktab(parsertab *tab, unsigned int *value) { int i; if (argc < 1) return -1; /* no enough parameters */ for (i = 0; tab[i].name; i++) if (!strcmp(tab[i].name, argv[0])) { argc--; argv++; *value = tab[i].value; return 0; } return -1; /* Not found */ } static const char* tabstr(unsigned int value, parsertab *tab, const char* unknown) { int i; for (i = 0; tab[i].name; i++) if (tab[i].value == value) return tab[i].name; return unknown; /* Not found */ } static unsigned int match(const char* name, unsigned int *value, unsigned int minimum, unsigned int maximum) { char test; if (argc < 1) return -1; /* no enough parameters */ if (name) { if (strcmp(name, argv[0])) return -1; argc--; argv++; } if (argc < 1) error("Missing parameter\n"); if (sscanf(argv[0], "%u%c", value, &test) != 1) error("Invalid parameter: %s\n", argv[0]); if ((*value > maximum) || (*value < minimum)) error("Parameter out of range [%u - %u]: %u\n", minimum, maximum, *value); argc--; argv++; return 0; } static parsertab ifaces[] = {{ "v35", IF_IFACE_V35 }, { "v24", IF_IFACE_V24 }, { "x21", IF_IFACE_X21 }, { "e1", IF_IFACE_E1 }, { "t1", IF_IFACE_T1 }, { NULL, 0 }}; static parsertab clocks[] = {{ "int", CLOCK_INT }, { "ext", CLOCK_EXT }, { "txint", CLOCK_TXINT }, { "txfromrx", CLOCK_TXFROMRX }, { NULL, 0 }}; static parsertab protos[] = {{ "hdlc", IF_PROTO_HDLC}, { "cisco", IF_PROTO_CISCO}, { "fr", IF_PROTO_FR}, { "ppp", IF_PROTO_PPP}, { "x25", IF_PROTO_X25}, #ifdef IF_PROTO_HDLC_ETH { "hdlc-eth", IF_PROTO_HDLC_ETH}, #endif { NULL, 0 }}; static parsertab hdlc_enc[] = {{ "nrz", ENCODING_NRZ }, { "nrzi", ENCODING_NRZI }, { "fm-mark", ENCODING_FM_MARK }, { "fm-space", ENCODING_FM_SPACE }, { "manchester", ENCODING_MANCHESTER }, { NULL, 0 }}; static parsertab hdlc_par[] = {{ "no-parity", PARITY_NONE }, { "crc16", PARITY_CRC16_PR1 }, { "crc16-pr0", PARITY_CRC16_PR0 }, { "crc16-itu", PARITY_CRC16_PR1_CCITT }, { "crc16-itu-pr0", PARITY_CRC16_PR0_CCITT }, { "crc32-itu", PARITY_CRC32_PR1_CCITT }, { NULL, 0 }}; static parsertab lmi[] = {{ "none", LMI_NONE }, { "ansi", LMI_ANSI }, { "ccitt", LMI_CCITT }, { NULL, 0 }}; static void set_iface(void) { int orig_argc = argc; te1_settings te1; memset(&te1, 0, sizeof(te1)); req.ifr_settings.type = IF_IFACE_SYNC_SERIAL; while (argc > 0) { if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL) if (!checktab(ifaces, &req.ifr_settings.type)) continue; if (!te1.clock_type) if (!checkkey("clock")) { if (!checktab(clocks, &te1.clock_type)) continue; error("Invalid clock type\n"); } if (!te1.clock_rate && (te1.clock_type == CLOCK_INT || te1.clock_type == CLOCK_TXINT)) if (!match("rate", &te1.clock_rate, 1, 0xFFFFFFFF)) continue; if (!te1.loopback) { if (!checkkey("loopback") || !checkkey("lb")) { te1.loopback = 1; continue; } } /* slotmap goes here */ if (orig_argc == argc) return; /* not an iface definition */ error("Invalid parameter: %s\n", argv[0]); } if (!te1.clock_rate && (te1.clock_type == CLOCK_INT || te1.clock_type == CLOCK_TXINT)) te1.clock_rate = 64000; /* FIXME stupid hack, will remove it later */ req.ifr_settings.ifs_ifsu.te1 = &te1; if (req.ifr_settings.type == IF_IFACE_E1 || req.ifr_settings.type == IF_IFACE_T1) req.ifr_settings.size = sizeof(te1_settings); else req.ifr_settings.size = sizeof(sync_serial_settings); if (ioctl(sock, SIOCWANDEV, &req)) error("Unable to set interface information: %s\n", strerror(errno)); exit(0); } static void set_proto_fr(void) { unsigned int lmi_type = 0; fr_proto fr; memset(&fr, 0, sizeof(fr)); while (argc > 0) { if (!lmi_type) if (!checkkey("lmi")) { if (!checktab(lmi, &lmi_type)) continue; error("Invalid LMI type: %s\n", argv[0]); } if (lmi_type && lmi_type != LMI_NONE) { if (!fr.dce) if (!checkkey("dce")) { fr.dce = 1; continue; } if (!fr.t391) if (!match("t391", &fr.t391, 1, 1000)) continue; if (!fr.t392) if (!match("t392", &fr.t392, 1, 1000)) continue; if (!fr.n391) if (!match("n391", &fr.n391, 1, 1000)) continue; if (!fr.n392) if (!match("n392", &fr.n392, 1, 1000)) continue; if (!fr.n393) if (!match("n393", &fr.n393, 1, 1000)) continue; } error("Invalid parameter: %s\n", argv[0]); } /* polling verification timer*/ if (!fr.t391) fr.t391 = 10; /* link integrity verification polling timer */ if (!fr.t392) fr.t392 = 15; /* full status polling counter*/ if (!fr.n391) fr.n391 = 6; /* error threshold */ if (!fr.n392) fr.n392 = 3; /* monitored events count */ if (!fr.n393) fr.n393 = 4; if (!lmi_type) fr.lmi = LMI_DEFAULT; else fr.lmi = lmi_type; req.ifr_settings.ifs_ifsu.fr = &fr; req.ifr_settings.size = sizeof(fr); if (ioctl(sock, SIOCWANDEV, &req)) error("Unable to set FR protocol information: %s\n", strerror(errno)); } static void set_proto_hdlc(int eth) { unsigned int enc = 0, par = 0; raw_hdlc_proto raw; memset(&raw, 0, sizeof(raw)); while (argc > 0) { if (!enc) if (!checktab(hdlc_enc, &enc)) continue; if (!par) if (!checktab(hdlc_par, &par)) continue; error("Invalid parameter: %s\n", argv[0]); } if (!enc) raw.encoding = ENCODING_DEFAULT; else raw.encoding = enc; if (!par) raw.parity = ENCODING_DEFAULT; else raw.parity = par; req.ifr_settings.ifs_ifsu.raw_hdlc = &raw; req.ifr_settings.size = sizeof(raw); if (ioctl(sock, SIOCWANDEV, &req)) error("Unable to set HDLC%s protocol information: %s\n", eth ? "-ETH" : "", strerror(errno)); } static void set_proto_cisco(void) { cisco_proto cisco; memset(&cisco, 0, sizeof(cisco)); while (argc > 0) { if (!cisco.interval) if (!match("interval", &cisco.interval, 1, 100)) continue; if (!cisco.timeout) if (!match("timeout", &cisco.timeout, 1, 100)) continue; error("Invalid parameter: %s\n", argv[0]); } if (!cisco.interval) cisco.interval = 10; if (!cisco.timeout) cisco.timeout = 25; req.ifr_settings.ifs_ifsu.cisco = &cisco; req.ifr_settings.size = sizeof(cisco); if (ioctl(sock, SIOCWANDEV, &req)) error("Unable to set Cisco HDLC protocol information: %s\n", strerror(errno)); } static void set_proto(void) { if (checktab(protos, &req.ifr_settings.type)) return; switch(req.ifr_settings.type) { case IF_PROTO_HDLC: set_proto_hdlc(0); break; #ifdef IF_PROTO_HDLC_ETH case IF_PROTO_HDLC_ETH: set_proto_hdlc(1); break; #endif case IF_PROTO_CISCO: set_proto_cisco(); break; case IF_PROTO_FR: set_proto_fr(); break; case IF_PROTO_PPP: case IF_PROTO_X25: req.ifr_settings.ifs_ifsu.sync = NULL; /* FIXME */ req.ifr_settings.size = 0; if (!ioctl(sock, SIOCWANDEV, &req)) break; error("Unable to set %s protocol information: %s\n", req.ifr_settings.type == IF_PROTO_PPP ? "PPP" : "X.25", strerror(errno)); default: error("Unknown protocol %u\n", req.ifr_settings.type); } if (argc > 0) error("Unexpected parameter: %s\n", argv[0]); close(sock); exit(0); } static void set_pvc(void) { char *op = argv[0]; parsertab ops[] = {{ "create", IF_PROTO_FR_ADD_PVC }, { "delete", IF_PROTO_FR_DEL_PVC }, { NULL, 0 }}; fr_proto_pvc pvc; memset(&pvc, 0, sizeof(pvc)); if (checktab(ops, &req.ifr_settings.type)) return; #ifdef IF_PROTO_FR_ETH_PVC if (!match("ether", &pvc.dlci, 0, 1023)) { if (req.ifr_settings.type == IF_PROTO_FR_ADD_PVC) req.ifr_settings.type = IF_PROTO_FR_ADD_ETH_PVC; else req.ifr_settings.type = IF_PROTO_FR_DEL_ETH_PVC; } else #endif if (match(NULL, &pvc.dlci, 0, 1023)) return; if (argc != 0) return; req.ifr_settings.ifs_ifsu.fr_pvc = &pvc; req.ifr_settings.size = sizeof(pvc); if (ioctl(sock, SIOCWANDEV, &req)) error("Unable to %s PVC: %s\n", op, strerror(errno)); exit(0); } static void private(void) { if (argc < 1) return; if (!strcmp(argv[0], "private")) { if (argc != 1) return; if (ioctl(sock, SIOCDEVPRIVATE, &req)) error("SIOCDEVPRIVATE: %s\n", strerror(errno)); exit(0); } } static void show_port(void) { const char *s; char buffer[128]; const te1_settings *te1 = (void*)buffer; const raw_hdlc_proto *raw = (void*)buffer; const cisco_proto *cisco = (void*)buffer; const fr_proto *fr = (void*)buffer; #ifdef IF_PROTO_FR_PVC const fr_proto_pvc_info *pvc = (void*)buffer; #endif req.ifr_settings.ifs_ifsu.sync = (void*)buffer; /* FIXME */ printf("%s: ", req.ifr_name); req.ifr_settings.size = sizeof(buffer); req.ifr_settings.type = IF_GET_IFACE; if (ioctl(sock, SIOCWANDEV, &req)) if (errno != EINVAL) { printf("unable to get interface information: %s\n", strerror(errno)); close(sock); exit(1); } /* Get and print physical interface settings */ if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL) s = ""; /* Unspecified serial interface */ else s = tabstr(req.ifr_settings.type, ifaces, NULL); if (!s) printf("unknown interface 0x%x\n", req.ifr_settings.type); else { if (*s) printf("interface %s ", s); printf("clock %s", tabstr(te1->clock_type, clocks, "type unknown")); if (te1->clock_type == CLOCK_INT || te1->clock_type == CLOCK_TXINT) printf(" rate %u", te1->clock_rate); if (te1->loopback) printf(" loopback"); if (req.ifr_settings.type == IF_IFACE_E1 || req.ifr_settings.type == IF_IFACE_T1) { unsigned int u; printf(" slotmap "); for (u = te1->slot_map; u != 0; u /= 2) printf("%u", u % 2); } printf("\n"); } /* Get and print protocol settings */ do { printf("\t"); req.ifr_settings.size = sizeof(buffer); req.ifr_settings.type = IF_GET_PROTO; if (ioctl(sock, SIOCWANDEV, &req)) { if (errno == EINVAL) printf("no protocol set\n"); else printf("unable to get protocol information: " "%s\n", strerror(errno)); break; } switch(req.ifr_settings.type) { case IF_PROTO_FR: printf("protocol fr lmi %s", tabstr(fr->lmi, lmi, "unknown")); if (fr->lmi == LMI_ANSI || fr->lmi == LMI_CCITT) printf("%s t391 %u t392 %u n391 %u n392 %u " "n393 %u\n", fr->dce ? " dce" : "", fr->t391, fr->t392, fr->n391, fr->n392, fr->n393); else putchar('\n'); break; #ifdef IF_PROTO_FR_PVC case IF_PROTO_FR_PVC: printf("Frame-Relay PVC: DLCI %u, master device %s\n", pvc->dlci, pvc->master); break; #endif #ifdef IF_PROTO_FR_ETH_PVC case IF_PROTO_FR_ETH_PVC: printf("Frame-Relay PVC (Ethernet emulation): DLCI %u," " master device %s\n", pvc->dlci, pvc->master); break; #endif case IF_PROTO_HDLC: printf("protocol hdlc %s %s\n", tabstr(raw->encoding, hdlc_enc, "unknown"), tabstr(raw->parity, hdlc_par, "unknown")); break; #ifdef IF_PROTO_HDLC_ETH case IF_PROTO_HDLC_ETH: printf("protocol hdlc-eth %s %s\n", tabstr(raw->encoding, hdlc_enc, "unknown"), tabstr(raw->parity, hdlc_par, "unknown")); break; #endif case IF_PROTO_CISCO: printf("protocol cisco interval %u timeout %u\n", cisco->interval, cisco->timeout); break; case IF_PROTO_PPP: printf("protocol ppp\n"); break; case IF_PROTO_X25: printf("protocol x25\n"); break; default: printf("unknown protocol %u\n", req.ifr_settings.type); } }while(0); close(sock); exit(0); } static void usage(void) { fprintf(stderr, "sethdlc version 1.15\n" "Copyright (C) 2000 - 2003 Krzysztof Halasa \n" "\n" "Usage: sethdlc INTERFACE [PHYSICAL] [clock CLOCK] [LOOPBACK] " "[slotmap SLOTMAP]\n" " sethdlc INTERFACE [PROTOCOL]\n" " sethdlc INTERFACE create | delete" #ifdef IF_PROTO_FR_ETH_PVC " [ether]" #endif " DLCI\n" " sethdlc INTERFACE private...\n" "\n" "PHYSICAL := v24 | v35 | x21 | e1 | t1\n" "CLOCK := int [rate RATE] | ext | txint [rate RATE] | txfromrx\n" "LOOPBACK := loopback | lb\n" "\n" "PROTOCOL := hdlc [ENCODING] [PARITY] |\n" #ifdef IF_PROTO_HDLC_ETH " hdlc-eth [ENCODING] [PARITY] |\n" #endif " cisco [interval val] [timeout val] |\n" " fr [lmi LMI] |\n" " ppp |\n" " x25\n" "\n" "ENCODING := nrz | nrzi | fm-mark | fm-space | manchester\n" "PARITY := no-parity | crc16 | crc16-pr0 | crc16-itu | crc16-itu-pr0 | crc32-itu\n" "LMI := none | ansi [LMI_SPEC] | ccitt [LMI_SPEC]\n" "LMI_SPEC := [dce] [t391 val] [t392 val] [n391 val] [n392 val] [n393 val]\n"); exit(0); } int main(int arg_c, char *arg_v[]) { argc = arg_c; argv = arg_v; if (argc <= 1) usage(); sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock < 0) error("Unable to create socket: %s\n", strerror(errno)); dahdi_copy_string(req.ifr_name, argv[1], sizeof(req.ifr_name)); /* Device name */ if (argc == 2) show_port(); argc -= 2; argv += 2; set_iface(); set_proto(); set_pvc(); private(); close(sock); usage(); exit(0); }