dect
/
libpcap
Archived
13
0
Fork 0

SITA ACN support, from Fulko Hew.

This commit is contained in:
guy 2007-10-20 01:15:14 +00:00
parent 3a0937cfba
commit bb9a52d915
13 changed files with 2058 additions and 9 deletions

View File

@ -34,6 +34,7 @@ Additional people who have contributed patches:
Erik de Castro Lopo <erik.de.castro.lopo@sensorynetworks.com>
Florent Drouin <Florent.Drouin@alcatel-lucent.fr>
Franz Schaefer <schaefer@mond.at>
Fulko Hew <fulko.hew@gmail.com>
Gianluca Varenni <varenni@netgroup-serv.polito.it>
Gilbert Hoyek <gil_hoyek@hotmail.com>
Gisle Vanem <giva@bgnett.no>

5
FILES
View File

@ -13,6 +13,7 @@ README.hpux
README.linux
README.macosx
README.septel
README.sita
README.tru64
README.Win32
SUNOS4/nit_if.o.sparc
@ -38,6 +39,7 @@ fad-getad.c
fad-gifc.c
fad-glifc.c
fad-null.c
fad-sita.c
fad-win32.c
filtertest.c
findalldevstest.c
@ -101,6 +103,9 @@ pcap-pf.c
pcap-pf.h
pcap-septel.c
pcap-septel.h
pcap-sita.h
pcap-sita.c
pcap-sita.html
pcap-stdinc.h
pcap-snit.c
pcap-snoop.c

View File

