From 018e3d3447492c7511aca29a6e54226274d7e930 Mon Sep 17 00:00:00 2001 From: markster Date: Fri, 21 Nov 2003 09:30:54 +0000 Subject: Fix for new kernels, add support for 2.4.22 and new sethdlc git-svn-id: http://svn.digium.com/svn/zaptel/trunk@281 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- sethdlc-new.c | 692 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 692 insertions(+) create mode 100755 sethdlc-new.c (limited to 'sethdlc-new.c') diff --git a/sethdlc-new.c b/sethdlc-new.c new file mode 100755 index 0000000..4a4a7bb --- /dev/null +++ b/sethdlc-new.c @@ -0,0 +1,692 @@ +/* + * sethdlc.c + * + * Copyright (C) 1999 - 2002 Krzysztof Halasa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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)); + +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)); + + strcpy(req.ifr_name, argv[1]); /* Device name */ + + if (argc == 2) + show_port(); + + argc -= 2; + argv += 2; + + set_iface(); + set_proto(); + set_pvc(); + private(); + + close(sock); + usage(); + exit(0); +} -- cgit v1.2.3