/* isdnsync.c
 *
 * Author       Andreas Eversberg <jolly@eversberg.eu>
 *
 * 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 <http://www.gnu.org/licenses/>.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#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 <card>\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;
}