@ -1,4 +1,4 @@
@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.21 2007-09-22 02:10:17 guy Exp $ (LBL)
@(#) $Header: /tcpdump/master/libpcap/INSTALL.txt,v 1.22 2007-10-20 01:15:14 guy Exp $ (LBL)
To build libpcap, run "./configure" (a shell script). The configure
script will determine your system attributes and generate an
@ -309,6 +309,7 @@ README.hpux - notes on using libpcap on HP-UX
README.linux - notes on using libpcap on Linux
README.macosx - notes on using libpcap on Mac OS X
README.septel - notes on using libpcap to capture on Intel/Septel devices
README.sita - notes on using libpcap to capture on SITA devices
README.tru64 - notes on using libpcap on Digital/Tru64 UNIX
README.Win32 - notes on using libpcap on Win32 systems (with WinPcap)
SUNOS4 - pre-SunOS 4.1 replacement kernel nit modules
@ -332,6 +333,7 @@ fad-getad.c - pcap_findalldevs() for systems with getifaddrs()
fad-gifc.c - pcap_findalldevs() for systems with only SIOCGIFLIST
fad-glifc.c - pcap_findalldevs() for systems with SIOCGLIFCONF
fad-null.c - pcap_findalldevs() for systems without capture support
fad-sita.c - pcap_findalldevs() for systems with SITA support
fad-win32.c - pcap_findalldevs() for WinPcap
filtertest.c - test program for BPF compiler
findalldevstest.c - test program for pcap_findalldevs()
@ -377,6 +379,9 @@ pcap-pf.c - Ultrix and Digital/Tru64 UNIX Packet Filter support
pcap-pf.h - Ultrix and Digital/Tru64 UNIX Packet Filter definitions
pcap-septel.c - Intel/Septel device capture support
pcap-septel.h - Intel/Septel device capture support
pcap-sita.c - SITA device capture support
pcap-sita.h - SITA device capture support
pcap-sita.html - SITA device capture documentation
pcap-stdinc.h - includes and #defines for compiling on Win32 systems
pcap-snit.c - SunOS 4.x STREAMS-based Network Interface Tap support
pcap-snoop.c - IRIX Snoop network monitoring support

61
README.sita Normal file
View File

@ -0,0 +1,61 @@
The following instructions apply if you have a Linux platform and want
libpcap to support the 'ACN' WAN/LAN router product from from SITA
(http://www.sita.aero)
See also the libpcap INSTALL.txt file for further libpcap configuration
options.
These additions/extensions have been made to PCAP to allow it to
capture packets from a SITA ACN device (and potentially others).
To enable its support you need to ensure that the distribution has
a correct configure.in file; that can be created if neccessay by
using the normal autoconf procedure of:
aclocal
autoconf
autoheader
automake
Then run configure with the 'sita' option:
./configure --with-sita
Applications built with libpcap configured in this way will only detect SITA
ACN interfaces and will not capture from the native OS packet stream.
The SITA extension provides a remote datascope operation for capturing
both WAN and LAN protocols. It effectively splits the operation of
PCAP into two halves. The top layer performs the majority of the
work, but interfaces via a TCP session to remote agents that
provide the lower layer functionality of actual sniffing and
filtering. More detailed information regarding the functions and
inter-device protocol and naming conventions are described in detail
in 'pcap-sita.html'.
pcap_findalldevs() reads the local system's /etc/hosts file looking
for host names that match the format of IOP type devices. ie. aaa_I_x_y
and then queries each associated IP address for a list of its WAN and
LAN devices. The local system the aggregates the lists obtained from
each IOP, sorts it, and provides it (to Wireshark et.al) as the
list of monitorable interfaces.
Once a valid interface has been selected, pcap_open() is called
which opens a TCP session (to a well known port) on the target IOP
and tells it to start monitoring.
All captured packets are then forwarded across that TCP session
back to the local 'top layer' for forwarding to the actual
sniffing program (wireshark...)
Note that the DLT_SITA protocol includes a proprietary header
that is documented as part of the SITA dissector of Wireshark
and is also described in 'pcap-sita.html' for posterity sake.
That header provides:
- Packet direction (in/out) (1 octet)
- Link layer hardware signal status (1 octet)
- Transmit/Receive error status (2 octets)
- Encapsulated WAN protocol ID (1 octet)

View File

@ -29,13 +29,13 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @(#) $Header: /tcpdump/master/libpcap/atmuni31.h,v 1.1 2002-07-11 09:06:32 guy Exp $ (LBL)
* @(#) $Header: /tcpdump/master/libpcap/atmuni31.h,v 1.2 2007-10-20 01:15:14 guy Exp $ (LBL)
*/
/* Based on UNI3.1 standard by ATM Forum */
/* ATM traffic types based on VPI=0 and (the following VCI */
#define PPC 0x05 /* Point-to-point signal msg */
#define ATM_PPC 0x05 /* Point-to-point signal msg */
#define BCC 0x02 /* Broadcast signal msg */
#define OAMF4SC 0x03 /* Segment OAM F4 flow cell */
#define OAMF4EC 0x04 /* End-to-end OAM F4 flow cell */

View File

@ -182,6 +182,9 @@
/* target host supports USB sniffing */
#undef PCAP_SUPPORT_USB
/* include ACN support */
#undef SITA
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS

19
configure vendored
View File

@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in Revision: 1.138 .
# From configure.in Revision: 1.139 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61.
#
@ -1289,6 +1289,7 @@ Optional Packages:
--without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
--without-gcc don't use gcc
--with-pcap=TYPE use packet capture TYPE
--with-sita include SITA support
--with-dag[=DIR] include Endace DAG support ("yes", "no" or DIR; default="yes" on BSD and Linux if present)
--with-dag-includes=DIR Endace DAG include directory
--with-dag-libraries=DIR Endace DAG library directory
@ -6341,6 +6342,22 @@ cat >>confdefs.h <<\_ACEOF
_ACEOF
fi
# Check whether --with-sita was given.
if test "${with_sita+set}" = set; then
withval=$with_sita;
cat >>confdefs.h <<\_ACEOF
#define SITA 1
_ACEOF
SSRC="pcap-sita.c"
{ echo "$as_me:$LINENO: Enabling SITA ACN support" >&5
echo "$as_me: Enabling SITA ACN support" >&6;}
V_FINDALLDEVS=sita
fi
;;
dag)

View File

@ -1,4 +1,4 @@
dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.138 2007-10-04 23:06:25 guy Exp $ (LBL)
dnl @(#) $Header: /tcpdump/master/libpcap/configure.in,v 1.139 2007-10-20 01:15:14 guy Exp $ (LBL)
dnl
dnl Copyright (c) 1994, 1995, 1996, 1997
dnl The Regents of the University of California. All rights reserved.
@ -6,7 +6,7 @@ dnl
dnl Process this file with autoconf to produce a configure script.
dnl
AC_REVISION($Revision: 1.138 $)
AC_REVISION($Revision: 1.139 $)
AC_PREREQ(2.50)
AC_INIT(pcap.c)
@ -371,6 +371,13 @@ linux)
AC_MSG_ERROR(version 2 or higher required; see the INSTALL doc for more info)
fi
AC_LBL_TPACKET_STATS
AC_ARG_WITH(sita, [ --with-sita include SITA support],
[
AC_DEFINE(SITA,1,[include ACN support])
SSRC="pcap-sita.c"
AC_MSG_NOTICE(Enabling SITA ACN support)
V_FINDALLDEVS=sita
])
;;
dag)

62
fad-sita.c Normal file
View File

@ -0,0 +1,62 @@
/*
* fad-sita.c: Packet capture interface additions for SITA ACN devices
*
* Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc <fulko.hew@sita.aero>
*
* License: BSD
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* $Id: fad-sita.c */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "pcap-int.h"
extern pcap_if_t *acn_if_list; /* pcap's list of available interfaces */
extern int acn_parse_hosts_file(char *errbuf);
extern int acn_findalldevs(char *errbuf);
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf) {
//printf("pcap_findalldevs()\n"); // fulko
*alldevsp = 0; /* initialize the returned variables before we do anything */
strcpy(errbuf, "");
if (acn_parse_hosts_file(errbuf)) /* scan the hosts file for potential IOPs */
{
//printf("pcap_findalldevs() returning BAD after parsehosts\n"); // fulko
return -1;
}
//printf("pcap_findalldevs() got hostlist now finding devs\n"); // fulko
if (acn_findalldevs(errbuf)) /* then ask the IOPs for their monitorable devices */
{
//printf("pcap_findalldevs() returning BAD after findalldevs\n"); // fulko
return -1;
}
*alldevsp = acn_if_list;
acn_if_list = 0; /* then forget our list head, because someone will call pcap_freealldevs() to empty the malloc'ed stuff */
//printf("pcap_findalldevs() returning ZERO OK\n"); // fulko
return 0;
}

View File

@ -27,7 +27,7 @@
#ifndef lint
static const char rcsid[] _U_ =
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.129 2007-10-05 01:40:14 guy Exp $ (LBL)";
"@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.130 2007-10-20 01:15:14 guy Exp $ (LBL)";
#endif
/*
@ -96,6 +96,10 @@ static const char rcsid[] _U_ =
#include "pcap-bt-linux.h"
#endif
#ifdef SITA
#include "pcap-sita.h"
#endif
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
@ -324,6 +328,12 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
* trying both methods with the newer method preferred.
*/
#ifdef SITA
live_open_ok = acn_open_live((unsigned char *)device, ebuf, &handle->linktype);
handle->md.clear_promisc = promisc;
handle->fd = live_open_ok;
handle->bufsize = handle->snapshot;
#else
if ((err = live_open_new(handle, device, promisc, to_ms, ebuf)) == 1)
live_open_ok = 1;
else if (err == 0) {
@ -331,6 +341,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
if (live_open_old(handle, device, promisc, to_ms, ebuf))
live_open_ok = 1;
}
#endif
if (!live_open_ok) {
/*
* Both methods to open the packet socket failed. Tidy
@ -344,6 +355,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
return NULL;
}
#ifndef SITA
/*
* Compute the buffer size.
*
@ -426,6 +438,7 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
}
handle->bufsize = handle->snapshot;
}
#endif
/* Allocate the buffer */
@ -444,16 +457,22 @@ pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
*/
handle->selectable_fd = handle->fd;
handle->read_op = pcap_read_linux;
handle->inject_op = pcap_inject_linux;
handle->setfilter_op = pcap_setfilter_linux;
handle->setdirection_op = pcap_setdirection_linux;
handle->set_datalink_op = NULL; /* can't change data link type */
handle->getnonblock_op = pcap_getnonblock_fd;
handle->setnonblock_op = pcap_setnonblock_fd;
handle->stats_op = pcap_stats_linux;
handle->close_op = pcap_close_linux;
#ifdef SITA
handle->read_op = pcap_read_acn;
handle->stats_op = pcap_stats_acn;
#else
handle->read_op = pcap_read_linux;
handle->stats_op = pcap_stats_linux;
#endif
return handle;
}
@ -968,6 +987,10 @@ pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
return -1;
}
#ifdef SITA
return acn_setfilter(handle->fd, filter);
#endif
/* Make our private copy of the filter */
if (install_bpf_program(handle, filter) < 0)
@ -1729,6 +1752,11 @@ static void pcap_close_all(void)
static void pcap_close_linux( pcap_t *handle )
{
#ifdef SITA
pcap_close_acn(handle);
return;
#endif
struct pcap *p, *prevp;
struct ifreq ifr;

905
pcap-sita.c Normal file
View File

@ -0,0 +1,905 @@
/*
* pcap-sita.c: Packet capture interface additions for SITA ACN devices
*
* Copyright (c) 2007 Fulko Hew, SITA INC Canada, Inc <fulko.hew@sita.aero>
*
* License: BSD
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* $Id: pcap-sita.c */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "pcap-int.h"
/* non-configureable manifests follow */
#define IOP_SNIFFER_PORT 49152 /* TCP port on the IOP used for 'distributed pcap' usage */
#define MAX_LINE_SIZE 255 /* max size of a buffer/line in /etc/hosts we allow */
#define MAX_CHASSIS 8 /* number of chassis in an ACN site */
#define MAX_GEOSLOT 8 /* max number of access units in an ACN site */
#define FIND 0
#define LIVE 1
typedef struct iface {
struct iface *next; /* a pointer to the next interface */
char *name; /* this interface's name on Wireshark */
char *IOPname; /* this interface's name on an IOP */
uint32_t iftype; /* the type of interface (DLT values) */
} iface_t;
typedef struct unit {
char *ip; /* this unit's IP address (as extracted from /etc/hosts) */
int fd; /* the connection to this unit (if it exists) */
int find_fd; /* a big kludge to avoid my programming limitations since I could have this unit open for findalldevs purposes */
int first_time; /* 0 = just opened via acn_open_live(), ie. the first time, NZ = nth time */
struct sockaddr_in *serv_addr; /* the address control block for comms to this unit */
int chassis;
int geoslot;
iface_t *iface; /* a pointer to a linked list of interface structures */
char *imsg; /* a pointer to an inbound message */
int len; /* the current size of the inbound message */
} unit_t;
static char *errorString;
static unit_t units[MAX_CHASSIS+1][MAX_GEOSLOT+1]; /* we use indexes of 1 through 8, but we reserve/waste index 0 */
static fd_set readfds; /* a place to store the file descriptors for the connections to the IOPs */
static fd_set working_set;
static int max_fs;
static char static_buf[32];
pcap_if_t *acn_if_list; /* pcap's list of available interfaces */
static void dump_interface_list() {
pcap_if_t *iff;
pcap_addr_t *addr;
int longest_name_len = 0;
char *n, *d, *f;
int if_number = 0;
iff = acn_if_list;
while (iff) {
if (iff->name && (strlen(iff->name) > longest_name_len)) longest_name_len = strlen(iff->name);
iff = iff->next;
}
iff = acn_if_list;
printf("Interface List:\n");
while (iff) {
n = (iff->name) ? iff->name : "";
d = (iff->description) ? iff->description : "";
f = (iff->flags == PCAP_IF_LOOPBACK) ? "L" : "";
printf("%3d: %*s %s '%s'\n", if_number++, longest_name_len, n, f, d);
addr = iff->addresses;
while (addr) {
printf("%*s ", (5 + longest_name_len), ""); /* add some indentation */
printf("%15s ", (addr->addr) ? inet_ntoa(((struct sockaddr_in *)addr->addr)->sin_addr) : "");
printf("%15s ", (addr->netmask) ? inet_ntoa(((struct sockaddr_in *)addr->netmask)->sin_addr) : "");
printf("%15s ", (addr->broadaddr) ? inet_ntoa(((struct sockaddr_in *)addr->broadaddr)->sin_addr) : "");
printf("%15s ", (addr->dstaddr) ? inet_ntoa(((struct sockaddr_in *)addr->dstaddr)->sin_addr) : "");
printf("\n");
addr = addr->next;
}
iff = iff->next;
}
}
static dump(unsigned char *ptr, int i, int indent) {
fprintf(stderr, "%*s", indent, " ");
for (; i > 0; i--) {
fprintf(stderr, "%2.2x ", *ptr++);
}
fprintf(stderr, "\n");
}
static void dump_interface_list_p() {
pcap_if_t *iff;
pcap_addr_t *addr;
int longest_name_len = 0;
char *n, *d, *f;
int if_number = 0;
iff = acn_if_list;
printf("Interface Pointer @ %p is %p:\n", &acn_if_list, iff);
while (iff) {
printf("%3d: %p %p next: %p\n", if_number++, iff->name, iff->description, iff->next);
dump((unsigned char *)iff, sizeof(pcap_if_t), 5);
addr = iff->addresses;
while (addr) {
printf(" %p %p %p %p, next: %p\n", addr->addr, addr->netmask, addr->broadaddr, addr->dstaddr, addr->next);
dump((unsigned char *)addr, sizeof(pcap_addr_t), 10);
addr = addr->next;
}
iff = iff->next;
}
}
static void dump_unit_table() {
int chassis, geoslot;
iface_t *p;
printf("%c:%c %s %s\n", 'C', 'S', "fd", "IP Address");
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL)
printf("%d:%d %2d %s\n", chassis, geoslot, units[chassis][geoslot].fd, units[chassis][geoslot].ip);
p = units[chassis][geoslot].iface;
while (p) {
char *n = (p->name) ? p->name : "";
char *i = (p->IOPname) ? p->IOPname : "";
p = p->next;
printf(" %12s -> %12s\n", i, n);
}
}
}
}
static int find_unit_by_fd(int fd, int *chassis, int *geoslot, unit_t **unit_ptr) {
int c, s;
for (c = 0; c <= MAX_CHASSIS; c++) {
for (s = 0; s <= MAX_GEOSLOT; s++) {
if (units[c][s].fd == fd || units[c][s].find_fd == fd) {
if (chassis) *chassis = c;
if (geoslot) *geoslot = s;
if (unit_ptr) *unit_ptr = &units[c][s];
return 1;
}
}
}
return 0;
}
static int read_client_nbytes(int fd, int count, unsigned char *buf) {
unit_t *u;
int chassis, geoslot;
int len;
find_unit_by_fd(fd, &chassis, &geoslot, &u);
while (count) {
if ((len = recv(fd, buf, count, 0)) <= 0) return -1; /* read in whatever data was sent to us */
count -= len;
buf += len;
} /* till we have everything we are looking for */
return 0;
}
static void empty_unit_iface(unit_t *u) {
iface_t *p, *cur;
cur = u->iface;
while (cur) { /* loop over all the interface entries */
if (cur->name) free(cur->name); /* throwing away the contents if they exist */
if (cur->IOPname) free(cur->IOPname);
p = cur->next;
free(cur); /* then throw away the structure itself */
cur = p;
}
u->iface = 0; /* and finally remember that there are no remaining structure */
}
static void empty_unit(int chassis, int geoslot) {
iface_t *p, *cur;
unit_t *u = &units[chassis][geoslot];
empty_unit_iface(u);
if (u->imsg) { /* then if an inbound message buffer exists */
u->imsg = (char *)realloc(u->imsg, 1); /* and re-allocate the old large buffer into a new small one */
}
}
static void empty_unit_table() {
int chassis, geoslot;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL) {
free(units[chassis][geoslot].ip); /* get rid of the malloc'ed space that holds the IP address */
units[chassis][geoslot].ip = 0; /* then set the pointer to NULL */
}
empty_unit(chassis, geoslot);
}
}
}
static char *find_nth_interface_name(int n) {
int chassis, geoslot;
iface_t *p;
char *last_name = 0;
if (n < 0) n = 0; /* ensure we are working with a valid number */
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
if (units[chassis][geoslot].ip != NULL) {
p = units[chassis][geoslot].iface;
while (p) { /* and all interfaces... */
if (p->IOPname) last_name = p->name; /* remembering the last name found */
if (n-- == 0) return last_name; /* and if we hit the instance requested */
p = p->next;
}
}
}
}
/* if we couldn't fine the selected entry */
if (last_name) return last_name; /* ... but we did have at least one entry... return the last entry found */
return ""; /* ... but if there wasn't any entry... return an empty string instead */
}
int acn_parse_hosts_file(char *errbuf) { /* returns: -1 = error, 0 = OK */
FILE *fp;
char buf[MAX_LINE_SIZE];
char *ptr, *ptr2;
int pos;
int chassis, geoslot;
unit_t *u;
empty_unit_table();
if ((fp = fopen("/etc/hosts", "r")) == NULL) { /* try to open the hosts file and if it fails */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot open '/etc/hosts' for reading."); /* return the nohostsfile error response */
return -1;
}
while (fgets(buf, MAX_LINE_SIZE-1, fp)) { /* while looping over the file */
pos = strcspn(buf, "#\n\r"); /* find the first comment character or EOL */
*(buf + pos) = '\0'; /* and clobber it and anything that follows it */
pos = strspn(buf, " \t"); /* then find the first non-white space */
if (pos == strlen(buf)) /* if there is nothing but white space on the line */
continue; /* ignore that empty line */
ptr = buf + pos; /* and skip over any of that leading whitespace */
if ((ptr2 = strstr(ptr, "_I_")) == NULL) /* skip any lines that don't have names that look like they belong to IOPs */
continue;
if (*(ptr2 + 4) != '_') /* and skip other lines that have names that don't look like ACN components */
continue;
*(ptr + strcspn(ptr, " \t")) = '\0'; /* null terminate the IP address so its a standalone string */
chassis = *(ptr2 + 3) - '0'; /* extract the chassis number */
geoslot = *(ptr2 + 5) - '0'; /* and geo-slot number */
if (chassis < 1 || chassis > MAX_CHASSIS ||
geoslot < 1 || geoslot > MAX_GEOSLOT) { /* if the chassis and/or slot numbers appear to be bad... */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "Invalid ACN name in '/etc/hosts'."); /* warn the user */
continue; /* and ignore the entry */
}
if ((ptr2 = (char *)malloc(strlen(ptr) + 1)) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
continue;
}
strcpy(ptr2, ptr); /* copy the IP address into our malloc'ed memory */
u = &units[chassis][geoslot];
u->ip = ptr2; /* and remember the whole shebang */
u->chassis = chassis;
u->geoslot = geoslot;
}
fclose(fp);
if (*errbuf) return -1;
else return 0;
}
static int open_with_IOP(unit_t *u, int flag) {
int sockfd;
char *ip;
if (u->serv_addr == NULL) {
u->serv_addr = malloc(sizeof(struct sockaddr_in));
}
ip = u->ip;
bzero((char *)u->serv_addr, sizeof(struct sockaddr_in));
u->serv_addr->sin_family = AF_INET;
u->serv_addr->sin_addr.s_addr = inet_addr(ip);
u->serv_addr->sin_port = htons(IOP_SNIFFER_PORT);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "pcap can't open a socket for connecting to IOP at %s\n", ip);
return 0;
}
if (connect(sockfd, (struct sockaddr *)u->serv_addr, sizeof(struct sockaddr_in)) < 0) {
fprintf(stderr, "pcap can't connect to IOP at %s\n", ip);
return 0;
}
if (flag == LIVE) u->fd = sockfd;
else u->find_fd = sockfd;
u->first_time = 0;
return sockfd; /* return the non-zero file descriptor as a 'success' indicator */
}
static void close_with_IOP(int chassis, int geoslot, int flag) {
int *id;
if (flag == LIVE) id = &units[chassis][geoslot].fd;
else id = &units[chassis][geoslot].find_fd;
if (*id) { /* this was the last time, so... if we are connected... */
close(*id); /* disconnect us */
*id = 0; /* and forget that the descriptor exists because we are not open */
}
}
void pcap_close_acn(pcap_t *handle) {
int chassis, geoslot;
unit_t *u;
if (find_unit_by_fd(handle->fd, &chassis, &geoslot, &u) == 0)
return;
close_with_IOP(chassis, geoslot, LIVE);
if (u)
u->first_time = 0;
}
static void send_to_fd(int fd, int len, unsigned char *str) {
int nwritten;
int chassis, geoslot;
while (len > 0) {
if ((nwritten = write(fd, str, len)) <= 0) {
find_unit_by_fd(fd, &chassis, &geoslot, NULL);
if (units[chassis][geoslot].fd == fd) close_with_IOP(chassis, geoslot, LIVE);
else if (units[chassis][geoslot].find_fd == fd) close_with_IOP(chassis, geoslot, FIND);
empty_unit(chassis, geoslot);
return;
}
len -= nwritten;
str += nwritten;
}
}
static void acn_freealldevs() {
pcap_if_t *iff, *next_iff;
pcap_addr_t *addr, *next_addr;
for (iff = acn_if_list; iff != NULL; iff = next_iff) {
next_iff = iff->next;
for (addr = iff->addresses; addr != NULL; addr = next_addr) {
next_addr = addr->next;
if (addr->addr) free(addr->addr);
if (addr->netmask) free(addr->netmask);
if (addr->broadaddr) free(addr->broadaddr);
if (addr->dstaddr) free(addr->dstaddr);
free(addr);
}
if (iff->name) free(iff->name);
if (iff->description) free(iff->description);
free(iff);
}
}
static char *nonUnified_port_num(unit_t *u, int IOPportnum) {
sprintf(static_buf, "%d_%d", u->chassis, u->geoslot);
return static_buf;
}
static char *unified_port_num(unit_t *u, int IOPportnum) {
int portnum;
portnum = ((u->chassis - 1) * 64) + ((u->geoslot - 1) * 8) + IOPportnum + 1;
sprintf(static_buf, "%d", portnum);
return static_buf;
}
static char *translate_IOP_to_pcap_name(unit_t *u, char *IOPname, ulong iftype) {
iface_t *iface_ptr, *iface;
char *name;
char buf[32];
char *proto;
char *port;
int IOPportnum = 0;
iface = malloc(sizeof(iface_t)); /* get memory for a structure */
bzero((char *)iface, sizeof(iface_t));
iface->iftype = iftype; /* remember the interface type of this interface */
name = malloc(strlen(IOPname) + 1); /* get memory for the IOP's name */
strcpy(name, IOPname); /* and copy it in */
iface->IOPname = name; /* and stick it into the structure */
if (strncmp(IOPname, "lo", 2) == 0) {
IOPportnum = atoi(&IOPname[2]);
switch (iftype) {
case DLT_EN10MB: proto = "lo"; port = nonUnified_port_num(u, IOPportnum); break;
default: proto = "???"; port = unified_port_num(u, IOPportnum); break;
}
} else if (strncmp(IOPname, "eth", 3) == 0) {
IOPportnum = atoi(&IOPname[3]);
switch (iftype) {
case DLT_EN10MB: proto = "eth"; port = nonUnified_port_num(u, IOPportnum); break;
default: proto = "???"; port = unified_port_num(u, IOPportnum); break;
}
} else if (strncmp(IOPname, "wan", 3) == 0) {
IOPportnum = atoi(&IOPname[3]);
switch (iftype) {
case DLT_SITA: proto = "wan"; port = unified_port_num(u, IOPportnum); break;
default: proto = "???"; port = unified_port_num(u, IOPportnum); break;
}
}
sprintf(buf, "%s_%s", proto, port); /* compose the user's name for that IOP port name */
name = malloc(strlen(buf) + 1); /* get memory for that name */
strcpy(name, buf); /* and copy it in */
iface->name = name; /* and stick it into the structure */
if (u->iface == 0) { /* if this is the first name */
u->iface = iface; /* stick this entry at the head of the list */
} else {
iface_ptr = u->iface;
while (iface_ptr->next) { /* othewise scan the list */
iface_ptr = iface_ptr->next; /* till we're at the last entry */
}
iface_ptr->next = iface; /* then tack this entry on the end of the list */
}
return iface->name;
}
static int if_sort(char *s1, char *s2) {
char *s1_p2, *s2_p2;
char str1[MAX_LINE_SIZE], str2[MAX_LINE_SIZE];
int s1_p1_len, s2_p1_len;
int retval;
if ((s1_p2 = strchr(s1, '_'))) { /* if an underscore is found... */
s1_p1_len = s1_p2 - s1; /* the prefix length is the difference in pointers */
s1_p2++; /* the suffix actually starts _after_ the underscore */
} else { /* otherwise... */
s1_p1_len = strlen(s1); /* the prefix length is the length of the string itself */
s1_p2 = 0; /* and there is no suffix */
}
if ((s2_p2 = strchr(s2, '_'))) { /* now do the same for the second string */
s2_p1_len = s2_p2 - s2;
s2_p2++;
} else {
s2_p1_len = strlen(s2);
s2_p2 = 0;
}
strncpy(str1, s1, (s1_p1_len > sizeof(str1)) ? s1_p1_len : sizeof(str1)); *(str1 + s1_p1_len) = 0;
strncpy(str2, s2, (s2_p1_len > sizeof(str2)) ? s2_p1_len : sizeof(str2)); *(str2 + s2_p1_len) = 0;
retval = strcmp(str1, str2);
if (retval != 0) return retval; /* if they are not identical, then we can quit now and return the indication */
return strcmp(s1_p2, s2_p2); /* otherwise we return the result of comparing the 2nd half of the string */
}
static void sort_if_table() {
pcap_if_t *p1, *p2, *prev, *temp;
int has_swapped;
if (!acn_if_list) return; /* nothing to do if the list is empty */
while (1) {
p1 = acn_if_list; /* start at the head of the list */
prev = 0;
has_swapped = 0;
while ((p2 = p1->next)) {
if (if_sort(p1->name, p2->name) > 0) {
if (prev) { /* we are swapping things that are _not_ at the head of the list */
temp = p2->next;
prev->next = p2;
p2->next = p1;
p1->next = temp;
} else { /* special treatment if we are swapping with the head of the list */
temp = p2->next;
acn_if_list= p2;
p2->next = p1;
p1->next = temp;
}
p1 = p2;
prev = p1;
has_swapped = 1;
}
prev = p1;
p1 = p1->next;
}
if (has_swapped == 0)
return;
}
return;
}
static int process_client_data (char *errbuf) { /* returns: -1 = error, 0 = OK */
int chassis, geoslot;
unit_t *u;
pcap_if_t *iff, *prev_iff;
pcap_addr_t *addr, *prev_addr;
char *ptr;
int address_count;
struct sockaddr_in *s;
char *newname;
ulong interfaceType;
unsigned char flags;
prev_iff = 0;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) { /* now loop over all the devices */
u = &units[chassis][geoslot];
empty_unit_iface(u);
ptr = u->imsg; /* point to the start of the msg for this IOP */
while (ptr < (u->imsg + u->len)) {
if ((iff = malloc(sizeof(pcap_if_t))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)iff, sizeof(pcap_if_t));
if (acn_if_list == 0) acn_if_list = iff; /* remember the head of the list */
if (prev_iff) prev_iff->next = iff; /* insert a forward link */
if (*ptr) { /* if there is a count for the name */
if ((iff->name = malloc(*ptr + 1)) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memcpy(iff->name, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */
*(iff->name + *ptr) = 0; /* and null terminate the string */
ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */
}
ptr++;
if (*ptr) { /* if there is a count for the description */
if ((iff->description = malloc(*ptr + 1)) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
memcpy(iff->description, (ptr + 1), *ptr); /* copy the name into the malloc'ed space */
*(iff->description + *ptr) = 0; /* and null terminate the string */
ptr += *ptr; /* now move the pointer forwards by the length of the count plus the length of the string */
}
ptr++;
interfaceType = ntohl(*(ulong *)ptr);
ptr += 4; /* skip over the interface type */
flags = *ptr++;
if (flags) iff->flags = PCAP_IF_LOOPBACK; /* if this is a loopback style interface, lets mark it as such */
address_count = *ptr++;
prev_addr = 0;
while (address_count--) {
if ((addr = malloc(sizeof(pcap_addr_t))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)addr, sizeof(pcap_addr_t));
if (iff->addresses == 0) iff->addresses = addr;
if (prev_addr) prev_addr->next = addr; /* insert a forward link */
if (*ptr) { /* if there is a count for the address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) { /* get that amount of space */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)s, sizeof(struct sockaddr_in));
addr->addr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(ulong *)(ptr + 1); /* copy the address in */
ptr += *ptr; /* now move the pointer forwards according to the specified length of the address */
}
ptr++; /* then forwards one more for the 'length of the address' field */
if (*ptr) { /* process any netmask */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)s, sizeof(struct sockaddr_in));
addr->netmask = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(ulong*)(ptr + 1);
ptr += *ptr;
}
ptr++;
if (*ptr) { /* process any broadcast address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)s, sizeof(struct sockaddr_in));
addr->broadaddr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(ulong*)(ptr + 1);
ptr += *ptr;
}
ptr++;
if (*ptr) { /* process any destination address */
if ((s = malloc(sizeof(struct sockaddr_in))) == NULL) {
snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));
return -1;
}
bzero((char *)s, sizeof(struct sockaddr_in));
addr->dstaddr = (struct sockaddr *)s;
s->sin_family = AF_INET;
s->sin_addr.s_addr = *(ulong*)(ptr + 1);
ptr += *ptr;
}
ptr++;
prev_addr = addr;
}
prev_iff = iff;
newname = translate_IOP_to_pcap_name(u, iff->name, interfaceType); /* add a translation entry and get a point to the mangled name */
if ((iff->name = realloc(iff->name, strlen(newname) + 1)) == NULL) { /* we now re-write the name stored in the interface list */
snprintf(errbuf, PCAP_ERRBUF_SIZE, "realloc: %s", pcap_strerror(errno));
return -1;
}
strcpy(iff->name, newname); /* to this new name */
}
}
}
return 0;
}
static int read_client_data (int fd) {
unsigned char buf[256];
int chassis, geoslot;
unit_t *u;
int len;
find_unit_by_fd(fd, &chassis, &geoslot, &u);
if ((len = recv(fd, buf, sizeof(buf), 0)) <= 0) return 0; /* read in whatever data was sent to us */
if ((u->imsg = realloc(u->imsg, (u->len + len))) == NULL) /* extend the buffer for the new data */
return 0;
memcpy((u->imsg + u->len), buf, len); /* append the new data */
u->len += len;
return 1;
}
static void wait_for_all_answers() {
int retval;
struct timeval tv;
int fd;
int chassis, geoslot;
tv.tv_sec = 2;
tv.tv_usec = 0;
while (1) {
int flag = 0;
for (fd = 0; fd <= max_fs; fd++) { /* scan the list of descriptors we may be listening to */
if (FD_ISSET(fd, &readfds)) flag = 1; /* and see if there are any still set */
}
if (flag == 0) return; /* we are done, when they are all gone */
memcpy(&working_set, &readfds, sizeof(readfds)); /* otherwise, we still have to listen for more stuff, till we timeout */
retval = select(max_fs + 1, &working_set, NULL, NULL, &tv);
if (retval == -1) { /* an error occured !!!!! */
return;
} else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
printf("timeout\n");
return;
} else {
for (fd = 0; fd <= max_fs; fd++) { /* scan the list of things to do, and do them */
if (FD_ISSET(fd, &working_set)) {
if (read_client_data(fd) == 0) { /* if the socket has closed */
FD_CLR(fd, &readfds); /* and descriptors we listen to for errors */
find_unit_by_fd(fd, &chassis, &geoslot, NULL);
close_with_IOP(chassis, geoslot, FIND); /* and close out connection to him */
}
}
}
}
}
}
static char *get_error_response(int fd, char *errbuf) { /* return a pointer on error, NULL on no error */
char byte;
int len = 0;
while (1) {
recv(fd, &byte, 1, 0); /* read another byte in */
if (errbuf && (len++ < PCAP_ERRBUF_SIZE)) { /* and if there is still room in the buffer */
*errbuf++ = byte; /* stick it in */
*errbuf = '\0'; /* ensure the string is null terminated just in case we might exceed the buffer's size */
}
if (byte == '\0')
if (len > 1) { return errbuf; }
else { return NULL; }
}
}
int acn_findalldevs(char *errbuf) { /* returns: -1 = error, 0 = OK */
int chassis, geoslot;
unit_t *u;
FD_ZERO(&readfds);
max_fs = 0;
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) {
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
u = &units[chassis][geoslot];
if (u->ip && (open_with_IOP(u, FIND))) { /* connect to the remote IOP */
send_to_fd(u->find_fd, 1, (unsigned char *)"\0");
if (get_error_response(u->find_fd, errbuf))
close_with_IOP(chassis, geoslot, FIND);
else {
if (u->find_fd > max_fs)
max_fs = u->find_fd; /* remember the highest number currently in use */
FD_SET(u->find_fd, &readfds); /* we are going to want to read this guy's response to */
u->len = 0;
send_to_fd(u->find_fd, 1, (unsigned char *)"Q"); /* this interface query request */
}
}
}
}
wait_for_all_answers();
if (process_client_data(errbuf))
return -1;
sort_if_table();
return 0;
}
int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps) {
unsigned char buf[12];
send_to_fd(handle->fd, 1, (unsigned char *)"S"); /* send the get_stats command to the IOP */
if (read_client_nbytes(handle->fd, sizeof(buf), buf) == -1) return -1; /* try reading the required bytes */
ps->ps_recv = ntohl(*(uint32_t *)&buf[0]); /* break the buffer into its three 32 bit components */
ps->ps_drop = ntohl(*(uint32_t *)&buf[4]);
ps->ps_ifdrop = ntohl(*(uint32_t *)&buf[8]);
return 0;
}
int acn_open_live(char *name, char *errbuf, int *linktype) { /* returns 0 on error, else returns the file descriptor */
int chassis, geoslot;
unit_t *u;
iface_t *p;
pcap_if_t *alldevsp;
pcap_findalldevs(&alldevsp, errbuf);
for (chassis = 0; chassis <= MAX_CHASSIS; chassis++) { /* scan the table... */
for (geoslot = 0; geoslot <= MAX_GEOSLOT; geoslot++) {
u = &units[chassis][geoslot];
if (u->ip != NULL) {
p = u->iface;
while (p) { /* and all interfaces... */
if (p->IOPname && p->name && (strcmp(p->name, name) == 0)) { /* and if we found the interface we want... */
*linktype = p->iftype;
open_with_IOP(u, LIVE); /* start a connection with that IOP */
send_to_fd(u->fd, strlen(p->IOPname)+1, (unsigned char *)p->IOPname); /* send the IOP's interface name, and a terminating null */
if (get_error_response(u->fd, errbuf)) {
return 0;
}
return u->fd; /* and return that open descriptor */
}
p = p->next;
}
}
}
}
return 0; /* if the interface wasn't found, return an error */
}
void acn_start_monitor(int fd, int snaplen, int timeout, int promiscuous, int direction) {
unsigned char buf[8];
unit_t *u;
//printf("acn_start_monitor()\n"); // fulko
find_unit_by_fd(fd, NULL, NULL, &u);
if (u->first_time == 0) {
buf[0] = 'M';
*(uint32_t *)&buf[1] = htonl(snaplen);
buf[5] = timeout;
buf[6] = promiscuous;
buf[7] = direction;
//printf("acn_start_monitor() first time\n"); // fulko
send_to_fd(fd, 8, buf); /* send the start monitor command with its parameters to the IOP */
u->first_time = 1;
}
//printf("acn_start_monitor() complete\n"); // fulko
}
int acn_setfilter(int fd, struct bpf_program *bpf) {
int count;
struct bpf_insn *p;
uint16_t shortInt;
uint32_t longInt;
send_to_fd(fd, 1, (unsigned char *)"F"); /* BPF filter follows command */
count = bpf->bf_len;
longInt = htonl(count);
send_to_fd(fd, 4, (unsigned char *)&longInt); /* send the instruction sequence count */
p = bpf->bf_insns;
while (count--) { /* followed by the list of instructions */
shortInt = htons(p->code);
longInt = htonl(p->k);
send_to_fd(fd, 2, (unsigned char *)&shortInt);
send_to_fd(fd, 1, (unsigned char *)&p->jt);
send_to_fd(fd, 1, (unsigned char *)&p->jf);
send_to_fd(fd, 4, (unsigned char *)&longInt);
p++;
}
if (get_error_response(fd, NULL))
return -1;
return 0;
}
int acn_read_n_bytes_with_timeout(pcap_t *handle, int count) {
struct timeval tv;
int retval, fd;
fd_set r_fds;
fd_set w_fds;
u_char *bp;
int len = 0;
int offset = 0;
tv.tv_sec = 5;
tv.tv_usec = 0;
fd = handle->fd;
FD_ZERO(&r_fds);
FD_SET(fd, &r_fds);
memcpy(&w_fds, &r_fds, sizeof(r_fds));
bp = handle->bp;
while (count) {
retval = select(fd + 1, &w_fds, NULL, NULL, &tv);
if (retval == -1) { /* an error occured !!!!! */
// fprintf(stderr, "error during packet data read\n");
return -1; /* but we need to return a good indication to prevent unneccessary popups */
} else if (retval == 0) { /* timeout occured, so process what we've got sofar and return */
// fprintf(stderr, "timeout during packet data read\n");
return -1;
} else {
if ((len = recv(fd, (bp + offset), count, 0)) <= 0) {
// fprintf(stderr, "premature exit during packet data rx\n");
return -1;
}
count -= len;
offset += len;
}
}
return 0;
}
int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user) {
#define HEADER_SIZE (4 * 4)
unsigned char packet_header[HEADER_SIZE];
struct pcap_pkthdr pcap_header;
//printf("pcap_read_acn()\n"); // fulko
acn_start_monitor(handle->fd, handle->snapshot, handle->md.timeout, handle->md.clear_promisc, handle->direction); /* maybe tell him to start monitoring */
//printf("pcap_read_acn() after start monitor\n"); // fulko
handle->bp = packet_header;
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 */
pcap_header.ts.tv_sec = ntohl(*(uint32_t *)&packet_header[0]); /* tv_sec */
pcap_header.ts.tv_usec = ntohl(*(uint32_t *)&packet_header[4]); /* tv_usec */
pcap_header.caplen = ntohl(*(uint32_t *)&packet_header[8]); /* caplen */
pcap_header.len = ntohl(*(uint32_t *)&packet_header[12]); /* len */
handle->bp = handle->buffer + handle->offset; /* start off the receive pointer at the right spot */
if (acn_read_n_bytes_with_timeout(handle, pcap_header.caplen) == -1) return 0; /* then try to read in the rest of the data */
callback(user, &pcap_header, handle->bp); /* call the user supplied callback function */
return 1;
}

