diff --git a/isdnctrl/ctrltimru.c b/isdnctrl/ctrltimru.c new file mode 100644 index 00000000..6c279069 --- /dev/null +++ b/isdnctrl/ctrltimru.c @@ -0,0 +1,1150 @@ +/* + * ISDN TimRu-Control + * + * Copyright 1998 by Christian A. Lademann (cal@zls.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "isdnctrl.h" +#include "ctrlconf.h" + +#ifdef HAVE_TIMRU +/* TimRu - Erweiterung */ +/* +06.06.97:cal:turnaround_rule(): bei nicht-umkehrbarer Regel mit 0 zurueckkehren +10.06.97:cal:hdl_timeout_rule(): memset(&timru, 0, ...) +12.06.97:cal:commandline-parsing kompatibel zur Hauptschleife, damit mehrere + Kommandos hintereinander angegeben werden koennen; id und cmdptr werden + an die betreffenden Funktionen uebergeben. +26.06.97:cal:neben "*" auch "any" als Wildcard-Angabe und neben "!" auch "not" + als Negations-Angabe zulassen; bei "bringup" jetzt auch hup-timeout als + initial-timeout einlesen. +09.06.98:cal:Mini-Glibc-Patch von Andreas Steffan eing. +*/ + +char *timru_protfam_kt [] = { "ip", "ipx", "ppp", "*", "any", "\0" }; +int timru_protfam_nt [] = { ISDN_TIMRU_PROTFAM_IP, + ISDN_TIMRU_PROTFAM_IPX, + ISDN_TIMRU_PROTFAM_PPP, + ISDN_TIMRU_PROTFAM_WILDCARD, + ISDN_TIMRU_PROTFAM_WILDCARD, + -1 }; + +char *timru_ip_kt [] = { "icmp", "tcp", "udp", "*", "any", "\0" }; +int timru_ip_nt [] = { ISDN_TIMRU_IP_ICMP, + ISDN_TIMRU_IP_TCP, + ISDN_TIMRU_IP_UDP, + ISDN_TIMRU_IP_WILDCARD, + ISDN_TIMRU_IP_WILDCARD, + -1 }; + +char *timru_ppp_kt [] = { "ipcp", "ipxcp", "ccp", "lcp", "pap", "lqr", + "chap", "*", "any", "\0" }; +int timru_ppp_nt [] = { ISDN_TIMRU_PPP_IPCP, + ISDN_TIMRU_PPP_IPXCP, + ISDN_TIMRU_PPP_CCP, + ISDN_TIMRU_PPP_LCP, + ISDN_TIMRU_PPP_PAP, + ISDN_TIMRU_PPP_LQR, + ISDN_TIMRU_PPP_CHAP, + ISDN_TIMRU_PPP_WILDCARD, + ISDN_TIMRU_PPP_WILDCARD, + -1 }; + + +char *timru_ruletype_kt [] = { "bringup", "keepup_in", "keepup_out", "\0" }; +int timru_ruletype_nt [] = { ISDN_TIMRU_BRINGUP, + ISDN_TIMRU_KEEPUP_IN, + ISDN_TIMRU_KEEPUP_OUT, + -1 }; + +#define MIN_IP_PORT 0 +#define MAX_IP_PORT 0xffff + +#define MIN_ICMP_TYPE 0 +#define MAX_ICMP_TYPE 0xff + +int flush_timeout_rules(int, char *, int, int, int, char *[]); +int output_rule_header(int, int); +int output_timeout_rules(int, char *, int, int, char *[]); +int output_timeout_rule(isdn_ioctl_timeout_rule *); +int read_icmp_type(char *, __u8 *, __u8 *); +int read_ip_addr(char *, struct in_addr *, struct in_addr *); +int read_ip_port(char *, char *, __u16 *, __u16 *); +int set_default_timeout(int, char *, int, int, char *[]); +int turnaround_rule(isdn_ioctl_timeout_rule *); +int write_icmp_type(char *, __u8, __u8); +int write_ip_addr(char *, struct in_addr, struct in_addr); +int write_ip_port(char *, __u16, __u16); + + +int +read_ip_addr(char *s, struct in_addr *a, struct in_addr *m) { + char host [256], + mask [16]; + int a1, a2, a3, a4; + struct hostent *he; + struct netent *ne; + + + if(!strcmp(s, "*") || !strcmp(s, "any")) { + a->s_addr = (__u32)htonl(0); + m->s_addr = (__u32)htonl(0); + + return(0); + } + + if(strchr(s, '/')) { + strcpy(host, strtok(s, "/")); + strcpy(mask, strtok(NULL, "/")); + } else { + strcpy(host, s); + strcpy(mask, "0"); + } + + if(! strcmp(host, "0")) + a->s_addr = (__u32)htonl(0x00000000); + else if(sscanf(host, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) == 4) + a->s_addr = (__u32)htonl((((a1&0xff)<<24)|((a2&0xff)<<16)|((a3&0xff)<<8)|(a4&0xff))); + else if((ne = getnetbyname(s)) && ne->n_addrtype == AF_INET) + a->s_addr = (__u32)htonl(ne->n_net); + else if((he = gethostbyname(s)) && he->h_addrtype == AF_INET) + memcpy(a, he->h_addr_list [0], sizeof(struct in_addr)); + else + return(-1); + + if(sscanf(mask, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) == 4) + m->s_addr = (__u32)htonl((((a1&0xff)<<24)|((a2&0xff)<<16)|((a3&0xff)<<8)|(a4&0xff))); + else if(sscanf(mask, "%d", &a1) == 1) { + int i; + + m->s_addr = (__u32)htonl(0); + + for(i = a1; i > 0; i--) + m->s_addr |= 1 << (32 - i); + + m->s_addr = (__u32)htonl(m->s_addr); + } else + return(-1); + + return(0); +} + + +int +write_ip_addr(char *s, struct in_addr a, struct in_addr m) { + int a1, a2, a3, a4, m1, m2, m3, m4, + i, mbits, in_mask; + + + if(a.s_addr == (__u32)ntohl(0)) + sprintf(s, "0"); + else { + a1 = (ntohl(a.s_addr) >> 24) & 0xff; + a2 = (ntohl(a.s_addr) >> 16) & 0xff; + a3 = (ntohl(a.s_addr) >> 8) & 0xff; + a4 = ntohl(a.s_addr) & 0xff; + + sprintf(s, "%d.%d.%d.%d", a1, a2, a3, a4); + } + + mbits = 0; + in_mask = 1; + for(i = 31; i >= 0; i--) { + if((((1 << i) & ntohl(m.s_addr)) != 0) == (in_mask != 0)) { + if(in_mask) + mbits++; + } else { + if(in_mask) + in_mask = 0; + else + break; + } + } + + if(i < 0) + sprintf(s, "%s/%d", s, mbits); + else { + m1 = (ntohl(m.s_addr) >> 24) & 0xff; + m2 = (ntohl(m.s_addr) >> 16) & 0xff; + m3 = (ntohl(m.s_addr) >> 8) & 0xff; + m4 = ntohl(m.s_addr) & 0xff; + + sprintf(s, "%s/%d.%d.%d.%d", s, m1, m2, m3, m4); + } + + return(0); +} + + +int +read_ip_port(char *s, char *proto, __u16 *from, __u16 *to) { + int f, t, n; + char *q; + struct servent *service; + + + if(!strcmp(s, "*") || !strcmp(s, "any")) { + f = MIN_IP_PORT; + t = MAX_IP_PORT; + } else { + if(proto && (service = getservbyname(s, proto))) /* specific port by name */ + f = t = ntohs(service->s_port); + else + if((q = strchr(s, '-'))) { /* port range */ + if(q - s == 0) /* -to: empty from */ + f = MIN_IP_PORT; + else { + if(sscanf(s, "%i%n", &f, &n) <= 0 || n != q - s) + return(-1); + } + + if(! *(q + 1)) /* from-: empty to */ + t = MAX_IP_PORT; + else { + if(sscanf(q + 1, "%i%n", &t, &n) <= 0 || n != strlen(q + 1)) + return(-1); + } + } else { /* specific port */ + if(sscanf(s, "%i%n", &f, &n) > 0 || n == strlen(s)) + t = f; + else + return(-1); + } + } + + if(f < MIN_IP_PORT || f > MAX_IP_PORT || t < MIN_IP_PORT || t > MAX_IP_PORT) + return(-1); + + *from = (__u16)htons(f); + *to = (__u16)htons(t); + + return(0); +} + + +int +write_ip_port(char *s, __u16 from, __u16 to) { + if(ntohs(from) == MIN_IP_PORT && ntohs(to) == MAX_IP_PORT) + sprintf(s, "*"); + else if(from == to) + sprintf(s, "%d", ntohs(from)); + else + sprintf(s, "%d-%d", ntohs(from), ntohs(to)); + + return(0); +} + + +int +read_icmp_type(char *s, __u8 *from, __u8 *to) { + int f, t, n; + char *q; + + + if(!strcmp(s, "*") || !strcmp(s, "any")) { + f = MIN_ICMP_TYPE; + t = MAX_ICMP_TYPE; + } else { + if((q = strchr(s, '-'))) { /* port range */ + if(q - s == 0) /* -to: empty from */ + f = MIN_ICMP_TYPE; + else { + if(sscanf(s, "%i%n", &f, &n) <= 0 || n != q - s) + return(-1); + } + + if(! *(q + 1)) /* from-: empty to */ + t = MAX_ICMP_TYPE; + else { + if(sscanf(q + 1, "%i%n", &t, &n) <= 0 || n != strlen(q + 1)) + return(-1); + } + } else { /* specific port */ + if(sscanf(s, "%i%n", &f, &n) > 0 || n == strlen(s)) + t = f; + else + return(-1); + } + } + + if(f < MIN_ICMP_TYPE || f > MAX_ICMP_TYPE || t < MIN_ICMP_TYPE || t > MAX_ICMP_TYPE) + return(-1); + + *from = (__u8)f; + *to = (__u8)t; + + return(0); +} + + +int +write_icmp_type(char *s, __u8 from, __u8 to) { + if(from == MIN_ICMP_TYPE && to == MAX_ICMP_TYPE) + sprintf(s, "*"); + else if(from == to) + sprintf(s, "%d", from); + else + sprintf(s, "%d-%d", from, to); + + return(0); +} + + +#define SHIFT_ARGS(msg) { \ + if(++argp >= argc) { \ + fprintf(stderr, "rule-parser: out of arguments"); \ + if(strlen(msg)) \ + fprintf(stderr, " looking for %s", (msg)); \ + fprintf(stderr, "\n"); \ + return(-1); \ + } else { \ + ++args_used; \ + } \ +} + + +#define UNSHIFT_ARGS(i) { \ + if(argp > (i)) { \ + argp -= (i); \ + args_used -= (i); \ + } \ +} + + +#define PARSER_ERROR(msg) { \ + fprintf(stderr, "rule-parser: parse-error"); \ + if(strlen(msg)) \ + fprintf(stderr, ": %s", (msg)); \ + fprintf(stderr, "\n"); \ + return(-1); \ +} + +#define max(a, b) ((a) > (b) ? (a) : (b)) + + +int +hdl_timeout_rule(int fd, char *id, int cmd, int argc, char *argv []) { + isdn_ioctl_timeout_rule timru; + int ioctl_fcn, + n_protfam, n_prot, + ioret, n, + other_type = -1, + argp = 0, + args_used = 0; + char k_protfam [16], k_prot [16]; + + + memset(&timru, 0, sizeof(isdn_ioctl_timeout_rule)); + + /* cmd */ + switch(cmd) { + case ADDRULE: + ioctl_fcn = IIOCNETARU; + timru.where = 1; + break; + + case INSRULE: + ioctl_fcn = IIOCNETARU; + timru.where = 0; + break; + + case DELRULE: + ioctl_fcn = IIOCNETDRU; + break; + + case DEFAULT: + return(args_used + set_default_timeout(fd, id, argp, argc, argv)); + break; + + case SHOWRULES: + return(args_used + output_timeout_rules(fd, id, argp, argc, argv)); + break; + + case FLUSHRULES: + return(args_used + flush_timeout_rules(fd, id, 0, argp, argc, argv)); + break; + + case FLUSHALLRULES: + return(args_used + flush_timeout_rules(fd, id, 1, argp, argc, argv)); + break; + + default: + PARSER_ERROR("unknown command"); + } + + /* interface */ + strncpy(timru.name, id, sizeof(timru.name) - 1); + + /* rule-type */ + /* SHIFT_ARGS("rule-type"); */ + if(! strcmp(argv [argp], "bringup")) { + timru.rule.type = ISDN_TIMRU_BRINGUP; + } else if(! strcmp(argv [argp], "keepup")) { + /* keepup-type */ + SHIFT_ARGS("keepup-type"); + if(! strcmp(argv [argp], "in")) + timru.rule.type = ISDN_TIMRU_KEEPUP_IN; + else if(! strcmp(argv [argp], "out")) + timru.rule.type = ISDN_TIMRU_KEEPUP_OUT; + else if(! strcmp(argv [argp], "both")) { + timru.rule.type = ISDN_TIMRU_KEEPUP_IN; + other_type = ISDN_TIMRU_KEEPUP_OUT; + } else + PARSER_ERROR("wrong keepup-type"); + } else + PARSER_ERROR("wrong rule-type"); + + /* hup-timeout */ + SHIFT_ARGS("hup-timeout"); + if(sscanf(argv [argp], "%i%n", &timru.rule.timeout, &n) <= 0 || n != strlen(argv [argp])) + PARSER_ERROR("wrong timeout"); + + /* neg */ + SHIFT_ARGS("rule-parameter"); + if(! strcmp(argv [argp], "!") || ! strcmp(argv [argp], "not")) { + timru.rule.neg = 1; + SHIFT_ARGS("rule-parameter"); + } else + timru.rule.neg = 0; + + /* rule */ + if(strchr(argv [argp], '/')) { + if(sscanf(argv [argp], "%[a-z0-9*]/%[a-z0-9*]", k_protfam, k_prot) != 2) + PARSER_ERROR("wrong protocol specification"); + } else { + if(! strcmp(argv [argp], "any")) { + strcpy(k_protfam, "any"); + strcpy(k_prot, "any"); + } else + PARSER_ERROR("wrong protocol specification"); + } + + if((n_protfam = key2num(k_protfam, timru_protfam_kt, timru_protfam_nt)) < 0) + PARSER_ERROR("wrong protocol-family"); + + timru.rule.protfam = n_protfam; + + switch(timru.rule.protfam) { + case ISDN_TIMRU_PROTFAM_IP: + if((n_prot = key2num(k_prot, timru_ip_kt, timru_ip_nt)) < 0) + PARSER_ERROR("wrong ip-protocol"); + + timru.rule.rule.ip.protocol = n_prot; + + /* src-addr */ + SHIFT_ARGS("source-address"); + if(read_ip_addr(argv [argp], &timru.rule.rule.ip.saddr, &timru.rule.rule.ip.smask) < 0) + PARSER_ERROR("wrong source-address"); + + switch(timru.rule.rule.ip.protocol) { + case ISDN_TIMRU_IP_ICMP: + /* port-range */ + SHIFT_ARGS("icmp-type(s)"); + if(read_icmp_type(argv [argp], &timru.rule.rule.ip.pt.type.from, &timru.rule.rule.ip.pt.type.to) < 0) + PARSER_ERROR("wrong icmp-type(s)"); + break; + + case ISDN_TIMRU_IP_TCP: + case ISDN_TIMRU_IP_UDP: + /* service-range */ + SHIFT_ARGS("source port-number(s)"); + if(read_ip_port(argv [argp], k_prot, &timru.rule.rule.ip.pt.port.s_from, &timru.rule.rule.ip.pt.port.s_to) < 0) + PARSER_ERROR("wrong source port-number(s)"); + break; + } + + /* dst-addr */ + SHIFT_ARGS("destination-address"); + if(read_ip_addr(argv [argp], &timru.rule.rule.ip.daddr, &timru.rule.rule.ip.dmask) < 0) + PARSER_ERROR("wrong destination-address"); + + switch(timru.rule.rule.ip.protocol) { + case ISDN_TIMRU_IP_TCP: + case ISDN_TIMRU_IP_UDP: + /* service-range */ + SHIFT_ARGS("destination port-number(s)"); + if(read_ip_port(argv [argp], k_prot, &timru.rule.rule.ip.pt.port.d_from, &timru.rule.rule.ip.pt.port.d_to) < 0) + PARSER_ERROR("wrong destination port-number(s)"); + break; + } + + break; + + case ISDN_TIMRU_PROTFAM_PPP: + if((n_prot = key2num(k_prot, timru_ppp_kt, timru_ppp_nt)) < 0) + PARSER_ERROR("wrong ppp-protocol"); + + timru.rule.rule.ppp.protocol = n_prot; + break; + } + + if((ioret = ioctl(fd, ioctl_fcn, &timru)) < 0) { + perror("ioctl failed."); + return(ioret); + } + + if(other_type >= 0) { + if(turnaround_rule(&timru) < 0) + return(-1); + + timru.rule.type = other_type; + + if((ioret = ioctl(fd, ioctl_fcn, &timru)) < 0) { + perror("ioctl failed."); + return(ioret); + } + } + + return(args_used); +} + + +int +turnaround_rule(isdn_ioctl_timeout_rule *timru) { + isdn_ioctl_timeout_rule timbuf; + + memcpy((char *)&timbuf, (char *)timru, sizeof(isdn_ioctl_timeout_rule)); + switch(timru->rule.protfam) { + case ISDN_TIMRU_PROTFAM_IP: + memcpy((char *)&timru->rule.rule.ip.saddr, (char *)&timbuf.rule.rule.ip.daddr, sizeof(timbuf.rule.rule.ip.daddr)); + memcpy((char *)&timru->rule.rule.ip.smask, (char *)&timbuf.rule.rule.ip.dmask, sizeof(timbuf.rule.rule.ip.dmask)); + memcpy((char *)&timru->rule.rule.ip.daddr, (char *)&timbuf.rule.rule.ip.saddr, sizeof(timbuf.rule.rule.ip.saddr)); + memcpy((char *)&timru->rule.rule.ip.dmask, (char *)&timbuf.rule.rule.ip.smask, sizeof(timbuf.rule.rule.ip.smask)); + + switch(timru->rule.rule.ip.protocol) { + case ISDN_TIMRU_IP_TCP: + case ISDN_TIMRU_IP_UDP: + timru->rule.rule.ip.pt.port.s_from = timbuf.rule.rule.ip.pt.port.d_from; + timru->rule.rule.ip.pt.port.s_to = timbuf.rule.rule.ip.pt.port.d_to; + timru->rule.rule.ip.pt.port.d_from = timbuf.rule.rule.ip.pt.port.s_from; + timru->rule.rule.ip.pt.port.d_to = timbuf.rule.rule.ip.pt.port.s_to; + break; + } + break; + } + return(0); +} + + +int +output_timeout_rules(int fd, char *id, int firstarg, int argc, char *argv []) { + isdn_ioctl_timeout_rule timru; + int i, j, k, + header_printed; + + + /* interface */ + strncpy(timru.name, id, sizeof(timru.name) - 1); + + printf("Timeout rules for interface %s:\n", timru.name); + + for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++) { + timru.where = -1; + timru.type = i; + + if(ioctl(fd, IIOCNETGRU, &timru) == 0) { + switch(i) { + case ISDN_TIMRU_BRINGUP: + printf("Default bringup policy: "); + if(timru.defval == 0) + printf("false\n"); + else + printf("true, initial timeout is %d sec.\n", timru.defval); + break; + + case ISDN_TIMRU_KEEPUP_IN: + printf("Default huptimeout for incoming packets: %d sec.\n", timru.defval); + break; + + case ISDN_TIMRU_KEEPUP_OUT: + printf("Default huptimeout for outgoing packets: %d sec.\n", timru.defval); + printf("\nCurrent huptimeout: %d sec.\n", timru.index); + printf("Time until hangup: %d sec.\n", max(0, timru.index - timru.protfam)); + break; + } + } + } + + for(i = 0; i < ISDN_TIMRU_NUM_CHECK; i++) { + header_printed = 0; + for(j = 0; j < ISDN_TIMRU_NUM_PROTFAM; j++) { + k = 0; + header_printed = 0; + while(1) { + timru.type = i; + timru.protfam = j; + timru.index = k; + timru.where = 0; + + if(ioctl(fd, IIOCNETGRU, &timru) == 0) { + if(! header_printed) { + output_rule_header(i, j); + header_printed = 1; + } + output_timeout_rule(&timru); + } else + break; + + k++; + } + } + } + + return(0); +} + + +int +output_timeout_rule(isdn_ioctl_timeout_rule *timru) { + char str [80]; + + /* rule-nr */ + printf("%d-%d-%-d ", timru->type, timru->protfam, timru->index); + + /* rule-type */ + printf("%s ", num2key(timru->rule.type, timru_ruletype_kt, timru_ruletype_nt)); + + /* timeout */ + if(timru->rule.type != ISDN_TIMRU_BRINGUP) + printf("%d ", timru->rule.timeout); + + /* neg */ + printf("%s", (timru->rule.neg ? "!" : "")); + + /* protocol */ + printf("%s", num2key(timru->rule.protfam, timru_protfam_kt, timru_protfam_nt)); + switch(timru->rule.protfam) { + case ISDN_TIMRU_PROTFAM_IP: + /* protocol */ + printf("/%s ", num2key(timru->rule.rule.ip.protocol, timru_ip_kt, timru_ip_nt)); + + /* src addr */ + write_ip_addr(str, timru->rule.rule.ip.saddr, timru->rule.rule.ip.smask); + printf("%s ", str); + + /* src port/type */ + strcpy(str, "\0"); + switch(timru->rule.rule.ip.protocol) { + case ISDN_TIMRU_IP_ICMP: + write_icmp_type(str, timru->rule.rule.ip.pt.type.from, timru->rule.rule.ip.pt.type.to); + printf("%s ", str); + break; + + case ISDN_TIMRU_IP_TCP: + case ISDN_TIMRU_IP_UDP: + write_ip_port(str, timru->rule.rule.ip.pt.port.s_from, timru->rule.rule.ip.pt.port.s_to); + printf("%s ", str); + break; + } + + /* dst addr */ + write_ip_addr(str, timru->rule.rule.ip.daddr, timru->rule.rule.ip.dmask); + printf("%s ", str); + + /* dst port */ + strcpy(str, "\0"); + switch(timru->rule.rule.ip.protocol) { + case ISDN_TIMRU_IP_TCP: + case ISDN_TIMRU_IP_UDP: + write_ip_port(str, timru->rule.rule.ip.pt.port.d_from, timru->rule.rule.ip.pt.port.d_to); + printf("%s ", str); + break; + } + break; + + case ISDN_TIMRU_PROTFAM_PPP: + printf("/%s", num2key(timru->rule.rule.ppp.protocol, timru_ppp_kt, timru_ppp_nt)); + break; + + default: + printf(" "); + break; + } + + printf("\n"); + + return(0); +} + + +int +output_rule_header(int rule_type, int protfam) { + printf("\n"); + switch(rule_type) { + case ISDN_TIMRU_BRINGUP: printf("Bringup-rules for outgoing "); break; + case ISDN_TIMRU_KEEPUP_IN: printf("Keepup-rules for incoming "); break; + case ISDN_TIMRU_KEEPUP_OUT: printf("Keepup-rules for outgoing "); break; + } + printf("%s-packets:\n", num2key(protfam, timru_protfam_kt, timru_protfam_nt)); + + return(0); +} + + +int +flush_timeout_rules(int fd, char *id, int all, int firstarg, int argc, char *argv []) { + isdn_ioctl_timeout_rule timru; + int i, j, first, last, + argp = firstarg, + args_used = 0; + char name [9]; + + + /* interface */ + strncpy(name, id, sizeof(name) - 1); + + if(all) { + first = 0; + last = ISDN_TIMRU_NUM_CHECK - 1; + } else { + /* rule-type */ + SHIFT_ARGS("rule-type"); + if(! strcmp(argv [argp], "bringup")) { + first = last = ISDN_TIMRU_BRINGUP; + } else if(! strcmp(argv [argp], "keepup")) { + /* keepup-type */ + SHIFT_ARGS("keepup-type"); + if(! strcmp(argv [argp], "in")) + first = last = ISDN_TIMRU_KEEPUP_IN; + else if(! strcmp(argv [argp], "out")) + first = last = ISDN_TIMRU_KEEPUP_OUT; + else if(! strcmp(argv [argp], "both")) { + first = ISDN_TIMRU_KEEPUP_IN; + last = ISDN_TIMRU_KEEPUP_OUT; + } else + PARSER_ERROR("wrong keepup-type"); + } else + PARSER_ERROR("wrong rule-type"); + } + + for(i = first; i <= last; i++) { + for(j = 0; j < ISDN_TIMRU_NUM_PROTFAM; j++) { + while(1) { + strcpy(timru.name, name); + timru.where = 0; + timru.type = i; + timru.protfam = j; + timru.index = 0; + + if(ioctl(fd, IIOCNETGRU, &timru) < 0) + break; + + if(ioctl(fd, IIOCNETDRU, &timru) < 0) + break; + } + } + } + + return(args_used); +} + + +int +set_default_timeout(int fd, char *id, int firstarg, int argc, char *argv []) { + isdn_ioctl_timeout_rule timru; + int n, ret, other_type = -1, + argp = firstarg, + args_used = 0; + + + /* set defaults */ + timru.where = -1; + + /* interface */ + strncpy(timru.name, id, sizeof(timru.name) - 1); + + /* rule-type */ + SHIFT_ARGS("rule-type"); + if(! strcmp(argv [argp], "bringup")) { + timru.type = ISDN_TIMRU_BRINGUP; + } else if(! strcmp(argv [argp], "keepup")) { + /* keepup-type */ + SHIFT_ARGS("keepup-type"); + if(! strcmp(argv [argp], "in")) + timru.type = ISDN_TIMRU_KEEPUP_IN; + else if(! strcmp(argv [argp], "out")) + timru.type = ISDN_TIMRU_KEEPUP_OUT; + else if(! strcmp(argv [argp], "both")) { + timru.type = ISDN_TIMRU_KEEPUP_IN; + other_type = ISDN_TIMRU_KEEPUP_OUT; + } else + PARSER_ERROR("wrong keepup-type"); + } else + PARSER_ERROR("wrong rule-type"); + + /* default value */ + SHIFT_ARGS("default-value"); + if(sscanf(argv [argp], "%i%n", &timru.defval, &n) <= 0 || n != strlen(argv [argp])) + PARSER_ERROR("wrong default-value"); + + if((ret = ioctl(fd, IIOCNETARU, &timru)) < 0) + return(ret); + + if(other_type >= 0) { + timru.type = other_type; + if((ret = ioctl(fd, IIOCNETARU, &timru)) < 0) + return(ret); + } + + return(args_used); +} + + +char * +defs_timru(char *id) { + static char r [1024]; + char *p = r; + + p += sprintf(p, "addrule %s keepup in 0 ppp/lcp\n", id); + + return(r); +} + + +/* Budget-Erweiterung */ +/* +??.07.97:cal:DAY: (60 * HOUR) --> (24 * HOUR) +04.11.97:cal:div. Formatierungen +*/ + +int output_budgets(int, char *, int, int, int, char *[]); +int read_budget_time(char *, time_t *); +char *write_budget_time(time_t); +char *output_time(time_t *); + +#define MINUTE 60 +#define HOUR (60 * MINUTE) +#define DAY (24 * HOUR) +#define WEEK (7 * DAY) +#define MONTH (30 * DAY) +#define YEAR (365 * DAY) + + +int +hdl_budget(int fd, char *id, int cmd, int argc, char *argv []) { + isdn_ioctl_budget budget; + int ioret, n, + argp = 0, + args_used = 0; + time_t t; + + + memset(&budget, 0, sizeof(isdn_ioctl_budget)); + + /* cmd */ + switch(cmd) { + case SHOWBUDGETS: + case SAVEBUDGETS: + return(args_used + output_budgets(fd, id, cmd, argp, argc, argv)); + break; + + case BUDGET: + /* interface */ + strncpy(budget.name, id, sizeof(budget.name) - 1); + + /* budget-type */ + SHIFT_ARGS("rule-type"); + if(! strcmp(argv [argp], "dial")) + budget.budget = ISDN_BUDGET_DIAL; + else if(! strcmp(argv [argp], "charge")) + budget.budget = ISDN_BUDGET_CHARGE; + else if(! strcmp(argv [argp], "online")) + budget.budget = ISDN_BUDGET_ONLINE; + else + PARSER_ERROR("wrong budget-type"); + + budget.command = ISDN_BUDGET_GET_BUDGET; + if((ioret = ioctl(fd, IIOCNETBUD, &budget)) < 0) { + perror("ioctl failed."); + return(ioret); + } + + /* amount */ + SHIFT_ARGS("amount"); + if(!strcmp(argv [argp], "off")) { + budget.amount = -1; + budget.period = (time_t)0; + } else { + /* amount */ + if(read_budget_time(argv [argp], &t) < 0) + PARSER_ERROR("wrong amount"); + budget.amount = t; + + /* period */ + SHIFT_ARGS("period"); + if(read_budget_time(argv [argp], &budget.period) < 0) + PARSER_ERROR("wrong period"); + + budget.used = 0; + budget.period_started = (time_t)0; + } + + budget.command = ISDN_BUDGET_SET_BUDGET; + if((ioret = ioctl(fd, IIOCNETBUD, &budget)) < 0) { + perror("ioctl failed."); + return(ioret); + } + + return(args_used); + break; + + case RESTOREBUDGETS: + /* interface */ + strncpy(budget.name, id, sizeof(budget.name) - 1); + + while(argp + 1 < argc) { + SHIFT_ARGS("saved-budget"); + if(sscanf(argv [argp], "%d:%d:%ld:%d:%ld%n", + &budget.budget, &budget.amount, (long *)&budget.period, + &budget.used, (long *)&budget.period_started, &n) != 5 || + n != strlen(argv [argp])) { + + UNSHIFT_ARGS(1); + break; + } else { + budget.command = ISDN_BUDGET_SET_BUDGET; + if((ioret = ioctl(fd, IIOCNETBUD, &budget)) < 0) { + perror("ioctl failed."); + return(ioret); + } + } + } + + return(args_used); + break; + + default: + PARSER_ERROR("unknown command"); + } +} + + +int +read_budget_time(char *str, time_t *period) { + char *s = str, base [10], comma [2]; + int e, n, amount; + time_t total = 0; + + while(*s) { + memset(base, 0, sizeof(base)); + + if((e = sscanf(s, "%i%n%[a-zA-Z]%n", &amount, &n, base, &n)) > 0) { + s += n; + + if(*s && sscanf(s, "%[,]%n", comma, &n) > 0) + s += n; + + if(e == 1 || !strcmp(base, "s") || !strcmp(base, "sec")) + total += amount; + else if(!strcmp(base, "m") || !strcmp(base, "min")) + total += (amount * MINUTE); + else if(!strcmp(base, "h") || !strcmp(base, "hour")) + total += (amount * HOUR); + else if(!strcmp(base, "d") || !strcmp(base, "day")) + total += (amount * DAY); + else if(!strcmp(base, "w") || !strcmp(base, "week")) + total += (amount * WEEK); + else if(!strcmp(base, "M") || !strcmp(base, "month")) + total += (amount * MONTH); + else if(!strcmp(base, "y") || !strcmp(base, "year")) + total += (amount * YEAR); + else + return(-1); + } else + return(-1); + } + + *period = total; + + return(0); +} + + +char * +write_budget_time(time_t period) { + static char str [64]; + time_t rest = period; + + + memset(str, 0, sizeof(str)); + + if(rest >= YEAR) { + sprintf(str, "%ldy", rest / YEAR); + rest %= YEAR; + } + + if(rest >= MONTH) { + sprintf(str, "%s%ldM", str, rest / MONTH); + rest %= MONTH; + } + + if(rest >= WEEK) { + sprintf(str, "%s%ldw", str, rest / WEEK); + rest %= WEEK; + } + + if(rest >= DAY) { + sprintf(str, "%s%ldd", str, rest / DAY); + rest %= DAY; + } + + if(rest >= HOUR) { + sprintf(str, "%s%ldh", str, rest / HOUR); + rest %= HOUR; + } + + if(rest >= MINUTE) { + sprintf(str, "%s%ldm", str, rest / MINUTE); + rest %= MINUTE; + } + + if(rest > 0 || period == 0) + sprintf(str, "%s%lds", str, rest); + + return(str); +} + + +char * +output_time(time_t *t) { + static char str [64]; + struct tm *u; + + + memset(str, 0, sizeof(str)); + + if((u = localtime(t))) + sprintf(str, "%02d.%02d.%04d, %02d:%02d:%02d", + u->tm_mday, u->tm_mon + 1, u->tm_year + 1900, + u->tm_hour, u->tm_min, u->tm_sec); + + return(str); +} + + +int +output_budgets(int fd, char *id, int cmd, int firstarg, int argc, char *argv []) { + isdn_ioctl_budget budget; + int i; + + + /* interface */ + strncpy(budget.name, id, sizeof(budget.name) - 1); + + switch(cmd) { + case SHOWBUDGETS: + printf("Budgets for interface %s:\n", budget.name); + + printf("\n"); + printf("TYPE AMOUNT PERIOD USED SINCE\n"); + + for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) { + budget.command = ISDN_BUDGET_GET_BUDGET; + budget.budget = i; + + if(ioctl(fd, IIOCNETBUD, &budget) == 0) { + switch(i) { + case ISDN_BUDGET_DIAL: + printf("%-6.6s ", "dial"); + if(budget.amount < 0) + printf("off\n"); + else + printf("%-10d %-10.10s %-10d %s\n", + budget.amount, write_budget_time(budget.period), budget.used, + output_time(&budget.period_started)); + break; + + case ISDN_BUDGET_CHARGE: + printf("%-6.6s ", "charge"); + if(budget.amount < 0) + printf("off\n"); + else + printf("%-10d %-10.10s %-10d %s\n", + budget.amount, write_budget_time(budget.period), budget.used, + output_time(&budget.period_started)); + break; + + case ISDN_BUDGET_ONLINE: + printf("%-6.6s ", "online"); + if(budget.amount < 0) + printf("off\n"); + else { + printf("%-10.10s ", write_budget_time(budget.amount)); + printf("%-10.10s ", write_budget_time(budget.period)); + printf("%-10.10s %s\n", write_budget_time(budget.used), + output_time(&budget.period_started)); + } + break; + } + } else { + perror("ioctl failed"); + } + } + break; + + case SAVEBUDGETS: + for(i = 0; i < ISDN_BUDGET_NUM_BUDGET; i++) { + budget.command = ISDN_BUDGET_GET_BUDGET; + budget.budget = i; + + if(ioctl(fd, IIOCNETBUD, &budget) == 0) { + if(i > 0) + printf(" "); + + printf("%d:%d:%ld:%d:%ld", + i, budget.amount, budget.period, + budget.used, budget.period_started); + } else { + perror("ioctl failed"); + } + } + printf("\n"); + } + + return(0); +} + + +char * +defs_budget(char *id) { + static char r [1024]; + char *p = r; + + p += sprintf(p, "budget %s dial 10 1min\n", id); + p += sprintf(p, "budget %s charge 100 1day\n", id); + p += sprintf(p, "budget %s online 8hour 1day\n", id); + + return(r); +} +#endif diff --git a/isdnctrl/ctrltimru.h b/isdnctrl/ctrltimru.h new file mode 100644 index 00000000..7786d616 --- /dev/null +++ b/isdnctrl/ctrltimru.h @@ -0,0 +1,25 @@ +/* + * ISDN TimRu-Control + * + * Copyright 1998 by Christian A. Lademann (cal@zls.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +int hdl_timeout_rule(int fd, char *id, int cmd, int argc, char *argv []); +char * defs_timru(char *id); +int hdl_budget(int fd, char *id, int cmd, int argc, char *argv []); +char * defs_budget(char *id);