/* * program for bundling channels * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: bundle.c,v 1.1 2004/03/11 03:59:32 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include #include #include #include #include #include #include #include #include #include #include "aps_if.h" #define CHECK_INTERVAL 5 /* in seconds, yep. */ int main ( int argc, char *argv[] ) { fd_set rfds; char buf[4096]; struct timeval tv, uniq; int fd = -1, len, num; int bundled = 0; int last_sent = 0; int timeouts = 0; int good = 0; int ints[2]; int iface; struct echodata { unsigned short proto; struct timeval uniq; struct timeval tv; int seq; int reply; } echosent, echorecv; if (argc < 3) { fprintf(stderr, "Usage: %s ...\n", argv[0]); exit(1); } iface = atoi(argv[1]); gettimeofday(&uniq, NULL); fd = open(argv[2], O_RDWR | O_NONBLOCK); if (-1 == fd) { fprintf(stderr, "Error opening %s: %s\n", argv[2], strerror(errno)); exit(1); } if (0 != ioctl(fd, BIOCCREATEBUNDLE, &iface) && EEXIST != errno) { perror("create bundle"); exit(1); } ints[0] = 0; ints[1] = BF_PPP | BF_ACFC | BF_PFC | BF_PASS_IP; if (0 != ioctl(fd, BIOC_SETBFL, &ints)) perror("setbfl(0, BF_PPP|BF_PASS_IP|BF_ACFC|BF_PFC)"); close(fd); fd = -1; tv.tv_sec = CHECK_INTERVAL; tv.tv_usec = 0; for (;;) { if (-1 == fd) { printf("Opening %s...\n", argv[2]); fd = open(argv[2], O_RDWR | (argc > 3 ? O_NONBLOCK : 0)); if (-1 == fd) fprintf(stderr, "Error opening %s: %s\n", argv[2], strerror(errno)); if (argc > 3) { int fl = fcntl(fd, F_GETFL, 0); fl &= ~O_NONBLOCK; fcntl(fd, F_SETFL, fl); fprintf(stderr, "dialing..."); fflush(stderr); if (ioctl(fd, BIOCDIAL, argv[3]) < 0) { perror("ioctl: dial"); close(fd); fd = -1; } else fprintf(stderr, "connected.\n"); } if (0 != ioctl(fd, BIOC_SETCFL, BF_PPP | BF_ACFC | BF_PFC | BF_PASS_IP)) perror("setcfl(whatever)"); } FD_ZERO(&rfds); if (-1 != fd) FD_SET(fd, &rfds); num = select(fd+1, &rfds, NULL, NULL, &tv); fprintf(stderr, "select=%d\n", num); if (num < 0) { perror("select"); continue; } if (-1 == fd) continue; if (!num) { /* timeout */ if (++timeouts > 2) { printf("timeout...\n"); leave: if (bundled) { if (0 != ioctl(fd, BIOCLEAVEBUNDLE, iface)) perror("leave bundle"); bundled = 0; printf("Dropped channel %s.\n", argv[2]); } } send: tv.tv_sec = CHECK_INTERVAL; tv.tv_usec = 0; echosent.proto = 0xc090; gettimeofday(&echosent.tv, NULL); echosent.seq = ++last_sent; echosent.reply = 0; memcpy(&echosent.uniq, &uniq, sizeof(uniq)); fprintf(stderr, "echoreq\n"); len = write(fd, &echosent, sizeof(echorecv)); if (-1 == len && EPIPE == errno) goto close; if (-1 == len) perror("write"); else if (sizeof(echorecv) != len) printf("short write (%d vs %d)\n", len, (int)sizeof(echorecv)); } else { len = read(fd, buf, sizeof(buf)); fprintf(stderr, "read=%d\n", len); if (len < 0) { perror("read"); } else if (!len) { close: good = 0; timeouts = 0; printf("Closing %s...\n", argv[2]); ioctl(fd, BIOCLEAVEBUNDLE, 0); bundled = 0; if (bundled) printf("Dropped channel %s.\n", argv[2]); close(fd); fd = -1; } else if (len == sizeof(echorecv)) { memcpy(&echorecv, buf, sizeof(echorecv)); if (echorecv.reply) { echorecv.reply = 0; if (!memcmp(&echorecv, &echosent, sizeof(echorecv))) { timeouts = 0; if (++good > 2 && !bundled) { if (0 != ioctl(fd, BIOCJOINBUNDLE, iface)) perror("join bundle"); else bundled = 1; printf("Added channel %s.\n", argv[2]); } if (!bundled) goto send; } else { fprintf(stderr, "recvd different\n"); } } else if (memcmp(&echorecv.uniq, &uniq, sizeof(uniq))) { fprintf(stderr, "echoreply\n"); echorecv.reply = 1; len = write(fd, &echorecv, sizeof(echorecv)); if (-1 == len && EPIPE == errno) goto close; if (-1 == len) perror("write"); else if (sizeof(echorecv) != len) printf("short write (%d vs %d)\n", len, (int)sizeof(echorecv)); } else { fprintf(stderr, "Loopback detected.\n"); goto leave; } } else printf("wrong size packet received (%d instead of %d)\n", len, (int)sizeof(echorecv)); } } return 0; }