12
pcap-sita.h Normal file
View File

@ -0,0 +1,12 @@
/*
* pcap-sita.h: Packet capture interface for SITA WAN devices
*
* Authors: Fulko Hew (fulko.hew@sita.aero) (+1 905 6815570);
*
* @(#) $Header: /tcpdump/master/libpcap/pcap-sita.h
*/
void pcap_close_acn(pcap_t *handle);
int pcap_stats_acn(pcap_t *handle, struct pcap_stat *ps);
int pcap_read_acn(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user);

943
pcap-sita.html Normal file
View File

@ -0,0 +1,943 @@
<HTML><HEAD>
<STYLE type="text/css">
<!--
A { text-decoration:none }
-->
</STYLE>
</HEAD>
<BODY>
<TABLE WIDTH=100%><TR>
<TD ALIGN=LEFT VALIGN=TOP>
<FONT SIZE=+0 FACE="COURIER"><B>A "Distributed Pcap" for<BR>Remote Monitoring LANs & WANs</B><BR>
(Design Notes for the SITA ACN device)</FONT>
</TD>
<TD ALIGN=RIGHT VALIGN=TOP>
Fulko Hew<BR>SITA INC Canada, Inc.<BR>Revised: October 2, 2007
</TD>
</TR></TABLE>
<H3>SUMMARY</H3>
<UL>
<STRONG>Note:</STRONG> This document is part of the libpcap CVS and was derived from 'pcap.3' (circa Aug/07).
<P>
The ACN provides a customized/distributed version of this library that alows SMPs to
interact with the various IOPs within the site providing a standard mechanism
to capture LAN and WAN message traffic.
<P>
<CENTER>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3 WIDTH=75%>
<TR>
<TH VALIGN=TOP>SMP</TH>
<TD VALIGN=TOP>The Supervisory Management Processor where Wireshark (or equivalent)
runs in conjuction with a libpcap front-end.</TD>
</TR>
<TR>
<TH VALIGN=TOP>IOP</TH>
<TD VALIGN=TOP>I/O Processors where the monitored ports exist in conjunction
with a custom device driver/libpcap back-end.</TD>
</TR>
</TABLE>
</CENTER>
<P>
Each IOP will be capable of supporting multiple connections from an SMP
enabling monitoring of more than one interface at a time, each through
its own seperate connection. The IOP is responsible to ensure and report
an error if any attempt is made to monitor the same interface more than once.
<P>
There are three applications that will be supported by the ACN version of libpcap.
They each use a slightly different mode for looping/capturing and termination
as summarized in the following table:
<P>
<CENTER>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR><TH>Application</TH> <TH>Capture</TH> <TH>Termination</TH></TR>
<TR><TH VALIGN=TOP NOWRAP>wireshark</TH>
<TD VALIGN=TOP>pcap_dispatch(all packets in one buffer of capture only)</TD>
<TD VALIGN=TOP>pcap_breakloop()</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>tshark</TH>
<TD VALIGN=TOP>pcap_dispatch(one buffer of capture only)</TD>
<TD VALIGN=TOP>Since a CTRL-C was used to terminate the application, pcap_breakloop() is never called.</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>tcpdump</TH>
<TD VALIGN=TOP>pcap_loop(all packets in the next buffer, and loop forever)</TD>
<TD VALIGN=TOP>pcap_breakloop()</TD>
</TR>
</TABLE>
</CENTER>
<P>
<B>Note: </B>In all cases, the termination of capturing is always (apparently) followed by
pcap_close(). Pcap_breakloop() is only used to stop/suspend looping/processing,
and upon close interpretation of the function definitions, it is possible to resume
capturing following a pcap_breakloop() without any re-initialization.
<P>
<H4>ACN Limitations</H4>
<OL>
<LI>Monitoring of backup IOPs is not currently supported.
<LI>Ethernet interfaces cannot be monitored in promiscuous mode.
</OL>
</UL>
<H3>ROUTINES</H3>
<UL>
The following list of functions is the sub-set of Pcap functions that have been
altered/enhanced to support the ACN remote monitoring facility. The remainder of the Pcap
functions continue to perform their duties un-altered. Libpcap only supports this
mode of operation if it has been configured/compiled for SITA/ACN support.
<P>
<UL><FONT FACE=COURIER>
pcap_findalldevs<BR>
pcap_freealldevs<BR>
pcap_open_live<BR>
pcap_close<BR>
pcap_setfilter<BR>
pcap_dispatch<BR>
pcap_loop<BR>
pcap_next<BR>
pcap_next_ex<BR>
pcap_stats<BR>
</FONT></UL>
These subroutines have been modified for the ACN specific distributed and remote monitoring
ability perform the following basic functions. More detail is provided in the
"SMP/IOP Inter-Process Communication Protocol" section.
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_open_live()</B></TD>
<TD VALIGN=TOP>Used to obtain a packet capture descriptor to look at packets on the network.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP will open a connection to the selected IOP on its 'sniffer' port
to ensure it is available. It sends a null terminated string identifying
the interface to be monitored.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
After any required processing is complete, the IOP will return a
null terminated string containing an error message if one occured.
If no error occured, a empty string is still returned.
Errors are:
<UL>
<LI>"Interface (xxx) does not exist."
<LI>"Interface (xxx) not configured."
<LI>"Interface (xxx) already being monitored."
</UL>
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_findalldevs()</B></TD>
<TD VALIGN=TOP>It constructs a list of network devices that can be opened with pcap_open_live().</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
It obtains a list of IOPs currently available (via /etc/hosts).
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP will sequentially open a connection to each IOP on its 'sniffer' port to ensure
the IOP is available.
It sends a null terminated empty interface ID followed by the query request command.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>The IOP returns an error response and its list of devices.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP closes the TCP connection with each IOP.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP adds the received information to its internal structure.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_freealldevs()</B></TD>
<TD VALIGN=TOP>Used to free a list allocated by pcap_findalldevs().</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP frees the structure it built as a result of the previous
invocation of pcap_findalldevs().
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_dispatch()</B></TD>
<TD VALIGN=TOP>Used to collect and process packets.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(),
the SMP will pass down the monitor start command and various parameters the IOP should use.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP now sends a stream of captured data.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP will read the reverse channel of the connection between the SMP and the
IOP that provides the captured data (via 'p->read_op' which is 'pcap_read_linux()'
until the select() call returns a 'no more data' indication.
It will the process (at most) the next 'cnt' packets and invoke the specified
callback function for each packet processed.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
<TD>
The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_loop()</B></TD>
<TD VALIGN=TOP>
Is similar to pcap_dispatch() except it keeps reading packets until
the requested number of packets are processed or an error occurs.
</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(),
the SMP will pass down the monitor start command and various parameters the IOP should use.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP now sends a stream of captured data.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP continuously reads the next packet from the reverse channel of the connection
between the SMP and the IOP that provides the captured data (via 'p->read_op'
which is 'pcap_read_linux()' until 'cnt' packets have been received.
The specified callback function will be invoked for each packet received.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
<TD>
The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_next()</B></TD>
<TD VALIGN=TOP>
It reads the next packet (by calling pcap_dispatch() with a count of 1)
and returns a pointer to the data in that packet.
</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(),
the SMP will pass down the monitor start command and various parameters the IOP should use.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP now sends a stream of captured data.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP reads only the next packet from the reverse channel of the connection
between the SMP and the IOP that provides the captured data (via calling pcap_dispatch()
with a count of 1) and returns a pointer to that data by invoking an internal callback.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
<TD>
The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_next_ex()</B></TD>
<TD VALIGN=TOP>Reads the next packet and returns a success/failure indication.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
On the first invocation of pcap_dispatch(), pcap_loop(), or pcap_next(), or pcap_next_ex() following a pcap_open_live(),
the SMP will pass down the monitor start command and various parameters the IOP should use.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP now sends a stream of captured data.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP reads only the next packet from the reverse channel of the connection
between the SMP and the IOP that provides the captured data (via calling pcap_dispatch()
with a count of 1) and returns seperate pointers to both the
packet header and packet data by invoking an internal callback.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
<TD>
The IOP continues to listen for additional commands as well as capturing and forwarding data to the SMP.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_setfilter()</B></TD>
<TD VALIGN=TOP>Used to specify a filter program.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP sends a 'set filter' command followed by the BPF commands.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP returns a null terminated error string if it failed to accept the filter.
If no error occured, then a NULL terminated empty string is returned instead.
Errors are:
<UL>
<LI>"Invalid BPF."
<LI>"Insufficient resources for BPF."
</UL>
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_stats()</B></TD>
<TD VALIGN=TOP>Fills in a pcap_stat struct with packet statistics.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP sends a message to the IOP requesting its statistics.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP -> SMP</TH>
<TD>
The IOP returns the statistics.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>SMP</TH>
<TD>
The SMP fills in the structure provided with the information retrieved from the IOP.
</TD>
</TR>
</TABLE></TD></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2><B>pcap_close()</B></TD>
<TD VALIGN=TOP>Closes the file and deallocates resources.</TD>
</TR>
<TR><TD><TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
<TR><TH VALIGN=TOP NOWRAP>SMP -> IOP</TH>
<TD>
The SMP closes the file descriptor, and if the descriptor is that of
the comminucation session with an IOP, it too is terminated.
</TD>
</TR>
<TR><TH VALIGN=TOP NOWRAP>IOP</TH>
<TD>
If the IOP detects that its communication session with an SMP
has closed, it will terminate any monitoring in progress,
release any resources and close its end of the session.
It will not maintain persistance of any information or prior mode of operation.
</TD>
</TR>
</TABLE></TD></TR>
</TABLE>
</UL>
<P>
<H3>SMP/IOP Inter-Process Communication Protocol</H3>
<UL>
<LI><P>Communications between an SMP and an IOP consists of a TCP session
between an ephemeral port on the SMP and the well known port of 49152
(which is the first available port in the 'dynamic and/or private port'
range) on an IOP.
<LI><P>Following a TCP open operation the IOP receives a null terminated
'interface ID' string to determine the type of operation that follows:
<LI><P>Every command received by an IOP implies a 'stop trace/stop forwarding' operation must
occur before executing the received command.
<LI><P>A session is closed when the SMP closes the TCP session with the IOP.
Obviously monitoring and forwarding is also stopped at that time.
<B>Note: </B>All multi-octet entities are sent in network neutral order.
<P>
<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=5>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=6>pcap_findalldevs()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>Open socket (to each IOP), and sends:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>Interface ID</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>A NULL to indicate an an empty 'interface ID'.</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>Send its (possibly empty) NULL terminated error response string.</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>Sends the 'interface query request':
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>Interface ID</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>A 'Q' (indicating 'interface query request').</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>The IOP returns a list of sequences of information as
defined by the return parameter of this function call (as shown in the following table).
Elements are specified by providing an unsigned byte preceeding the actual data that contains length information.
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Notes:</TH>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD ROWSPAN=7>&nbsp;</TD>
<TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the name field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Name</TD>
<TD VALIGN=TOP ALIGN=CENTER>1-255</TD>
<TD VALIGN=TOP>The name of the interface. The format of the name is an alphabetic string (indicating
the type of interface) followed by an optional numeric string (indicating the interface's
sequence number).
Sequence numbers (if needed) will begin at zero and progress monotonically upwards.
(i.e. 'eth0', 'lo', 'wan0', etc.)
<P>
For an IOP, the alphabetic string will be one of: 'eth', 'wan', and 'lo'
for Ethernet, WAN ports and the IP loopback device respectively.
An IOP currently supports: 'eth0', 'eth1', 'lo', 'wan0' ... 'wan7'.
<P>
<B>Note:</B> IOPs and ACNs will not currently support the concept of 'any' interface.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the interface description field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Interface Description</TD>
<TD VALIGN=TOP ALIGN=CENTER>0-255</TD>
<TD VALIGN=TOP>A description of the interface or it may be an empty string. (i.e. 'ALC')</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Interface Type</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The type of interface as defined in the description for pcap_datalink() (in network neutral order).</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Loopback Flag</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>1 = if the interface is a loopback interface, zero = otherwise.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=RIGHT>count</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP># of address entries that follow.
Each entry is a series of bytes in network neutral order.
See the parameter definition above for more details.</TD>
</TR>
<TR>
<TD ALIGN=CENTER ROWSPAN=8 WIDTH=1%>Repeated 'count' number of times.</TD>
<TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the address field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Address</TD>
<TD VALIGN=TOP ALIGN=CENTER>1-255</TD>
<TD VALIGN=TOP>The address of this interface (in network neutral order).</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the netmask field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Network Mask</TD>
<TD VALIGN=TOP ALIGN=CENTER>0-255</TD>
<TD VALIGN=TOP>The network mask used on this interface (if applicable) (in network neutral order).</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the broadcast address field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Broadcast Address</TD>
<TD VALIGN=TOP ALIGN=CENTER>0-255</TD>
<TD VALIGN=TOP>The broadcast address of this interface (if applicable) (in network neutral order).</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=RIGHT>length</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The number of octets in the destination address field that follows.</TD>
</TR>
<TR><TD VALIGN=TOP ALIGN=LEFT>Destination Address</TD>
<TD VALIGN=TOP ALIGN=CENTER>0-255</TD>
<TD VALIGN=TOP>The destination address of this interface (if applicable) (in network neutral order).</TD>
</TR>
</TABLE>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>Close the socket.</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>Close the socket.</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2>pcap_open_live()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>Open socket, and sends:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>Interface ID</TD>
<TD VALIGN=TOP ALIGN=CENTER>'n'</TD>
<TD VALIGN=TOP>'n' octets containing a NULL terminated interface name string.</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>Send its NULL terminated error response string.</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP NOWRAP ROWSPAN=2>pcap_dispatch()<BR>pcap_loop()<BR>pcap_next()<BR>pcap_next_ex()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>On the first invocation following a pcap_open_live() or pcap_breakloop() additional information is sent:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>command</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>'M' (indicating 'monitor start')</TD>
</TR>
<TR>
<TD VALIGN=TOP>snaplen</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>snaplen</TD>
</TR>
<TR>
<TD VALIGN=TOP>timeout</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>timeout value (in milliseconds)</TD>
</TR>
<TR>
<TD VALIGN=TOP>promiscuous</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>A flag indicating that the interface being monitored show operate
in promiscuous mode. [off(0) / on(NZ)]</TD>
</TR>
<TR>
<TD VALIGN=TOP>direction</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>A flag indicating the direction of traffic that should be captuted [both(0) / in(1) / out(2)]</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>Sends captured packets.</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2>pcap_setfilter()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>At any time, the SMP can issue a set filter command which contains
an indicator, a count of the number of statements in the filter,
followed by the sequence of filter commands represented as a sequence
of C-style structures.
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>command</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>'F' (indicating 'filter')</TD>
</TR>
<TR>
<TD VALIGN=TOP>count</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The number of command in the Berkeley Packet Filter that follow.</TD>
</TR>
<TR>
<TD VALIGN=TOP>BPF program</TD>
<TD VALIGN=TOP ALIGN=CENTER>'n'</TD>
<TD VALIGN=TOP>8 bytes of each command (repeated 'n' times).<BR>
Each command consists of that C-style structure which contains:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>opcode</TD>
<TD VALIGN=TOP ALIGN=CENTER>2</TD>
<TD VALIGN=TOP>The command's opcode.</TD>
</TR>
<TR>
<TD VALIGN=TOP>'jt'</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The 'jump if true' program counter offset.</TD>
</TR>
<TR>
<TD VALIGN=TOP>'jf'</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>The 'jump if false' program counter offset.</TD>
</TR>
<TR>
<TD VALIGN=TOP>'k'</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The 'other' data field.</TD>
</TR>
</TABLE>
<P>
Refer to the bpf(4) man page for more details.
</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>In return the IOP will send its (possibly empty) NULL terminated error response string.</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=2>pcap_stats()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>At any time, the SMP can issue a 'retrieve statistics' command which contains:<BR>
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>command</TD>
<TD VALIGN=TOP ALIGN=CENTER>1</TD>
<TD VALIGN=TOP>'S' (indicating 'request statistics')</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>IOP -> SMP</TD>
<TD VALIGN=TOP>In return the IOP will send:
<P>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TH VALIGN=TOP ALIGN=CENTER>Name/<BR>Purpose</TH>
<TH VALIGN=TOP ALIGN=CENTER NOWRAP>Size<BR>(in bytes)</TH>
<TH VALIGN=TOP ALIGN=CENTER>Description</TH>
</TR>
<TR>
<TD VALIGN=TOP>ps_recv</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The number of packets that passed the filter.</TD>
</TR>
<TR>
<TD VALIGN=TOP>ps_drop</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The number of packets that were dropped because the input queue was full,
regardless of whether they passed the filter.</TD>
</TR>
<TR>
<TD VALIGN=TOP>ps_ifdrop</TD>
<TD VALIGN=TOP ALIGN=CENTER>4</TD>
<TD VALIGN=TOP>The number of packets dropped by the network inteface
(regardless of whether they would have passed the input filter).</TD>
</TR>
</TABLE>
</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
<TR>
<TD VALIGN=TOP ROWSPAN=1>pcap_close()</TD>
<TD VALIGN=TOP ALIGN=CENTER NOWRAP>SMP -> IOP</TD>
<TD VALIGN=TOP>At any time, the SMP can close the TCP session with the IOP.</TD>
</TR>
<TR><TH COLSPAN=3><HR WIDTH=100%></TH></TR>
</TABLE>
</UL>
<H3>Interface ID Naming Convention</H3>
<UL>
Each interface within an IOP will be referred to uniquely. Since an currently contains
8 monitorable WAN ports and a monitorable Ethernet port, the naming convention is:
<P>
<CENTER>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR><TH>Interface #</TH> <TH>Type</TH> <TH>Name</TH></TR>
<TR><TD ALIGN=CENTER>1</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan0</TD></TR>
<TR><TD ALIGN=CENTER>2</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan1</TD></TR>
<TR><TD ALIGN=CENTER>3</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan2</TD></TR>
<TR><TD ALIGN=CENTER>4</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan3</TD></TR>
<TR><TD ALIGN=CENTER>5</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan4</TD></TR>
<TR><TD ALIGN=CENTER>6</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan5</TD></TR>
<TR><TD ALIGN=CENTER>7</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan6</TD></TR>
<TR><TD ALIGN=CENTER>8</TD> <TD ALIGN=CENTER>WAN</TD> <TD ALIGN=CENTER>wan7</TD></TR>
<TR><TD ALIGN=CENTER>9</TD> <TD ALIGN=CENTER>Ethernet</TD> <TD ALIGN=CENTER>eth0</TD></TR>
<TR><TD ALIGN=CENTER>10</TD> <TD ALIGN=CENTER>Ethernet</TD> <TD ALIGN=CENTER>eth1</TD></TR>
</TABLE>
</CENTER>
</UL>
<H3>Packet Trace Data Format</H3>
<UL>
The format of the trace data that is sent to the SMP follows a portion of the libpcap file format
and is summarized here. This format specifies the generic requirements needed to
be able to decode packets, but does not cover ACN specifics such as custom MAC addressing
and WAN protocol support.
<P>
Although a libpcap file begins with a global header followed by zero or
more records for each captured packet, trace data sent to the SMP does NOT begin with a global header.
A trace sequence looks like this:
<P>
<TABLE>
<TR>
<TD STYLE="background-color: #c0FFc0">&nbsp;[Packet Header]&nbsp;</TD>
<TD STYLE="background-color: #c0FFc0">&nbsp;[Packet Data]&nbsp;</TD>
<TD STYLE="background-color: #c0c0FF">&nbsp;[Packet Header]&nbsp;</TD>
<TD STYLE="background-color: #c0c0FF">&nbsp;[Packet Data]&nbsp;</TD>
<TD STYLE="background-color: #e0c0c0">&nbsp;[Packet Header]&nbsp;</TD>
<TD STYLE="background-color: #e0c0c0">&nbsp;[Packet Data]&nbsp;</TD>
<TD>...</TD>
</TR>
</TABLE>
<H4>Packet Header</H4>
<UL>
Each captured packet starts with a header that contains the following values
(in network neutral order):
<FONT SIZE=-1>
<PRE>
uint32 tv_sec; /* timestamp seconds */
uint32 tv_usec; /* timestamp microseconds */
uint32 caplen; /* number of octets in the following packet */
uint32 len; /* original length of packet on the wire */
</PRE>
</FONT>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR>
<TD VALIGN=TOP>tv_sec</TD>
<TD>The date and time when this packet was captured.
This value is in seconds since January 1, 1970 00:00:00 GMT;
this is also known as a UN*X time_t. You can use the ANSI C
<em>time()</em> function from <em>time.h</em> to get this value,
but you might use a more optimized way to get this timestamp value.
If this timestamp isn't based on GMT (UTC), use <em>thiszone</em>
from the global header for adjustments.</TD>
</TR>
<TR>
<TD VALIGN=TOP>tv_usec</TD>
<TD>The microseconds when this packet was captured, as an offset to <em>ts_sec</em>.
<B>Beware: </B>this value must never reach 1 second (1,000,000),
in this case <em>ts_sec</em> must be increased instead!</TD>
</TR>
<TR>
<TD VALIGN=TOP>caplen</TD>
<TD>The number of bytes actually provided in the capture record.
This value should never become larger than <em>len</em> or the
<em>snaplen</em> value specified during the capture.</TD>
</TR>
<TR>
<TD VALIGN=TOP>len</TD>
<TD>The length of the packet "on the wire" when it was captured.
If <em>caplen</em> and <em>len</em> differ, the actually
saved packet size was limited by the value of <em>snaplen</em> specified
during one of the capture directives such as pcap_dispatch().</TD>
</TR>
</TABLE>
</UL>
<H4>Packet Data</H4>
<UL>
The actual packet data will immediately follow the packet header as a sequence of <em>caplen</em> octets.
Depending on the DLT encoding number assigned to the interface, the packet data will contain an additional
custom header used to convey WAN port related information.
</UL>
<H4>ACN Custom Packet Header</H4>
<UL>
PCAP, Wireshark and Tcpdump enhancements have been added to the ACN to support
monitoring of its ports, however each of these facilities were focused on capturing
and displaying traffic from LAN interfaces. The SITA extentions to these facilities
are used to also provide the ability to capture, filter, and display information from
an ACN's WAN ports.
<P>
Although each packet follows the standard libpcap format, since there are
two types of interfaces that can be monitored, the format of the data
packet varies slightly.
<P>
<UL TYPE=DISC>
<LI>For Ethernet (like) devices, the packet format is unchanged from the standard Pcap format.
<LI>For WAN devices, the packet contains a 5 byte header that preceeds the actual captured data
described by the following table:
</UL>
<P>
<CENTER>
<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=3>
<TR> <TH>Octet</TH>
<TH>Name</TH>
<TH>Mask/Value</TH>
<TH COLSPAN=2>Definition</TH> </TR>
<TR> <TH VALIGN=TOP ALIGN=CENTER ROWSPAN=3>0</TH>
<TH VALIGN=TOP ALIGN=CENTER ROWSPAN=3>Control / Status</TH>
<TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxxx0</FONT></TD>
<TD>Transmitted by capture device</TD>
<TD ROWSPAN=2 ALIGN=CENTER>(see 'Errors' octets)</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxxx1</FONT></TD>
<TD>Received by capture device</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">1xxxxxxx</FONT></TD>
<TD COLSPAN=2>No buffer was available during capture of previous packet.</TD> </TR>
<TR> <TH VALIGN=TOP ALIGN=CENTER ROWSPAN=8>1</TH>
<TH VALIGN=TOP ALIGN=CENTER ROWSPAN=8>Signals</TH>
<TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxxx1</FONT></TD> <TD COLSPAN=2>DSR asserted</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxx1x</FONT></TD> <TD COLSPAN=2>DTR asserted</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxx1xx</FONT></TD> <TD COLSPAN=2>CTS asserted</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxx1xxx</FONT></TD> <TD COLSPAN=2>RTS asserted</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxx1xxxx</FONT></TD> <TD COLSPAN=2>DCD asserted</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xx1xxxxx</FONT></TD> <TD COLSPAN=2>Undefined</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">x1xxxxxx</FONT></TD> <TD COLSPAN=2>Undefined</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">1xxxxxxx</FONT></TD> <TD COLSPAN=2>Undefined</TD> </TR>
<TR> <TH VALIGN=TOP ALIGN=CENTER ROWSPAN=9>2</TH>
<TH VALIGN=TOP ALIGN=CENTER ROWSPAN=9>Errors<BR>(octet 1)</TH>
<TH>&nbsp;</TH> <TH>Tx</TH> <TH>Rx</TH> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxxx1</FONT></TD> <TD>Underrun</TD> <TD>Framing</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxx1x</FONT></TD> <TD>CTS Lost</TD> <TD>Parity</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxx1xx</FONT></TD> <TD>UART Error</TD> <TD>Collision</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxx1xxx</FONT></TD> <TD>Re-Tx Limit Reached</TD> <TD>Long Frame</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxx1xxxx</FONT></TD> <TD>Undefined</TD> <TD>Short Frame</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xx1xxxxx</FONT></TD> <TD>Undefined</TD> <TD>Undefined</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">x1xxxxxx</FONT></TD> <TD>Undefined</TD> <TD>Undefined</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">1xxxxxxx</FONT></TD> <TD>Undefined</TD> <TD>Undefined</TD> </TR>
<TR> <TH VALIGN=TOP ALIGN=CENTER ROWSPAN=9>3</TH>
<TH VALIGN=TOP ALIGN=CENTER ROWSPAN=9>Errors<BR>(octet 2)</TH>
<TH>&nbsp;</TH> <TH>Tx</TH> <TH>Rx</TH> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxxx1</FONT></TD> <TD>Undefined</TD> <TD>Non-Octet Aligned</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxxx1x</FONT></TD> <TD>Undefined</TD> <TD>Abort Received</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxxx1xx</FONT></TD> <TD>Undefined</TD> <TD>CD Lost</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxxx1xxx</FONT></TD> <TD>Undefined</TD> <TD>Digital PLL Error</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xxx1xxxx</FONT></TD> <TD>Undefined</TD> <TD>Overrun</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">xx1xxxxx</FONT></TD> <TD>Undefined</TD> <TD>Frame Length Violation</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">x1xxxxxx</FONT></TD> <TD>Undefined</TD> <TD>CRC Error</TD> </TR>
<TR> <TD VALIGN=TOP ALIGN=CENTER><FONT FACE="COURIER">1xxxxxxx</FONT></TD> <TD>Undefined</TD> <TD>Break Received</TD> </TR>
<TR> <TH VALIGN=TOP ALIGN=CENTER ROWSPAN=12>4</TH>
<TH VALIGN=TOP ALIGN=CENTER>Protocol</TH>
<TD COLSPAN=3>
<CENTER>
<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x01</TD> <TD>-</TD> <TD>LAPB (BOP) <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x02</TD> <TD>-</TD> <TD>Ethernet <SUP>1</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x03</TD> <TD>-</TD> <TD>Async (Interrupt IO) <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x04</TD> <TD>-</TD> <TD>Async (Block IO) <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x05</TD> <TD>-</TD> <TD>IPARS <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x06</TD> <TD>-</TD> <TD>UTS <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x07</TD> <TD>-</TD> <TD>PPP (HDLC) <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x08</TD> <TD>-</TD> <TD>SDLC <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x09</TD> <TD>-</TD> <TD>Token Ring <SUP>1</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x10</TD> <TD>-</TD> <TD>I2C <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x11</TD> <TD>-</TD> <TD>DPM Link <SUP>&nbsp;</SUP> </TD> </TR>
<TR VALIGN=BOTTOM><TD ALIGN=CENTER>0x12</TD> <TD>-</TD> <TD>Frame Relay (BOP) <SUP>&nbsp;</SUP> </TD> </TR>
</TABLE>
</CENTER>
<P>
<STRONG>Note 1:</STRONG>
Ethernet and Token Ring frames will never be sent as DLT_SITA (with the 5 octet header),
but will be sent as their corresponding DLT types instead.
</TD>
</TR>
</TABLE>
</CENTER>
</UL>
<P>
</UL>
</UL>