#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <sys/ioctl.h>

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

#include "global.h"

int main(int argc, char **argv)
{
	unsigned char buf[512];
	int size;
	int s;
	char *dev = NULL;
	struct sockaddr sa;
	int asize = sizeof(sa);
	struct ifreq ifr;
	int proto = ETH_P_AX25;

	while ((s = getopt(argc, argv, "d:p")) != -1) {
		switch (s) {
			case 'd':
				dev = optarg;
				break;
			case 'p':
				proto = ETH_P_ALL;
				break;
			case ':':
				fprintf(stderr, "%s: option -d needs a device name.\n", argv[0]);
				return 1;
			case '?':
				fprintf(stderr, "Usage: %s [-d device] [-p]\n", argv[0]);
				return 1;
		}
	}

	if ((s = socket(AF_INET, SOCK_PACKET, htons(proto))) == -1) {
		perror("socket");
		return(1);
	}
	
	for (;;) {
		if ((size = recvfrom(s, buf, sizeof(buf), 0, &sa, &asize)) == -1) {
			perror("recv");
			return(1);
		}
		
		if (dev != NULL && strcmp(dev, sa.sa_data) != 0)
			continue;
			
		if (proto == ETH_P_ALL) {
			strcpy(ifr.ifr_name, sa.sa_data);
			if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
				perror("GIFADDR");

			if (ifr.ifr_hwaddr.sa_family == AF_AX25) {
				printf("Port %s: ", sa.sa_data);
				ki_dump(buf, size);
				putc('\n', stdout);
				fflush(stdout);
			}
			
			if (buf[12] == 0x08 && buf[13] == 0xFF) {
				printf("Port %s: ", sa.sa_data);
				bpq_dump(buf, size);
				putc('\n', stdout);
				fflush(stdout);
			}
		}
	}
}

void data_dump(unsigned char *data, int length)
{
	int  i, j;
	char c;

	for (i = 0; length > 0; i += 64)
	{
		fprintf(stdout, "%04X  ", i);
	
		for (j = 0; j < 64 && length > 0; j++)
		{
			c = *data++;
			length--;
			
			if (c >= 0x20 && c < 0x7F)
				putc(c, stdout);
			else
				putc('.', stdout);
		}
		
		putc('\n', stdout);
	}
}

int get16(unsigned char *cp)
{
	int x;
	
	x = *cp++;
	x <<= 8;
	x |= *cp++;
	
	return(x);
}

int get32(unsigned char *cp)
{
	int x;
	
	x = *cp++;
	x <<= 8;
	x |= *cp++;
	x <<= 8;
	x |= *cp++;
	x <<= 8;
	x |= *cp;
	
	return(x);
}
