/* isdnsync.c * * Author Andreas Eversberg * * All rights reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 of the License, 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include "mISDNif.h" #define MISDN_OLD_AF_COMPATIBILITY #define AF_COMPATIBILITY_FUNC #include "compat_af_isdn.h" int card = 0; int sock = -1; int mISDN_open(void) { int fd, ret; struct mISDN_devinfo devinfo; struct sockaddr_mISDN l2addr; fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE); if (fd < 0) { fprintf(stderr, "could not open socket (%s)\n", strerror(errno)); return fd; } devinfo.id = card; ret = ioctl(fd, IMGETDEVINFO, &devinfo); if (ret < 0) { fprintf(stderr,"could not send IOCTL IMGETCOUNT (%s)\n", strerror(errno)); close(fd); return ret; } close(fd); if (!(devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) && !(devinfo.Dprotocols & (1 << ISDN_P_TE_E1))) { fprintf(stderr,"Interface does not support TE mode (%s)\n", strerror(errno)); close(fd); return ret; } fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_TE); if (fd < 0) { fprintf(stderr,"could not open ISDN_P_LAPD_TE socket (%s)\n", strerror(errno)); return fd; } l2addr.family = AF_ISDN; l2addr.dev = card; l2addr.channel = 0; l2addr.sapi = 0; l2addr.tei = 0; ret = bind(fd, (struct sockaddr *)&l2addr, sizeof(l2addr)); if (ret < 0) { fprintf(stderr,"could not bind socket for card %d (%s)\n", card, strerror(errno)); close(fd); return ret; } sock = fd; return sock; } void mISDN_handle(void) { int ret; fd_set rfd; struct timeval tv; struct sockaddr_mISDN addr; socklen_t alen; unsigned char buffer[2048]; struct mISDNhead *hh = (struct mISDNhead *)buffer; int l1 = 0, l2 = 0, tei = 0; while(1) { again: FD_ZERO(&rfd); FD_SET(sock, &rfd); tv.tv_sec = 2; tv.tv_usec = 0; ret = select(sock+1, &rfd, NULL, NULL, &tv); if (ret < 0) { if (errno == EINTR) continue; fprintf(stderr, "%s aborted: %s\n", __FUNCTION__, strerror(errno)); break; } if (FD_ISSET(sock, &rfd)) { alen = sizeof(addr); ret = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &alen); if (ret < 0) { fprintf(stderr, "%s read socket error %s\n", __FUNCTION__, strerror(errno)); } else if (ret < MISDN_HEADER_LEN) { fprintf(stderr, "%s read socket shor frame\n", __FUNCTION__); } else { switch(hh->prim) { case MPH_ACTIVATE_IND: case PH_ACTIVATE_IND: if (!l1) { printf("PH_ACTIVATE\n"); printf("*** Sync available from interface :-)\n"); l1 = 1; } goto again; break; case MPH_DEACTIVATE_IND: case PH_DEACTIVATE_IND: if (l1) { printf("PH_DEACTIVATE\n"); printf("*** Lost sync on interface :-(\n"); l1 = 0; } goto again; break; case DL_ESTABLISH_IND: case DL_ESTABLISH_CNF: printf("DL_ESTABLISH\n"); l2 = 1; goto again; break; case DL_RELEASE_IND: case DL_RELEASE_CNF: printf("DL_RELEASE\n"); l2 = 0; goto again; break; case DL_INFORMATION_IND: printf("DL_INFORMATION (tei %d sapi %d)\n", addr.tei, addr.sapi); tei = 1; break; default: // printf("prim %x\n", hh->prim); goto again; } } } if (tei && !l2) { hh->prim = DL_ESTABLISH_REQ; printf("-> activating layer 2\n"); sendto(sock, buffer, MISDN_HEADER_LEN, 0, (struct sockaddr *) &addr, alen); } } } int main(int argc, char *argv[]) { int ret; if (argc <= 1) { printf("Usage: %s \n\n", argv[0]); printf("Opens given card number in TE-mode PTP and tries to keep layer 2 established.\n"); printf("This keeps layer 1 activated to retrieve a steady sync signal from network.\n"); return(0); } card = atoi(argv[1]); init_af_isdn(); if ((ret = mISDN_open() < 0)) return(ret); mISDN_handle(); close(sock); return 0; }