1335640Shselasky/*
2335640Shselasky *  pcap-sita.c: Packet capture interface additions for SITA ACN devices
3335640Shselasky *
4335640Shselasky *  Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc <fulko.hew@sita.aero>
5335640Shselasky *
6335640Shselasky *  License: BSD
7335640Shselasky *
8335640Shselasky *  Redistribution and use in source and binary forms, with or without
9335640Shselasky *  modification, are permitted provided that the following conditions
10335640Shselasky *  are met:
11335640Shselasky *
12335640Shselasky *  1. Redistributions of source code must retain the above copyright
13335640Shselasky *     notice, this list of conditions and the following disclaimer.
14335640Shselasky *  2. Redistributions in binary form must reproduce the above copyright
15335640Shselasky *     notice, this list of conditions and the following disclaimer in
16335640Shselasky *     the documentation and/or other materials provided with the
17335640Shselasky *     distribution.
18335640Shselasky *  3. The names of the authors may not be used to endorse or promote
19335640Shselasky *     products derived from this software without specific prior
20335640Shselasky *     written permission.
21335640Shselasky *
22335640Shselasky *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23335640Shselasky *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24335640Shselasky *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25335640Shselasky */
26335640Shselasky
27335640Shselasky#ifdef HAVE_CONFIG_H
28335640Shselasky#include <config.h>
29335640Shselasky#endif
30335640Shselasky
31335640Shselasky#include <stdio.h>
32335640Shselasky#include <string.h>
33335640Shselasky#include <stdlib.h>
34335640Shselasky#include <unistd.h>
35335640Shselasky#include <fcntl.h>
36335640Shselasky#include <errno.h>
37335640Shselasky#include <sys/time.h>
38335640Shselasky#include <sys/socket.h>
39335640Shselasky#include <netinet/in.h>
40335640Shselasky#include <arpa/inet.h>
41335640Shselasky#include "pcap-int.h"
42335640Shselasky
43335640Shselasky#include "pcap-sita.h"
44335640Shselasky
45335640Shselasky	/* non-configureable manifests follow */
46335640Shselasky
47335640Shselasky#define IOP_SNIFFER_PORT	49152			/* TCP port on the IOP used for 'distributed pcap' usage */
48335640Shselasky#define MAX_LINE_SIZE		255				/* max size of a buffer/line in /etc/hosts we allow */
49335640Shselasky#define MAX_CHASSIS			8				/* number of chassis in an ACN site */
50335640Shselasky#define MAX_GEOSLOT			8				/* max number of access units in an ACN site */
51335640Shselasky
52335640Shselasky#define FIND			0
53335640Shselasky#define LIVE			1
54335640Shselasky
55335640Shselaskytypedef struct iface {
56335640Shselasky	struct iface	*next;		/* a pointer to the next interface */
57335640Shselasky	char		*name;		/* this interface's name */
58335640Shselasky	char		*IOPname;	/* this interface's name on an IOP */
59335640Shselasky	uint32_t	iftype;		/* the type of interface (DLT values) */
60335640Shselasky} iface_t;
61335640Shselasky
62335640Shselaskytypedef struct unit {
63335640Shselasky	char			*ip;		/* this unit's IP address (as extracted from /etc/hosts) */
64335640Shselasky	int			fd;		/* the connection to this unit (if it exists) */
65335640Shselasky	int			find_fd;	/* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */
66335640Shselasky	int			first_time;	/* 0 = just opened via acn_open_live(),  ie. the first time, NZ = nth time */
67335640Shselasky	struct sockaddr_in	*serv_addr;	/* the address control block for comms to this unit */
68335640Shselasky	int			chassis;
69335640Shselasky	int			geoslot;
70335640Shselasky	iface_t			*iface;		/* a pointer to a linked list of interface structures */
71335640Shselasky	char			*imsg;		/* a pointer to an inbound message */
72335640Shselasky	int			len;		/* the current size of the inbound message */
73335640Shselasky} unit_t;
74335640Shselasky
75335640Shselaskystatic unit_t		units[MAX_CHASSIS+1][MAX_GEOSLOT+1];	/* we use indexes of 1 through 8, but we reserve/waste index 0 */
76335640Shselaskystatic fd_set		readfds;				/* a place to store the file descriptors for the connections to the IOPs */
77335640Shselaskystatic int		max_fs;
78335640Shselasky
79335640Shselaskypcap_if_t		*acn_if_list;		/* pcap's list of available interfaces */
80335640Shselasky
81335640Shselaskystatic void dump_interface_list(void) {
82335640Shselasky	pcap_if_t		*iff;
83335640Shselasky	pcap_addr_t		*addr;
84335640Shselasky	int			longest_name_len = 0;
85335640Shselasky	char			*n, *d, *f;
86335640Shselasky	int			if_number = 0;
87335640Shselasky
88335640Shselasky	iff = acn_if_list;
89335640Shselasky	while (iff) {
90335640Shselasky		if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name);
91335640Shselasky		iff = iff->next;
92335640Shselasky	}
93335640Shselasky	iff = acn_if_list;
94335640Shselasky	printf("Interface List:\n");
95335640Shselasky	while (iff) {
96335640Shselasky		n = (iff->name)							? iff->name			: "";
97335640Shselasky		d = (iff->description)					? iff->description	: "";
98335640Shselasky		f = (iff->flags == PCAP_IF_LOOPBACK)	? "L"				: "";
99335640Shselasky		printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d);
100335640Shselasky		addr = iff->addresses;
101335640Shselasky		while (addr) {
102335640Shselasky			printf("%*s ", (5 + longest_name_len), "");		/* add some indentation */
103335640Shselasky			printf("%15s  ", (addr->addr)		? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr)		: "");
104335640Shselasky			printf("%15s  ", (addr->netmask)	? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr)	: "");
105335640Shselasky			printf("%15s  ", (addr->broadaddr)	? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr)	: "");
106335640Shselasky			printf("%15s  ", (addr->dstaddr)	? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr)	: "");
107335640Shselasky			printf("\n");
108335640Shselasky			addr = addr->next;
109335640Shselasky		}
110335640Shselasky		iff = iff->next;
111335640Shselasky	}
112335640Shselasky}
113335640Shselasky
114335640Shselaskystatic void dump(unsigned char *ptr, int i, int indent) {
115335640Shselasky	fprintf(stderr, "%*s", indent, " ");
116335640Shselasky	for (; i > 0; i--) {
117335640Shselasky		fprintf(stderr, "%2.2x ", *ptr++);
118335640Shselasky	}
119335640Shselasky	fprintf(stderr, "\n");
120335640Shselasky}
121335640Shselasky
122335640Shselaskystatic void dump_interface_list_p(void) {
123335640Shselasky	pcap_if_t		*iff;
124335640Shselasky	pcap_addr_t		*addr;
125335640Shselasky	int				if_number = 0;
126335640Shselasky
127335640Shselasky	iff = acn_if_list;
128335640Shselasky	printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff);
129335640Shselasky	while (iff) {
130335640Shselasky		printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next);
131335640Shselasky		dump((unsigned char *)iff, sizeof(pcap_if_t), 5);
132335640Shselasky		addr = iff->addresses;
133335640Shselasky		while (addr) {
134335640Shselasky			printf("          %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next);
135335640Shselasky			dump((unsigned char *)addr, sizeof(pcap_addr_t), 10);
136335640Shselasky			addr = addr->next;
137335640Shselasky		}
138335640Shselasky		iff = iff->next;
139335640Shselasky	}
140335640Shselasky}
141335640Shselasky
142335640Shselaskystatic void dump_unit_table(void) {
143335640Shselasky	int		chassis, geoslot;
144335640Shselasky	iface_t	*p;
145335640Shselasky
146335640Shselasky	printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address");
147335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
148335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
149335640Shselasky			if (units[chassis][geoslot].ip != NULL)
150335640Shselasky				printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip);
151335640Shselasky			p = units[chassis][geoslot].iface;
152335640Shselasky			while (p) {
153335640Shselasky				char *n = (p->name)			? p->name			: "";
154335640Shselasky				char *i = (p->IOPname)		? p->IOPname		: "";
155335640Shselasky				p = p->next;
156335640Shselasky				printf("   %12s    -> %12s\n", i, n);
157335640Shselasky			}
158335640Shselasky		}
159335640Shselasky	}
160335640Shselasky}
161335640Shselasky
162335640Shselaskystatic int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) {
163335640Shselasky	int		c, s;
164335640Shselasky
165335640Shselasky	for (c = 0; c <= MAX_CHASSIS; c++) {
166335640Shselasky		for (s = 0; s <= MAX_GEOSLOT; s++) {
167335640Shselasky			if (units[c][s].fd == fd || units[c][s].find_fd == fd) {
168335640Shselasky				if (chassis)	*chassis = c;
169335640Shselasky				if (geoslot)	*geoslot = s;
170335640Shselasky				if (unit_ptr)	*unit_ptr = &units[c][s];
171335640Shselasky				return 1;
172335640Shselasky			}
173335640Shselasky		}
174335640Shselasky	}
175335640Shselasky	return 0;
176335640Shselasky}
177335640Shselasky
178335640Shselaskystatic int read_client_nbytes(int fd, int count, unsigned char *buf) {
179335640Shselasky	unit_t			*u;
180335640Shselasky	int				chassis, geoslot;
181335640Shselasky	int				len;
182335640Shselasky
183335640Shselasky	find_unit_by_fd(fd, &chassis, &geoslot, &u);
184335640Shselasky	while (count) {
185335640Shselasky		if ((len = recv(fd, buf, count, 0)) <= 0)	return -1;	/* read in whatever data was sent to us */
186335640Shselasky		count -= len;
187335640Shselasky		buf += len;
188335640Shselasky	}															/* till we have everything we are looking for */
189335640Shselasky	return 0;
190335640Shselasky}
191335640Shselasky
192335640Shselaskystatic void empty_unit_iface(unit_t *u) {
193335640Shselasky	iface_t	*p, *cur;
194335640Shselasky
195335640Shselasky	cur = u->iface;
196335640Shselasky	while (cur) {											/* loop over all the interface entries */
197335640Shselasky		if (cur->name)			free(cur->name);			/* throwing away the contents if they exist */
198335640Shselasky		if (cur->IOPname)		free(cur->IOPname);
199335640Shselasky		p = cur->next;
200335640Shselasky		free(cur);											/* then throw away the structure itself */
201335640Shselasky		cur = p;
202335640Shselasky	}
203335640Shselasky	u->iface = 0;											/* and finally remember that there are no remaining structure */
204335640Shselasky}
205335640Shselasky
206335640Shselaskystatic void empty_unit(int chassis, int geoslot) {
207335640Shselasky	unit_t	*u = &units[chassis][geoslot];
208335640Shselasky
209335640Shselasky	empty_unit_iface(u);
210335640Shselasky	if (u->imsg) {											/* then if an inbound message buffer exists */
211335640Shselasky		void *bigger_buffer;
212335640Shselasky
213335640Shselasky		bigger_buffer = (char *)realloc(u->imsg, 1);				/* and re-allocate the old large buffer into a new small one */
214335640Shselasky		if (bigger_buffer == NULL) {	/* oops, realloc call failed */
215335640Shselasky			fprintf(stderr, "Warning...call to realloc() failed, value of errno is %d\n", errno);
216335640Shselasky			return;
217335640Shselasky		}
218335640Shselasky		u->imsg = bigger_buffer;
219335640Shselasky	}
220335640Shselasky}
221335640Shselasky
222335640Shselaskystatic void empty_unit_table(void) {
223335640Shselasky	int		chassis, geoslot;
224335640Shselasky
225335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
226335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
227335640Shselasky			if (units[chassis][geoslot].ip != NULL) {
228335640Shselasky				free(units[chassis][geoslot].ip);			/* get rid of the malloc'ed space that holds the IP address */
229335640Shselasky				units[chassis][geoslot].ip = 0;				/* then set the pointer to NULL */
230335640Shselasky			}
231335640Shselasky			empty_unit(chassis, geoslot);
232335640Shselasky		}
233335640Shselasky	}
234335640Shselasky}
235335640Shselasky
236335640Shselaskystatic char *find_nth_interface_name(int n) {
237335640Shselasky	int		chassis, geoslot;
238335640Shselasky	iface_t	*p;
239335640Shselasky	char	*last_name = 0;
240335640Shselasky
241335640Shselasky	if (n < 0) n = 0;												/* ensure we are working with a valid number */
242335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {			/* scan the table... */
243335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
244335640Shselasky			if (units[chassis][geoslot].ip != NULL) {
245335640Shselasky				p = units[chassis][geoslot].iface;
246335640Shselasky				while (p) {											/* and all interfaces... */
247335640Shselasky					if (p->IOPname) last_name = p->name;			/* remembering the last name found */
248335640Shselasky					if (n-- == 0) return last_name;					/* and if we hit the instance requested */
249335640Shselasky					p = p->next;
250335640Shselasky				}
251335640Shselasky			}
252335640Shselasky		}
253335640Shselasky	}
254335640Shselasky											/* if we couldn't fine the selected entry */
255335640Shselasky	if (last_name)	return last_name;		/* ... but we did have at least one entry... return the last entry found */
256335640Shselasky	return "";								/* ... but if there wasn't any entry... return an empty string instead */
257335640Shselasky}
258335640Shselasky
259335640Shselaskyint acn_parse_hosts_file(char *errbuf) {				/* returns: -1 = error, 0 = OK */
260335640Shselasky	FILE	*fp;
261335640Shselasky	char	buf[MAX_LINE_SIZE];
262335640Shselasky	char	*ptr, *ptr2;
263335640Shselasky	int		pos;
264335640Shselasky	int		chassis, geoslot;
265335640Shselasky	unit_t	*u;
266335640Shselasky
267335640Shselasky	empty_unit_table();
268335640Shselasky	if ((fp = fopen("/etc/hosts", "r")) == NULL) {										/* try to open the hosts file and if it fails */
269335640Shselasky		pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading.");	/* return the nohostsfile error response */
270335640Shselasky		return -1;
271335640Shselasky	}
272335640Shselasky	while (fgets(buf, MAX_LINE_SIZE-1, fp)) {			/* while looping over the file */
273335640Shselasky
274335640Shselasky		pos = strcspn(buf, "#\n\r");					/* find the first comment character or EOL */
275335640Shselasky		*(buf + pos) = '\0';							/* and clobber it and anything that follows it */
276335640Shselasky
277335640Shselasky		pos = strspn(buf, " \t");						/* then find the first non-white space */
278335640Shselasky		if (pos == strlen(buf))							/* if there is nothing but white space on the line */
279335640Shselasky			continue;									/* ignore that empty line */
280335640Shselasky		ptr = buf + pos;								/* and skip over any of that leading whitespace */
281335640Shselasky
282335640Shselasky		if ((ptr2 = strstr(ptr, "_I_")) == NULL)		/* skip any lines that don't have names that look like they belong to IOPs */
283335640Shselasky			continue;
284335640Shselasky		if (*(ptr2 + 4) != '_')							/* and skip other lines that have names that don't look like ACN components */
285335640Shselasky			continue;
286335640Shselasky		*(ptr + strcspn(ptr, " \t")) = '\0';			/* null terminate the IP address so its a standalone string */
287335640Shselasky
288335640Shselasky		chassis = *(ptr2 + 3) - '0';					/* extract the chassis number */
289335640Shselasky		geoslot = *(ptr2 + 5) - '0';					/* and geo-slot number */
290335640Shselasky		if (chassis < 1 || chassis > MAX_CHASSIS ||
291335640Shselasky			geoslot < 1 || geoslot > MAX_GEOSLOT) {		/* if the chassis and/or slot numbers appear to be bad... */
292335640Shselasky			pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'.");	/* warn the user */
293335640Shselasky			continue;																	/* and ignore the entry */
294335640Shselasky		}
295335640Shselasky		if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
296335640Shselasky			pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
297335640Shselasky			    errno, "malloc");
298335640Shselasky			continue;
299335640Shselasky		}
300335640Shselasky		strcpy(ptr2, ptr);								/* copy the IP address into our malloc'ed memory */
301335640Shselasky		u = &units[chassis][geoslot];
302335640Shselasky		u->ip = ptr2;									/* and remember the whole shebang */
303335640Shselasky		u->chassis = chassis;
304335640Shselasky		u->geoslot = geoslot;
305335640Shselasky	}
306335640Shselasky	fclose(fp);
307335640Shselasky	if (*errbuf)	return -1;
308335640Shselasky	else			return 0;
309335640Shselasky}
310335640Shselasky
311335640Shselaskystatic int open_with_IOP(unit_t  *u, int flag) {
312335640Shselasky	int					sockfd;
313335640Shselasky	char				*ip;
314335640Shselasky
315335640Shselasky	if (u->serv_addr == NULL) {
316335640Shselasky		u->serv_addr = malloc(sizeof(struct sockaddr_in));
317335640Shselasky
318335640Shselasky		/* since we called malloc(), lets check to see if we actually got the memory	*/
319335640Shselasky		if (u->serv_addr == NULL) {	/* oops, we didn't get the memory requested	*/
320335640Shselasky			fprintf(stderr, "malloc() request for u->serv_addr failed, value of errno is: %d\n", errno);
321335640Shselasky			return 0;
322335640Shselasky		}
323335640Shselasky
324335640Shselasky	}
325335640Shselasky	ip = u->ip;
326335640Shselasky	/* bzero() is deprecated, replaced with memset()	*/
327335640Shselasky	memset((char *)u->serv_addr, 0, sizeof(struct sockaddr_in));
328335640Shselasky	u->serv_addr->sin_family		= AF_INET;
329335640Shselasky	u->serv_addr->sin_addr.s_addr	= inet_addr(ip);
330335640Shselasky	u->serv_addr->sin_port			= htons(IOP_SNIFFER_PORT);
331335640Shselasky
332335640Shselasky	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
333335640Shselasky		fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip);
334335640Shselasky		return 0;
335335640Shselasky	}
336335640Shselasky	if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) {
337335640Shselasky		fprintf(stderr, "pcap can't connect to IOP at %s\n", ip);
338335640Shselasky		return 0;
339335640Shselasky	}
340335640Shselasky	if (flag == LIVE)	u->fd = sockfd;
341335640Shselasky	else				u->find_fd = sockfd;
342335640Shselasky	u->first_time = 0;
343335640Shselasky	return sockfd;			/* return the non-zero file descriptor as a 'success' indicator */
344335640Shselasky}
345335640Shselasky
346335640Shselaskystatic void close_with_IOP(int chassis, int geoslot, int flag) {
347335640Shselasky	int		*id;
348335640Shselasky
349335640Shselasky	if (flag == LIVE)	id = &units[chassis][geoslot].fd;
350335640Shselasky	else				id = &units[chassis][geoslot].find_fd;
351335640Shselasky
352335640Shselasky	if (*id) {										/* this was the last time, so... if we are connected... */
353335640Shselasky		close(*id);									/* disconnect us */
354335640Shselasky		*id = 0;									/* and forget that the descriptor exists because we are not open */
355335640Shselasky	}
356335640Shselasky}
357335640Shselasky
358335640Shselaskystatic void pcap_cleanup_acn(pcap_t *handle) {
359335640Shselasky	int		chassis, geoslot;
360335640Shselasky	unit_t	*u;
361335640Shselasky
362335640Shselasky	if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0)
363335640Shselasky		return;
364335640Shselasky	close_with_IOP(chassis, geoslot, LIVE);
365335640Shselasky	if (u)
366335640Shselasky		u->first_time = 0;
367335640Shselasky	pcap_cleanup_live_common(handle);
368335640Shselasky}
369335640Shselasky
370335640Shselaskystatic void send_to_fd(int fd, int len, unsigned char *str) {
371335640Shselasky	int		nwritten;
372335640Shselasky	int		chassis, geoslot;
373335640Shselasky
374335640Shselasky	while (len > 0) {
375335640Shselasky		if ((nwritten = write(fd, str, len)) <= 0) {
376335640Shselasky			find_unit_by_fd(fd, &chassis, &geoslot, NULL);
377335640Shselasky			if (units[chassis][geoslot].fd == fd)			close_with_IOP(chassis, geoslot, LIVE);
378335640Shselasky			else if (units[chassis][geoslot].find_fd == fd)	close_with_IOP(chassis, geoslot, FIND);
379335640Shselasky			empty_unit(chassis, geoslot);
380335640Shselasky			return;
381335640Shselasky		}
382335640Shselasky		len -= nwritten;
383335640Shselasky		str += nwritten;
384335640Shselasky	}
385335640Shselasky}
386335640Shselasky
387335640Shselaskystatic void acn_freealldevs(void) {
388335640Shselasky
389335640Shselasky	pcap_if_t	*iff, *next_iff;
390335640Shselasky	pcap_addr_t	*addr, *next_addr;
391335640Shselasky
392335640Shselasky	for (iff = acn_if_list; iff != NULL; iff = next_iff) {
393335640Shselasky		next_iff = iff->next;
394335640Shselasky		for (addr = iff->addresses; addr != NULL; addr = next_addr) {
395335640Shselasky			next_addr = addr->next;
396335640Shselasky			if (addr->addr)			free(addr->addr);
397335640Shselasky			if (addr->netmask)		free(addr->netmask);
398335640Shselasky			if (addr->broadaddr)	free(addr->broadaddr);
399335640Shselasky			if (addr->dstaddr)		free(addr->dstaddr);
400335640Shselasky			free(addr);
401335640Shselasky		}
402335640Shselasky		if (iff->name)			free(iff->name);
403335640Shselasky		if (iff->description)	free(iff->description);
404335640Shselasky		free(iff);
405335640Shselasky	}
406335640Shselasky}
407335640Shselasky
408335640Shselaskystatic void nonUnified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u) {
409335640Shselasky
410335640Shselasky	pcap_snprintf(buf, bufsize, "%s_%d_%d", proto, u->chassis, u->geoslot);
411335640Shselasky}
412335640Shselasky
413335640Shselaskystatic void unified_IOP_port_name(char *buf, size_t bufsize, const char *proto, unit_t *u, int IOPportnum) {
414335640Shselasky	int			portnum;
415335640Shselasky
416335640Shselasky	portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
417335640Shselasky	pcap_snprintf(buf, bufsize, "%s_%d", proto, portnum);
418335640Shselasky}
419335640Shselasky
420335640Shselaskystatic char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, bpf_u_int32 iftype) {
421335640Shselasky	iface_t		*iface_ptr, *iface;
422335640Shselasky	char		*name;
423335640Shselasky	char		buf[32];
424335640Shselasky	char		*proto;
425335640Shselasky	char		*port;
426335640Shselasky	int			IOPportnum = 0;
427335640Shselasky
428335640Shselasky	iface = malloc(sizeof(iface_t));		/* get memory for a structure */
429335640Shselasky	if (iface == NULL) {	/* oops, we didn't get the memory requested	*/
430335640Shselasky		fprintf(stderr, "Error...couldn't allocate memory for interface structure...value of errno is: %d\n", errno);
431335640Shselasky		return NULL;
432335640Shselasky	}
433335640Shselasky	memset((char *)iface, 0, sizeof(iface_t));	/* bzero is deprecated(), replaced with memset() */
434335640Shselasky
435335640Shselasky	iface->iftype = iftype;					/* remember the interface type of this interface */
436335640Shselasky
437335640Shselasky	name = malloc(strlen(IOPname) + 1);		/* get memory for the IOP's name */
438335640Shselasky        if (name == NULL) {    /* oops, we didn't get the memory requested     */
439335640Shselasky                fprintf(stderr, "Error...couldn't allocate memory for IOPname...value of errno is: %d\n", errno);
440335640Shselasky                return NULL;
441335640Shselasky        }
442335640Shselasky
443335640Shselasky	strcpy(name, IOPname);					/* and copy it in */
444335640Shselasky	iface->IOPname = name;					/* and stick it into the structure */
445335640Shselasky
446335640Shselasky	if (strncmp(IOPname, "lo", 2) == 0) {
447335640Shselasky		IOPportnum = atoi(&IOPname[2]);
448335640Shselasky		switch (iftype) {
449335640Shselasky			case DLT_EN10MB:
450335640Shselasky				nonUnified_IOP_port_name(buf, sizeof buf, "lo", u);
451335640Shselasky				break;
452335640Shselasky			default:
453335640Shselasky				unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
454335640Shselasky				break;
455335640Shselasky		}
456335640Shselasky	} else if (strncmp(IOPname, "eth", 3) == 0) {
457335640Shselasky		IOPportnum = atoi(&IOPname[3]);
458335640Shselasky		switch (iftype) {
459335640Shselasky			case DLT_EN10MB:
460335640Shselasky				nonUnified_IOP_port_name(buf, sizeof buf, "eth", u);
461335640Shselasky				break;
462335640Shselasky			default:
463335640Shselasky				unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
464335640Shselasky				break;
465335640Shselasky		}
466335640Shselasky	} else if (strncmp(IOPname, "wan", 3) == 0) {
467335640Shselasky		IOPportnum = atoi(&IOPname[3]);
468335640Shselasky		switch (iftype) {
469335640Shselasky			case DLT_SITA:
470335640Shselasky				unified_IOP_port_name(buf, sizeof buf, "wan", u, IOPportnum);
471335640Shselasky				break;
472335640Shselasky			default:
473335640Shselasky				unified_IOP_port_name(buf, sizeof buf, "???", u, IOPportnum);
474335640Shselasky				break;
475335640Shselasky		}
476335640Shselasky	} else {
477335640Shselasky		fprintf(stderr, "Error... invalid IOP name %s\n", IOPname);
478335640Shselasky		return NULL;
479335640Shselasky	}
480335640Shselasky
481335640Shselasky	name = malloc(strlen(buf) + 1);			/* get memory for that name */
482335640Shselasky        if (name == NULL) {    /* oops, we didn't get the memory requested     */
483335640Shselasky                fprintf(stderr, "Error...couldn't allocate memory for IOP port name...value of errno is: %d\n", errno);
484335640Shselasky                return NULL;
485335640Shselasky        }
486335640Shselasky
487335640Shselasky	strcpy(name, buf);						/* and copy it in */
488335640Shselasky	iface->name = name;						/* and stick it into the structure */
489335640Shselasky
490335640Shselasky	if (u->iface == 0) {					/* if this is the first name */
491335640Shselasky		u->iface = iface;					/* stick this entry at the head of the list */
492335640Shselasky	} else {
493335640Shselasky		iface_ptr = u->iface;
494335640Shselasky		while (iface_ptr->next) {			/* othewise scan the list */
495335640Shselasky			iface_ptr = iface_ptr->next;	/* till we're at the last entry */
496335640Shselasky		}
497335640Shselasky		iface_ptr->next = iface;			/* then tack this entry on the end of the list */
498335640Shselasky	}
499335640Shselasky	return iface->name;
500335640Shselasky}
501335640Shselasky
502335640Shselaskystatic int if_sort(char *s1, char *s2) {
503335640Shselasky	char	*s1_p2, *s2_p2;
504335640Shselasky	char	str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE];
505335640Shselasky	int		s1_p1_len, s2_p1_len;
506335640Shselasky	int		retval;
507335640Shselasky
508335640Shselasky	if ((s1_p2 = strchr(s1, '_'))) {	/* if an underscore is found... */
509335640Shselasky		s1_p1_len = s1_p2 - s1;			/* the prefix length is the difference in pointers */
510335640Shselasky		s1_p2++;						/* the suffix actually starts _after_ the underscore */
511335640Shselasky	} else {							/* otherwise... */
512335640Shselasky		s1_p1_len = strlen(s1);			/* the prefix length is the length of the string itself */
513335640Shselasky		s1_p2 = 0;						/* and there is no suffix */
514335640Shselasky	}
515335640Shselasky	if ((s2_p2 = strchr(s2, '_'))) {	/* now do the same for the second string */
516335640Shselasky		s2_p1_len = s2_p2 - s2;
517335640Shselasky		s2_p2++;
518335640Shselasky	} else {
519335640Shselasky		s2_p1_len = strlen(s2);
520335640Shselasky		s2_p2 = 0;
521335640Shselasky	}
522335640Shselasky	strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1));   *(str1 + s1_p1_len) = 0;
523335640Shselasky	strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2));   *(str2 + s2_p1_len) = 0;
524335640Shselasky	retval = strcmp(str1, str2);
525335640Shselasky	if (retval != 0) return retval;		/* if they are not identical, then we can quit now and return the indication */
526335640Shselasky	return strcmp(s1_p2, s2_p2);		/* otherwise we return the result of comparing the 2nd half of the string */
527335640Shselasky}
528335640Shselasky
529335640Shselaskystatic void sort_if_table(void) {
530335640Shselasky	pcap_if_t	*p1, *p2, *prev, *temp;
531335640Shselasky	int			has_swapped;
532335640Shselasky
533335640Shselasky	if (!acn_if_list) return;				/* nothing to do if the list is empty */
534335640Shselasky
535335640Shselasky	while (1) {
536335640Shselasky		p1 = acn_if_list;					/* start at the head of the list */
537335640Shselasky		prev = 0;
538335640Shselasky		has_swapped = 0;
539335640Shselasky		while ((p2 = p1->next)) {
540335640Shselasky			if (if_sort(p1->name, p2->name) > 0) {
541335640Shselasky				if (prev) {					/* we are swapping things that are _not_ at the head of the list */
542335640Shselasky					temp = p2->next;
543335640Shselasky					prev->next = p2;
544335640Shselasky					p2->next = p1;
545335640Shselasky					p1->next = temp;
546335640Shselasky				} else {					/* special treatment if we are swapping with the head of the list */
547335640Shselasky					temp = p2->next;
548335640Shselasky					acn_if_list= p2;
549335640Shselasky					p2->next = p1;
550335640Shselasky					p1->next = temp;
551335640Shselasky				}
552335640Shselasky				p1 = p2;
553335640Shselasky				prev = p1;
554335640Shselasky				has_swapped = 1;
555335640Shselasky			}
556335640Shselasky			prev = p1;
557335640Shselasky			p1 = p1->next;
558335640Shselasky		}
559335640Shselasky		if (has_swapped == 0)
560335640Shselasky			return;
561335640Shselasky	}
562335640Shselasky	return;
563335640Shselasky}
564335640Shselasky
565335640Shselaskystatic int process_client_data (char *errbuf) {								/* returns: -1 = error, 0 = OK */
566335640Shselasky	int					chassis, geoslot;
567335640Shselasky	unit_t				*u;
568335640Shselasky	pcap_if_t			*iff, *prev_iff;
569335640Shselasky	pcap_addr_t			*addr, *prev_addr;
570335640Shselasky	char				*ptr;
571335640Shselasky	int					address_count;
572335640Shselasky	struct sockaddr_in	*s;
573335640Shselasky	char				*newname;
574335640Shselasky	bpf_u_int32				interfaceType;
575335640Shselasky	unsigned char		flags;
576335640Shselasky	void *bigger_buffer;
577335640Shselasky
578335640Shselasky	prev_iff = 0;
579335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
580335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {				/* now loop over all the devices */
581335640Shselasky			u = &units[chassis][geoslot];
582335640Shselasky			empty_unit_iface(u);
583335640Shselasky			ptr = u->imsg;													/* point to the start of the msg for this IOP */
584335640Shselasky			while (ptr < (u->imsg + u->len)) {
585335640Shselasky				if ((iff = malloc(sizeof(pcap_if_t))) == NULL) {
586335640Shselasky					pcap_fmt_errmsg_for_errno(errbuf,
587335640Shselasky					    PCAP_ERRBUF_SIZE, errno, "malloc");
588335640Shselasky					return -1;
589335640Shselasky				}
590335640Shselasky				memset((char *)iff, 0, sizeof(pcap_if_t)); /* bzero() is deprecated, replaced with memset() */
591335640Shselasky				if (acn_if_list == 0)	acn_if_list = iff;					/* remember the head of the list */
592335640Shselasky				if (prev_iff)			prev_iff->next = iff;				/* insert a forward link */
593335640Shselasky
594335640Shselasky				if (*ptr) {													/* if there is a count for the name */
595335640Shselasky					if ((iff->name = malloc(*ptr + 1)) == NULL) {			/* get that amount of space */
596335640Shselasky						pcap_fmt_errmsg_for_errno(errbuf,
597335640Shselasky						    PCAP_ERRBUF_SIZE, errno,
598335640Shselasky						    "malloc");
599335640Shselasky						return -1;
600335640Shselasky					}
601335640Shselasky					memcpy(iff->name, (ptr + 1), *ptr);						/* copy the name into the malloc'ed space */
602335640Shselasky					*(iff->name + *ptr) = 0;								/* and null terminate the string */
603335640Shselasky					ptr += *ptr;											/* now move the pointer forwards by the length of the count plus the length of the string */
604335640Shselasky				}
605335640Shselasky				ptr++;
606335640Shselasky
607335640Shselasky				if (*ptr) {													/* if there is a count for the description */
608335640Shselasky					if ((iff->description = malloc(*ptr + 1)) == NULL) {	/* get that amount of space */
609335640Shselasky						pcap_fmt_errmsg_for_errno(errbuf,
610335640Shselasky						    PCAP_ERRBUF_SIZE, errno,
611335640Shselasky						    "malloc");
612335640Shselasky						return -1;
613335640Shselasky					}
614335640Shselasky					memcpy(iff->description, (ptr + 1), *ptr);				/* copy the name into the malloc'ed space */
615335640Shselasky					*(iff->description + *ptr) = 0;							/* and null terminate the string */
616335640Shselasky					ptr += *ptr;											/* now move the pointer forwards by the length of the count plus the length of the string */
617335640Shselasky				}
618335640Shselasky				ptr++;
619335640Shselasky
620335640Shselasky				interfaceType = ntohl(*(bpf_u_int32 *)ptr);
621335640Shselasky				ptr += 4;													/* skip over the interface type */
622335640Shselasky
623335640Shselasky				flags = *ptr++;
624335640Shselasky				if (flags) iff->flags = PCAP_IF_LOOPBACK;					/* if this is a loopback style interface, lets mark it as such */
625335640Shselasky
626335640Shselasky				address_count = *ptr++;
627335640Shselasky
628335640Shselasky				prev_addr = 0;
629335640Shselasky				while (address_count--) {
630335640Shselasky					if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) {
631335640Shselasky						pcap_fmt_errmsg_for_errno(errbuf,
632335640Shselasky						    PCAP_ERRBUF_SIZE, errno,
633335640Shselasky						    "malloc");
634335640Shselasky						return -1;
635335640Shselasky					}
636335640Shselasky 					memset((char *)addr, 0, sizeof(pcap_addr_t)); /* bzero() is deprecated, replaced with memset() */
637335640Shselasky					if (iff->addresses == 0) iff->addresses = addr;
638335640Shselasky					if (prev_addr) prev_addr->next = addr;							/* insert a forward link */
639335640Shselasky					if (*ptr) {														/* if there is a count for the address */
640335640Shselasky						if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {		/* get that amount of space */
641335640Shselasky							pcap_fmt_errmsg_for_errno(errbuf,
642335640Shselasky							    PCAP_ERRBUF_SIZE,
643335640Shselasky							    errno, "malloc");
644335640Shselasky							return -1;
645335640Shselasky						}
646335640Shselasky						memset((char *)s, 0, sizeof(struct sockaddr_in)); /* bzero() is deprecated, replaced with memset() */
647335640Shselasky						addr->addr = (struct sockaddr *)s;
648335640Shselasky						s->sin_family		= AF_INET;
649335640Shselasky						s->sin_addr.s_addr	= *(bpf_u_int32 *)(ptr + 1);			/* copy the address in */
650335640Shselasky						ptr += *ptr;										/* now move the pointer forwards according to the specified length of the address */
651335640Shselasky					}
652335640Shselasky					ptr++;													/* then forwards one more for the 'length of the address' field */
653335640Shselasky					if (*ptr) {												/* process any netmask */
654335640Shselasky						if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
655335640Shselasky							pcap_fmt_errmsg_for_errno(errbuf,
656335640Shselasky							    PCAP_ERRBUF_SIZE,
657335640Shselasky							    errno, "malloc");
658335640Shselasky							return -1;
659335640Shselasky						}
660335640Shselasky						/* bzero() is deprecated, replaced with memset() */
661335640Shselasky						memset((char *)s, 0, sizeof(struct sockaddr_in));
662335640Shselasky
663335640Shselasky						addr->netmask = (struct sockaddr *)s;
664335640Shselasky						s->sin_family		= AF_INET;
665335640Shselasky						s->sin_addr.s_addr	= *(bpf_u_int32*)(ptr + 1);
666335640Shselasky						ptr += *ptr;
667335640Shselasky					}
668335640Shselasky					ptr++;
669335640Shselasky					if (*ptr) {												/* process any broadcast address */
670335640Shselasky						if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
671335640Shselasky							pcap_fmt_errmsg_for_errno(errbuf,
672335640Shselasky							    PCAP_ERRBUF_SIZE,
673335640Shselasky							    errno, "malloc");
674335640Shselasky							return -1;
675335640Shselasky						}
676335640Shselasky						/* bzero() is deprecated, replaced with memset() */
677335640Shselasky						memset((char *)s, 0, sizeof(struct sockaddr_in));
678335640Shselasky
679335640Shselasky						addr->broadaddr = (struct sockaddr *)s;
680335640Shselasky						s->sin_family		= AF_INET;
681335640Shselasky						s->sin_addr.s_addr	= *(bpf_u_int32*)(ptr + 1);
682335640Shselasky						ptr += *ptr;
683335640Shselasky					}
684335640Shselasky					ptr++;
685335640Shselasky					if (*ptr) {												/* process any destination address */
686335640Shselasky						if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
687335640Shselasky							pcap_fmt_errmsg_for_errno(errbuf,
688335640Shselasky							    PCAP_ERRBUF_SIZE,
689335640Shselasky							    errno, "malloc");
690335640Shselasky							return -1;
691335640Shselasky						}
692335640Shselasky						/* bzero() is deprecated, replaced with memset() */
693335640Shselasky						memset((char *)s, 0, sizeof(struct sockaddr_in));
694335640Shselasky
695335640Shselasky						addr->dstaddr = (struct sockaddr *)s;
696335640Shselasky						s->sin_family		= AF_INET;
697335640Shselasky						s->sin_addr.s_addr	= *(bpf_u_int32*)(ptr + 1);
698335640Shselasky						ptr += *ptr;
699335640Shselasky					}
700335640Shselasky					ptr++;
701335640Shselasky					prev_addr = addr;
702335640Shselasky				}
703335640Shselasky				prev_iff = iff;
704335640Shselasky
705335640Shselasky				newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType);		/* add a translation entry and get a point to the mangled name */
706335640Shselasky				bigger_buffer = realloc(iff->name, strlen(newname) + 1));
707335640Shselasky				if (bigger_buffer == NULL) {	/* we now re-write the name stored in the interface list */
708335640Shselasky					pcap_fmt_errmsg_for_errno(errbuf,
709335640Shselasky					    PCAP_ERRBUF_SIZE, errno, "realloc");
710335640Shselasky					return -1;
711335640Shselasky				}
712335640Shselasky				iff->name = bigger_buffer;
713335640Shselasky				strcpy(iff->name, newname);												/* to this new name */
714335640Shselasky			}
715335640Shselasky		}
716335640Shselasky	}
717335640Shselasky	return 0;
718335640Shselasky}
719335640Shselasky
720335640Shselaskystatic int read_client_data (int fd) {
721335640Shselasky	unsigned char	buf[256];
722335640Shselasky	int				chassis, geoslot;
723335640Shselasky	unit_t			*u;
724335640Shselasky	int				len;
725335640Shselasky
726335640Shselasky	find_unit_by_fd(fd, &chassis, &geoslot, &u);
727335640Shselasky
728335640Shselasky	if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0)	return 0;	/* read in whatever data was sent to us */
729335640Shselasky
730335640Shselasky	if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL)	/* extend the buffer for the new data */
731335640Shselasky		return 0;
732335640Shselasky	memcpy((u->imsg + u->len), buf, len);						/* append the new data */
733335640Shselasky	u->len += len;
734335640Shselasky	return 1;
735335640Shselasky}
736335640Shselasky
737335640Shselaskystatic void wait_for_all_answers(void) {
738335640Shselasky	int		retval;
739335640Shselasky	struct	timeval tv;
740335640Shselasky	int		fd;
741335640Shselasky	int		chassis, geoslot;
742335640Shselasky
743335640Shselasky	tv.tv_sec = 2;
744335640Shselasky	tv.tv_usec = 0;
745335640Shselasky
746335640Shselasky	while (1) {
747335640Shselasky		int flag = 0;
748335640Shselasky		fd_set working_set;
749335640Shselasky
750335640Shselasky		for (fd = 0; fd <= max_fs; fd++) {								/* scan the list of descriptors we may be listening to */
751335640Shselasky			if (FD_ISSET(fd, &readfds)) flag = 1;						/* and see if there are any still set */
752335640Shselasky		}
753335640Shselasky		if (flag == 0) return;											/* we are done, when they are all gone */
754335640Shselasky
755335640Shselasky		memcpy(&working_set, &readfds, sizeof(readfds));				/* otherwise, we still have to listen for more stuff, till we timeout */
756335640Shselasky		retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
757335640Shselasky		if (retval == -1) {												/* an error occured !!!!! */
758335640Shselasky			return;
759335640Shselasky		} else if (retval == 0) {										/* timeout occured, so process what we've got sofar and return */
760335640Shselasky			printf("timeout\n");
761335640Shselasky			return;
762335640Shselasky		} else {
763335640Shselasky			for (fd = 0; fd <= max_fs; fd++) {							/* scan the list of things to do, and do them */
764335640Shselasky				if (FD_ISSET(fd, &working_set)) {
765335640Shselasky					if (read_client_data(fd) == 0) {					/* if the socket has closed */
766335640Shselasky						FD_CLR(fd, &readfds);							/* and descriptors we listen to for errors */
767335640Shselasky						find_unit_by_fd(fd, &chassis, &geoslot, NULL);
768335640Shselasky						close_with_IOP(chassis, geoslot, FIND);			/* and close out connection to him */
769335640Shselasky					}
770335640Shselasky				}
771335640Shselasky			}
772335640Shselasky		}
773335640Shselasky	}
774335640Shselasky}
775335640Shselasky
776335640Shselaskystatic char *get_error_response(int fd, char *errbuf) {		/* return a pointer on error, NULL on no error */
777335640Shselasky	char	byte;
778335640Shselasky	int		len = 0;
779335640Shselasky
780335640Shselasky	while (1) {
781335640Shselasky		recv(fd, &byte, 1, 0);							/* read another byte in */
782335640Shselasky		if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) {		/* and if there is still room in the buffer */
783335640Shselasky			*errbuf++ = byte;							/* stick it in */
784335640Shselasky			*errbuf = '\0';								/* ensure the string is null terminated just in case we might exceed the buffer's size */
785335640Shselasky		}
786335640Shselasky		if (byte == '\0') {
787335640Shselasky			if (len > 1)	{ return errbuf;	}
788335640Shselasky			else			{ return NULL;		}
789335640Shselasky		}
790335640Shselasky	}
791335640Shselasky}
792335640Shselasky
793335640Shselaskyint acn_findalldevs(char *errbuf) {								/* returns: -1 = error, 0 = OK */
794335640Shselasky	int		chassis, geoslot;
795335640Shselasky	unit_t	*u;
796335640Shselasky
797335640Shselasky	FD_ZERO(&readfds);
798335640Shselasky	max_fs = 0;
799335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
800335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
801335640Shselasky			u = &units[chassis][geoslot];
802335640Shselasky			if (u->ip && (open_with_IOP(u, FIND))) {			/* connect to the remote IOP */
803335640Shselasky				send_to_fd(u->find_fd, 1, (unsigned char *)"\0");
804335640Shselasky				if (get_error_response(u->find_fd, errbuf))
805335640Shselasky					close_with_IOP(chassis, geoslot, FIND);
806335640Shselasky				else {
807335640Shselasky					if (u->find_fd > max_fs)
808335640Shselasky						max_fs = u->find_fd;								/* remember the highest number currently in use */
809335640Shselasky					FD_SET(u->find_fd, &readfds);						/* we are going to want to read this guy's response to */
810335640Shselasky					u->len = 0;
811335640Shselasky					send_to_fd(u->find_fd, 1, (unsigned char *)"Q");		/* this interface query request */
812335640Shselasky				}
813335640Shselasky			}
814335640Shselasky		}
815335640Shselasky	}
816335640Shselasky	wait_for_all_answers();
817335640Shselasky	if (process_client_data(errbuf))
818335640Shselasky		return -1;
819335640Shselasky	sort_if_table();
820335640Shselasky	return 0;
821335640Shselasky}
822335640Shselasky
823335640Shselaskystatic int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) {
824335640Shselasky	unsigned char	buf[12];
825335640Shselasky
826335640Shselasky	send_to_fd(handle->fd, 1, (unsigned char *)"S");						/* send the get_stats command to the IOP */
827335640Shselasky
828335640Shselasky	if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1;	/* try reading the required bytes */
829335640Shselasky
830335640Shselasky	ps->ps_recv		= ntohl(*(uint32_t *)&buf[0]);							/* break the buffer into its three 32 bit components */
831335640Shselasky	ps->ps_drop		= ntohl(*(uint32_t *)&buf[4]);
832335640Shselasky	ps->ps_ifdrop	= ntohl(*(uint32_t *)&buf[8]);
833335640Shselasky
834335640Shselasky	return 0;
835335640Shselasky}
836335640Shselasky
837335640Shselaskystatic int acn_open_live(const char *name, char *errbuf, int *linktype) {		/* returns 0 on error, else returns the file descriptor */
838335640Shselasky	int			chassis, geoslot;
839335640Shselasky	unit_t		*u;
840335640Shselasky	iface_t		*p;
841335640Shselasky	pcap_if_list_t	devlist;
842335640Shselasky
843335640Shselasky	pcap_platform_finddevs(&devlist, errbuf);
844335640Shselasky	for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {										/* scan the table... */
845335640Shselasky		for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
846335640Shselasky			u = &units[chassis][geoslot];
847335640Shselasky			if (u->ip != NULL) {
848335640Shselasky				p = u->iface;
849335640Shselasky				while (p) {																		/* and all interfaces... */
850335640Shselasky					if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) {				/* and if we found the interface we want... */
851335640Shselasky						*linktype = p->iftype;
852335640Shselasky						open_with_IOP(u, LIVE);													/* start a connection with that IOP */
853335640Shselasky						send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname);	/* send the IOP's interface name, and a terminating null */
854335640Shselasky						if (get_error_response(u->fd, errbuf)) {
855335640Shselasky							return -1;
856335640Shselasky						}
857335640Shselasky						return u->fd;															/* and return that open descriptor */
858335640Shselasky					}
859335640Shselasky					p = p->next;
860335640Shselasky				}
861335640Shselasky			}
862335640Shselasky		}
863335640Shselasky	}
864335640Shselasky	return -1;																				/* if the interface wasn't found, return an error */
865335640Shselasky}
866335640Shselasky
867335640Shselaskystatic void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) {
868335640Shselasky	unsigned char	buf[8];
869335640Shselasky	unit_t			*u;
870335640Shselasky
871335640Shselasky	//printf("acn_start_monitor()\n");				// fulko
872335640Shselasky	find_unit_by_fd(fd, NULL, NULL, &u);
873335640Shselasky	if (u->first_time == 0) {
874335640Shselasky		buf[0]					= 'M';
875335640Shselasky		*(uint32_t *)&buf[1]	= htonl(snaplen);
876335640Shselasky		buf[5]					= timeout;
877335640Shselasky		buf[6]					= promiscuous;
878335640Shselasky		buf[7]					= direction;
879335640Shselasky	//printf("acn_start_monitor() first time\n");				// fulko
880335640Shselasky		send_to_fd(fd, 8, buf);								/* send the start monitor command with its parameters to the IOP */
881335640Shselasky		u->first_time = 1;
882335640Shselasky	}
883335640Shselasky	//printf("acn_start_monitor() complete\n");				// fulko
884335640Shselasky}
885335640Shselasky
886335640Shselaskystatic int pcap_inject_acn(pcap_t *p, const void *buf _U_, size_t size _U_) {
887356341Scy	pcap_strlcpy(p->errbuf, "Sending packets isn't supported on ACN adapters",
888335640Shselasky	    PCAP_ERRBUF_SIZE);
889335640Shselasky	return (-1);
890335640Shselasky}
891335640Shselasky
892335640Shselaskystatic int pcap_setfilter_acn(pcap_t *handle, struct bpf_program *bpf) {
893335640Shselasky	int				fd = handle->fd;
894335640Shselasky	int				count;
895335640Shselasky	struct bpf_insn	*p;
896335640Shselasky	uint16_t		shortInt;
897335640Shselasky	uint32_t		longInt;
898335640Shselasky
899335640Shselasky	send_to_fd(fd, 1, (unsigned char *)"F");			/* BPF filter follows command */
900335640Shselasky	count = bpf->bf_len;
901335640Shselasky	longInt = htonl(count);
902335640Shselasky	send_to_fd(fd, 4, (unsigned char *)&longInt);		/* send the instruction sequence count */
903335640Shselasky	p = bpf->bf_insns;
904335640Shselasky	while (count--) {									/* followed by the list of instructions */
905335640Shselasky		shortInt = htons(p->code);
906335640Shselasky		longInt = htonl(p->k);
907335640Shselasky		send_to_fd(fd, 2, (unsigned char *)&shortInt);
908335640Shselasky		send_to_fd(fd, 1, (unsigned char *)&p->jt);
909335640Shselasky		send_to_fd(fd, 1, (unsigned char *)&p->jf);
910335640Shselasky		send_to_fd(fd, 4, (unsigned char *)&longInt);
911335640Shselasky		p++;
912335640Shselasky	}
913335640Shselasky	if (get_error_response(fd, NULL))
914335640Shselasky		return -1;
915335640Shselasky	return 0;
916335640Shselasky}
917335640Shselasky
918335640Shselaskystatic int pcap_setdirection_acn(pcap_t *handle, pcap_direction_t d) {
919335640Shselasky	pcap_snprintf(handle->errbuf, sizeof(handle->errbuf),
920335640Shselasky	    "Setting direction is not supported on ACN adapters");
921335640Shselasky	return -1;
922335640Shselasky}
923335640Shselasky
924335640Shselaskystatic int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
925335640Shselasky	struct		timeval tv;
926335640Shselasky	int			retval, fd;
927335640Shselasky	fd_set		r_fds;
928335640Shselasky	fd_set		w_fds;
929335640Shselasky	u_char		*bp;
930335640Shselasky	int			len = 0;
931335640Shselasky	int			offset = 0;
932335640Shselasky
933335640Shselasky	tv.tv_sec = 5;
934335640Shselasky	tv.tv_usec = 0;
935335640Shselasky
936335640Shselasky	fd = handle->fd;
937335640Shselasky	FD_ZERO(&r_fds);
938335640Shselasky	FD_SET(fd, &r_fds);
939335640Shselasky	memcpy(&w_fds, &r_fds, sizeof(r_fds));
940335640Shselasky	bp = handle->bp;
941335640Shselasky	while (count) {
942335640Shselasky		retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
943335640Shselasky		if (retval == -1) {											/* an error occured !!!!! */
944335640Shselasky//			fprintf(stderr, "error during packet data read\n");
945335640Shselasky			return -1;												/* but we need to return a good indication to prevent unneccessary popups */
946335640Shselasky		} else if (retval == 0) {									/* timeout occured, so process what we've got sofar and return */
947335640Shselasky//			fprintf(stderr, "timeout during packet data read\n");
948335640Shselasky			return -1;
949335640Shselasky		} else {
950335640Shselasky			if ((len = recv(fd, (bp + offset), count, 0)) <= 0) {
951335640Shselasky//				fprintf(stderr, "premature exit during packet data rx\n");
952335640Shselasky				return -1;
953335640Shselasky			}
954335640Shselasky			count -= len;
955335640Shselasky			offset += len;
956335640Shselasky		}
957335640Shselasky	}
958335640Shselasky	return 0;
959335640Shselasky}
960335640Shselasky
961335640Shselaskystatic int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) {
962335640Shselasky	#define HEADER_SIZE (4 * 4)
963335640Shselasky	unsigned char		packet_header[HEADER_SIZE];
964335640Shselasky	struct pcap_pkthdr	pcap_header;
965335640Shselasky
966335640Shselasky	//printf("pcap_read_acn()\n");			// fulko
967335640Shselasky	acn_start_monitor(handle->fd, handle->snapshot, handle->opt.timeout, handle->opt.promisc, handle->direction);	/* maybe tell him to start monitoring */
968335640Shselasky	//printf("pcap_read_acn() after start monitor\n");			// fulko
969335640Shselasky
970335640Shselasky	handle->bp = packet_header;
971335640Shselasky	if (acn_read_n_bytes_with_timeout(handle, HEADER_SIZE) == -1) return 0;			/* try to read a packet header in so we can get the sizeof the packet data */
972335640Shselasky
973335640Shselasky	pcap_header.ts.tv_sec	= ntohl(*(uint32_t *)&packet_header[0]);				/* tv_sec */
974335640Shselasky	pcap_header.ts.tv_usec	= ntohl(*(uint32_t *)&packet_header[4]);				/* tv_usec */
975335640Shselasky	pcap_header.caplen		= ntohl(*(uint32_t *)&packet_header[8]);				/* caplen */
976335640Shselasky	pcap_header.len			= ntohl(*(uint32_t *)&packet_header[12]);				/* len */
977335640Shselasky
978335640Shselasky	handle->bp = (u_char *)handle->buffer + handle->offset;									/* start off the receive pointer at the right spot */
979335640Shselasky	if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0;	/* then try to read in the rest of the data */
980335640Shselasky
981335640Shselasky	callback(user, &pcap_header, handle->bp);										/* call the user supplied callback function */
982335640Shselasky	return 1;
983335640Shselasky}
984335640Shselasky
985335640Shselaskystatic int pcap_activate_sita(pcap_t *handle) {
986335640Shselasky	int		fd;
987335640Shselasky
988335640Shselasky	if (handle->opt.rfmon) {
989335640Shselasky		/*
990335640Shselasky		 * No monitor mode on SITA devices (they're not Wi-Fi
991335640Shselasky		 * devices).
992335640Shselasky		 */
993335640Shselasky		return PCAP_ERROR_RFMON_NOTSUP;
994335640Shselasky	}
995335640Shselasky
996335640Shselasky	/* Initialize some components of the pcap structure. */
997335640Shselasky
998335640Shselasky	handle->inject_op = pcap_inject_acn;
999335640Shselasky	handle->setfilter_op = pcap_setfilter_acn;
1000335640Shselasky	handle->setdirection_op = pcap_setdirection_acn;
1001335640Shselasky	handle->set_datalink_op = NULL;	/* can't change data link type */
1002335640Shselasky	handle->getnonblock_op = pcap_getnonblock_fd;
1003335640Shselasky	handle->setnonblock_op = pcap_setnonblock_fd;
1004335640Shselasky	handle->cleanup_op = pcap_cleanup_acn;
1005335640Shselasky	handle->read_op = pcap_read_acn;
1006335640Shselasky	handle->stats_op = pcap_stats_acn;
1007335640Shselasky
1008335640Shselasky	fd = acn_open_live(handle->opt.device, handle->errbuf,
1009335640Shselasky	    &handle->linktype);
1010335640Shselasky	if (fd == -1)
1011335640Shselasky		return PCAP_ERROR;
1012335640Shselasky
1013335640Shselasky	/*
1014335640Shselasky	 * Turn a negative snapshot value (invalid), a snapshot value of
1015335640Shselasky	 * 0 (unspecified), or a value bigger than the normal maximum
1016335640Shselasky	 * value, into the maximum allowed value.
1017335640Shselasky	 *
1018335640Shselasky	 * If some application really *needs* a bigger snapshot
1019335640Shselasky	 * length, we should just increase MAXIMUM_SNAPLEN.
1020335640Shselasky	 */
1021335640Shselasky	if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
1022335640Shselasky		handle->snapshot = MAXIMUM_SNAPLEN;
1023335640Shselasky
1024335640Shselasky	handle->fd = fd;
1025335640Shselasky	handle->bufsize = handle->snapshot;
1026335640Shselasky
1027335640Shselasky	/* Allocate the buffer */
1028335640Shselasky
1029335640Shselasky	handle->buffer	 = malloc(handle->bufsize + handle->offset);
1030335640Shselasky	if (!handle->buffer) {
1031335640Shselasky		pcap_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
1032335640Shselasky		    errno, "malloc");
1033335640Shselasky		pcap_cleanup_acn(handle);
1034335640Shselasky		return PCAP_ERROR;
1035335640Shselasky	}
1036335640Shselasky
1037335640Shselasky	/*
1038335640Shselasky	 * "handle->fd" is a socket, so "select()" and "poll()"
1039335640Shselasky	 * should work on it.
1040335640Shselasky	 */
1041335640Shselasky	handle->selectable_fd = handle->fd;
1042335640Shselasky
1043335640Shselasky	return 0;
1044335640Shselasky}
1045335640Shselasky
1046335640Shselaskypcap_t *pcap_create_interface(const char *device _U_, char *ebuf) {
1047335640Shselasky	pcap_t *p;
1048335640Shselasky
1049335640Shselasky	p = pcap_create_common(ebuf, 0);
1050335640Shselasky	if (p == NULL)
1051335640Shselasky		return (NULL);
1052335640Shselasky
1053335640Shselasky	p->activate_op = pcap_activate_sita;
1054335640Shselasky	return (p);
1055335640Shselasky}
1056335640Shselasky
1057335640Shselaskyint pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf) {
1058335640Shselasky
1059335640Shselasky	//printf("pcap_findalldevs()\n");				// fulko
1060335640Shselasky
1061335640Shselasky	*alldevsp = 0;												/* initialize the returned variables before we do anything */
1062335640Shselasky	strcpy(errbuf, "");
1063335640Shselasky	if (acn_parse_hosts_file(errbuf))							/* scan the hosts file for potential IOPs */
1064335640Shselasky		{
1065335640Shselasky		//printf("pcap_findalldevs() returning BAD after parsehosts\n");				// fulko
1066335640Shselasky		return -1;
1067335640Shselasky		}
1068335640Shselasky	//printf("pcap_findalldevs() got hostlist now finding devs\n");				// fulko
1069335640Shselasky	if (acn_findalldevs(errbuf))								/* then ask the IOPs for their monitorable devices */
1070335640Shselasky		{
1071335640Shselasky		//printf("pcap_findalldevs() returning BAD after findalldevs\n");				// fulko
1072335640Shselasky		return -1;
1073335640Shselasky		}
1074335640Shselasky	devlistp->beginning = acn_if_list;
1075335640Shselasky	acn_if_list = 0;											/* then forget our list head, because someone will call pcap_freealldevs() to empty the malloc'ed stuff */
1076335640Shselasky	//printf("pcap_findalldevs() returning ZERO OK\n");				// fulko
1077335640Shselasky	return 0;
1078335640Shselasky}
1079335640Shselasky
1080335640Shselasky/*
1081335640Shselasky * Libpcap version string.
1082335640Shselasky */
1083335640Shselaskyconst char *
1084335640Shselaskypcap_lib_version(void)
1085335640Shselasky{
1086335640Shselasky	return PCAP_VERSION_STRING " (SITA-only)";
1087335640Shselasky}
1088