owlps/infrastructure-centred/owlps-listener/owlps-listenerd.c

747 lines
22 KiB
C
Raw Normal View History

/*
* This file is part of the rtap localisation project.
*/
#include "owlps-listener.h"
2010-07-13 15:09:07 +02:00
char *program_name = NULL ;
unsigned char mac[6] ; // AP MAC address
int aggregation_sockfd ;
struct sockaddr_in aggregation_server ;
#ifdef USE_CONFIG_FILE
cfg_t *cfg ; // Configuration structure
#else // USE_CONFIG_FILE
/* If we do not use libconfuse, we declare a structure to store getopt
* options.
*/
struct {
char mode ;
char aggregation_ip[16] ;
long aggregation_port ;
long listening_port ;
#ifdef USE_PTHREAD
BOOL keep_monitor ;
#endif // USE_PTHREAD
char rtap_iface[IFNAMSIZ + 1] ;
char wifi_iface[IFNAMSIZ + 1] ;
BOOL verbose ;
} options = { // Initalise default options:
MODE_ACTIVE,
"127.0.0.1",
AGGREGATE_DEFAULT_PORT,
LOC_REQUEST_DEFAULT_PORT,
#ifdef USE_PTHREAD
FALSE,
#endif // USE_PTHREAD
"",
"",
FALSE
} ;
#endif // USE_CONFIG_FILE
int main(int argc, char *argv[])
{
struct sigaction action ; // Signal handler structure
char *mac_string ; // AP MAC (string value)
int ret ; // Program return value
#ifdef USE_PTHREAD
pthread_t thread ; // Thread pour le repassage en mode monitor
#endif // USE_PTHREAD
2010-07-13 15:09:07 +02:00
program_name = argv[0] ;
initialise_configuration(argc, argv) ;
run = TRUE ;
/* Set up signal handlers */
sigemptyset(&action.sa_mask) ;
action.sa_handler = sigint_handler ;
sigaction(SIGINT, &action, NULL) ;
action.sa_handler = sigterm_handler ;
sigaction(SIGTERM, &action, NULL) ;
#ifdef USE_PTHREAD
/* Set up thread */
if (GET_KEEP_MONITOR())
pthread_create(&thread, NULL,
(void *) &keep_mode_monitor, GET_WIFI_IFACE()) ;
#endif // USE_PTHREAD
get_mac_addr(GET_WIFI_IFACE(), mac) ;
mac_string = mac_bytes_to_string(mac) ;
printf("My MAC address is: %s\n", mac_string) ;
free(mac_string) ;
ret = capture() ; // Capture loop
#ifdef USE_CONFIG_FILE
cfg_free(cfg) ; // Clean configuration
#endif // USE_CONFIG_FILE
printf("%s: end.\n", program_name) ;
return ret ;
}
void initialise_configuration(int argc, char **argv)
{
parse_config_file(argc, argv) ;
parse_command_line(argc, argv) ;
check_configuration() ;
#ifdef DEBUG
print_configuration() ;
#endif // DEBUG
}
void parse_config_file(int argc, char **argv)
{
#ifdef USE_CONFIG_FILE
// If we use libconfuse, we declare options:
cfg_opt_t opts[] =
{
// Listening mode: a for active, p for passive, m for mixed
// (default: a):
CFG_INT("mode", MODE_ACTIVE, CFGF_NONE),
// IP address of the aggregator (default: loopback):
CFG_STR("aggregation_ip", "127.0.0.1", CFGF_NONE),
// Port on which the aggregator listens:
CFG_INT("aggregation_port", AGGREGATE_DEFAULT_PORT, CFGF_NONE),
// Port on which mobiles send active requests:
CFG_INT("listening_port", LOC_REQUEST_DEFAULT_PORT, CFGF_NONE),
#ifdef USE_PTHREAD
// Activate the active monitor mode keeping-up (read the code if
// you do not understand what I mean):
CFG_BOOL("keep_monitor", cfg_false, CFGF_NONE),
#endif // USE_PTHREAD
// Radiotap interface, used to capture:
CFG_STR("rtap_iface", "", CFGF_NONE),
// Physical interface corresponding to the radiotap interface (used
// to get the MAC address):
CFG_STR("wifi_iface", "", CFGF_NONE),
// Display capture packets, or not:
CFG_BOOL("verbose", cfg_false, CFGF_NONE),
CFG_END()
} ;
char *config_file ; // Configuration file name
#endif // USE_CONFIG_FILE
// Option -f specifies a config file, so we search for it first
2010-07-13 15:09:07 +02:00
int opt ;
do
opt = getopt(argc, argv, OPTIONS) ;
while (opt != 'f' && opt != -1) ;
if (opt == 'f')
{
#ifdef USE_CONFIG_FILE
config_file = malloc((strlen(optarg) + 1) * sizeof(char)) ;
strcpy(config_file, optarg) ;
#else // USE_CONFIG_FILE
fprintf(stderr, "Warning! Program was not compiled with"
" configuration file support, so -f is not available. You"
" must specify all options on the command line, or default"
" value will be used.\n") ;
#endif // USE_CONFIG_FILE
}
#ifdef USE_CONFIG_FILE
else // If -f isn't found, we use the default config file
{
config_file =
malloc((strlen(DEFAULT_CONFIG_FILE) + 1) * sizeof(char)) ;
strcpy(config_file, DEFAULT_CONFIG_FILE) ;
}
/* Parse config file */
cfg = cfg_init(opts, CFGF_NONE) ; // Initialise options
switch (cfg_parse(cfg, config_file))
{
case CFG_FILE_ERROR :
fprintf(stderr,
"Error! Cannot open configuration file « %s »: %s.\n",
config_file, strerror(errno)) ;
break ;
case CFG_PARSE_ERROR :
fprintf(stderr,
"Error! Parsing of configuration file « %s » failed!\n",
config_file) ;
free(config_file) ;
exit(ERR_PARSING_CONFIG_FILE) ;
}
free(config_file) ;
#endif // USE_CONFIG_FILE
2010-07-13 15:09:07 +02:00
}
2010-07-13 15:09:07 +02:00
void parse_command_line(int argc, char **argv)
{
int opt ;
optind = 1 ; // Rewind argument parsing
2010-07-13 15:09:07 +02:00
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'd' :
SET_AGGREGATION_IP(optarg) ;
break ;
case 'f' : // Config file
break ; // (already parsed)
2010-07-13 14:42:33 +02:00
case 'h' :
2010-07-13 15:09:07 +02:00
print_usage() ;
2010-07-13 14:42:33 +02:00
exit(0) ;
case 'k' :
#ifdef USE_PTHREAD
SET_KEEP_MONITOR() ;
#else // USE_PTHREAD
fprintf(stderr, "Warning! The program was compiled without"
" support of POSIX threads, so -k (monitor mode"
" keeping-up) is not available and will be ignored."
"\n") ;
#endif // USE_PTHREAD
break ;
case 'l' :
SET_LISTENING_PORT(strtol(optarg, NULL, 0)) ;
break ;
case 'm' :
SET_MODE(optarg[0]) ;
break ;
case 'p' :
SET_AGGREGATION_PORT(strtol(optarg, NULL, 0)) ;
break ;
case 'q' :
UNSET_VERBOSE() ;
break ;
case 'r' :
SET_RTAP_IFACE(optarg) ;
break ;
case 'v' :
SET_VERBOSE() ;
break ;
case 'w' :
SET_WIFI_IFACE(optarg) ;
break ;
default :
2010-07-13 15:09:07 +02:00
print_usage() ;
exit(ERR_BAD_USAGE) ;
}
}
2010-07-13 15:09:07 +02:00
}
2010-07-13 15:09:07 +02:00
void check_configuration()
{
switch (GET_MODE())
{
case MODE_ACTIVE :
case MODE_MIXED :
case MODE_PASSIVE :
break ;
default :
fprintf(stderr, "Error! Unknown mode « %c ».\n", (char) GET_MODE()) ;
2010-07-13 15:09:07 +02:00
print_usage() ;
exit(ERR_BAD_USAGE) ;
}
if (GET_RTAP_IFACE()[0] == '\0')
{
fprintf(stderr, "Error! You must specify a radiotap interface"
" for the capture.\n") ;
2010-07-13 15:09:07 +02:00
print_usage() ;
exit(ERR_BAD_USAGE) ;
}
if (GET_WIFI_IFACE()[0] == '\0')
{
#ifdef DEBUG
fprintf(stderr, "Warning! No Wi-Fi was specified. Failing back to"
" the radiotap interface (%s) instead.\n",
GET_RTAP_IFACE()) ;
#endif // DEBUG
SET_WIFI_IFACE(GET_RTAP_IFACE()) ;
}
2010-07-13 15:09:07 +02:00
}
#ifdef DEBUG
2010-07-13 15:09:07 +02:00
void print_configuration()
{
fprintf(stderr, "Configuration:\n") ;
#ifdef USE_CONFIG_FILE
cfg_print(cfg, stderr) ;
#else // USE_CONFIG_FILE
fprintf(stderr,
"aggregation_ip = \"%s\"\n"
"aggregation_port = %ld\n"
"listening_port = %ld\n"
"rtap_iface = \"%s\"\n"
"wifi_iface = \"%s\"\n"
,
GET_AGGREGATION_IP(),
GET_AGGREGATION_PORT(),
GET_LISTENING_PORT(),
GET_RTAP_IFACE(),
GET_WIFI_IFACE()
);
#ifdef USE_PTHREAD
fprintf(stderr, "keep_monitor = %s\n",
GET_KEEP_MONITOR() ? "true" : "false"
) ;
#endif // USE_PTHREAD
#endif // USE_CONFIG_FILE
}
2010-07-13 15:09:07 +02:00
#endif // DEBUG
#ifdef USE_PTHREAD
/*
* Thread function. Switches interface 'iface' to monitor mode every
* second.
*/
void* keep_mode_monitor(char *iface)
{
while (run)
{
iface_mode_monitor(iface) ; // Switch the interface to monitor mode
sleep(1) ; // Wait for 1 second
}
pthread_exit(NULL) ;
}
#endif // USE_PTHREAD
/*
* Captures packets using the radiotap interface.
* Captured data is transmitted to the aggregator.
*/
int capture()
{
pcap_t *handle ; // Packet capture descriptor
char errbuf[PCAP_ERRBUF_SIZE] ; // Error message
// Start capture:
handle = pcap_open_live(GET_RTAP_IFACE(), BUFSIZ, 1, 1000, errbuf) ;
if (handle == NULL) // Capture starting failed
{
fprintf(stderr, "Cannot open interface « %s »: %s\n",
GET_RTAP_IFACE(), errbuf) ;
return ERR_OPENING_IFACE ;
}
/* Open UDP socket to the aggregator */
aggregation_sockfd =
owlps_create_socket_to_aggregator(GET_AGGREGATION_IP(),
GET_AGGREGATION_PORT(),
&aggregation_server, NULL) ;
while(run)
// Capture one packet at time, and call read_packet() on it:
pcap_loop(handle, 1, read_packet, NULL) ;
pcap_close(handle) ; // Stop capture
(void) close(aggregation_sockfd) ; // Close socket
return 0 ;
}
/*
* Treats a packet and sends it to the aggregator.
*/
void read_packet(u_char *args, const struct pcap_pkthdr *header,
const u_char *packet)
{
// Copy packet address into data:
unsigned char *data = (unsigned char *) packet ;
unsigned short rtap_bytes ; // Received data size
unsigned int
rtap_presentflags,
rtap_position ;
couple_message couple ; // Message to send to the aggregator
ssize_t nsent ; // sendto return value
BOOL check[15] ; // Present flags
unsigned char raw_packet_type ; // Received packet type (beacon, data…)
unsigned char raw_packet_flags ; // IEEE 802.11 header flags
unsigned short llc_packet_type = 0 ;
// Pointer to the (possible) IP header of the packet:
struct iphdr *packet_ip_header = NULL ;
// Pointer to the (possible) UDP header of the packet:
struct udphdr *packet_udp_header = NULL ;
char packet_type ; // Localisation request type (request, calibration)
BOOL is_explicit_packet = TRUE ; // Is the packet an explicit request?
int i ; // Iterator
/* Common treatements */
// Copy 2 bytes from the 3rd data byte, that is the size of the rtap
// header (changes with the flags):
memcpy(&rtap_bytes, &data[2], sizeof(unsigned short)) ;
2010-07-02 13:04:00 +02:00
rtap_bytes = ntohs(rtap_bytes) ;
// After the rtap header, there is the 802.11 header; the first byte
// is the packet type (beacon or not):
raw_packet_type = data[rtap_bytes] ;
if (raw_packet_type == RAW_PACKET_TYPE_DATA) // Data packet
{
// Get the packet type (protocol, 2 bytes) from the LLC header:
memcpy((unsigned char*) &llc_packet_type,
&data[rtap_bytes + IEEE80211_HEADER_SIZE + 6], 2) ;
llc_packet_type = ntohs(llc_packet_type) ;
if (llc_packet_type == ETH_P_IP) // IP packet
{
packet_ip_header = (struct iphdr *)
&data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE] ;
// Get the source IP:
memcpy(couple.mobile_ip_addr_bytes, &packet_ip_header->saddr, 4) ;
if (GET_MODE() != MODE_PASSIVE) // If mode is active or mixed
{
// Protocol for an explicit request is UDP
if (packet_ip_header->protocol == IPPROTO_UDP)
{ // Check destination port:
packet_udp_header = (struct udphdr *)
&data[rtap_bytes + IEEE80211_HEADER_SIZE +
LLC_HEADER_SIZE + sizeof(struct iphdr)] ;
if (ntohs(packet_udp_header->dest) !=
GET_LISTENING_PORT())
{
if (GET_MODE() == MODE_ACTIVE)
return ;
is_explicit_packet = FALSE ;
}
}
}
}
else if (GET_MODE() != MODE_ACTIVE) // Passive or mixed mode
{
is_explicit_packet = FALSE ;
bzero(couple.mobile_ip_addr_bytes, 4) ; // Blank the IP
}
else // Active mode and not an IP packet, so it is not a request
return ;
}
else // Packet is not data, so it is not a localisation request
{
if (GET_MODE() == MODE_ACTIVE)
return ;
is_explicit_packet = FALSE ;
}
// Get 802.11 flags from the 802.11 header:
raw_packet_flags = data[rtap_bytes+1] ;
#ifdef DEBUG
printf("raw_packet_flags: %02x\n", raw_packet_flags) ;
if (IS_RETRY(raw_packet_flags))
printf("This packet is a Retry.\n") ;
#endif // DEBUG
memcpy(couple.ap_mac_addr_bytes, mac, 6) ; // Copy AP MAC
// Source MAC address is 10 bytes after the 802.11 packet type:
memcpy(couple.mobile_mac_addr_bytes, &data[rtap_bytes+10], 6) ;
couple.start_time = header->ts ; // Capture time is in the pcap header
// Transmission time on the mobile is unknown (unless the packet is
// an explicit request):
couple.request_time.tv_sec = 0 ;
couple.request_time.tv_usec = 0 ;
/* Active mode */
if (is_explicit_packet
&& (GET_MODE() == MODE_ACTIVE || GET_MODE() == MODE_MIXED)
// FIXME: should we really ignore Retries?
&& ! IS_RETRY(raw_packet_flags))
{
packet_type =
data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE
+ sizeof(struct iphdr) + sizeof(struct udphdr)] ;
switch(packet_type)
{
case PACKET_TYPE_NORMAL :
if (GET_VERBOSE())
printf("\nExplicit packet received.\n") ;
couple.direction = 0 ;
couple.x_position = 0 ;
couple.y_position = 0 ;
couple.z_position = 0 ;
break ;
case PACKET_TYPE_CALIBRATION :
if (GET_VERBOSE())
printf("\nExplicite calibration packet received.\n") ;
couple.direction =
data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE
+ sizeof(struct iphdr) + sizeof(struct udphdr) + 9];
memcpy(&couple.x_position,
&data[rtap_bytes + IEEE80211_HEADER_SIZE
+ LLC_HEADER_SIZE + sizeof(struct iphdr)
+ sizeof(struct udphdr) + 10], sizeof(float)) ;
memcpy(&couple.y_position,
&data[rtap_bytes + IEEE80211_HEADER_SIZE
+ LLC_HEADER_SIZE + sizeof(struct iphdr)
+ sizeof(struct udphdr) + 14], sizeof(float)) ;
memcpy(&couple.z_position,
&data[rtap_bytes + IEEE80211_HEADER_SIZE
+ LLC_HEADER_SIZE + sizeof(struct iphdr)
+ sizeof(struct udphdr) + 18], sizeof(float)) ;
break ;
default :
if (GET_VERBOSE())
printf("\nStrange explicit packet received\n") ;
fprintf(stderr,
"Error! Unknown packet type (%d).\n", packet_type) ;
is_explicit_packet = FALSE ;
}
if (! is_explicit_packet)
{
if (GET_MODE() == MODE_ACTIVE)
return ;
else if (GET_VERBOSE())
printf("\nThis strange explicit packet will be handled as"
" an implicit one.\n") ;
}
else
memcpy(&couple.request_time,
&data[rtap_bytes + IEEE80211_HEADER_SIZE + LLC_HEADER_SIZE
+ sizeof(struct iphdr) + sizeof(struct udphdr) + 1],
sizeof(struct timeval)) ;
}
else if (GET_MODE() == MODE_PASSIVE || GET_MODE() == MODE_MIXED)
{
if (GET_VERBOSE())
printf("\nImplicit packet received.\n") ;
}
else // Active mode, packet was not an explicit request
return ;
/* Radiotap header handling */
// Get rtap flags:
memcpy(&rtap_presentflags,
&data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ;
/* We get the flags in big-endian (net-endianess), but we work on them
* as if it was in little-endian. This allows to declare an array of 15
* bits (instead of 32), because we work only on the least significant
* bits (and so we do not reserve space for most significant bits that
* are useless). It's kind of cheat :-)
* So, on big-endian architectures, we must inverse bits as if we had
* got flags in little-endian: */
rtap_presentflags = le32toh(rtap_presentflags) ;
for (i = 0 ; i < 15 ; i++) // Initialise present flags structure
check[i] = FALSE ;
rtap_position = 8 ; // Begining of the present flags determined fields
// Test the first 15 bits of the flag field in order to check their
// presence and to copy them:
for (i = 0 ; i < 15 ; i++)
{
if ((rtap_presentflags % 2) == 1)
{
switch(i)
{
case RTAP_MACTS:
check[RTAP_MACTS] = TRUE ;
rtap_position += RTAP_L_MACTS ;
break ;
case RTAP_FLAGS:
check[RTAP_FLAGS] = TRUE;
rtap_position += RTAP_L_FLAGS ;
break ;
case RTAP_RATE:
check[RTAP_RATE] = TRUE;
rtap_position += RTAP_L_RATE ;
break ;
case RTAP_CHANNEL:
rtap_position += RTAP_L_CHANNEL ;
rtap_position += RTAP_L_CHANNELTYPE ;
break ;
case RTAP_FHSS:
check[RTAP_FHSS] = TRUE;
rtap_position += RTAP_L_FHSS ;
break ;
case RTAP_ANTENNASIGNALDBM:
memcpy(&(couple.antenna_signal_dbm),
&data[rtap_position], RTAP_L_ANTENNASIGNALDBM) ;
check[RTAP_ANTENNASIGNALDBM] = TRUE;
if (GET_VERBOSE())
printf("Antenna signal: %d dBm\n",
couple.antenna_signal_dbm - 0x100);
rtap_position += RTAP_L_ANTENNASIGNALDBM ;
break ;
case RTAP_ANTENNANOISEDBM:
check[RTAP_ANTENNANOISEDBM] = TRUE;
rtap_position += RTAP_L_ANTENNANOISEDBM ;
break ;
case RTAP_LOCKQUALITY:
check[RTAP_LOCKQUALITY] = TRUE;
rtap_position += RTAP_L_LOCKQUALITY ;
break ;
case RTAP_TXATTENUATION:
check[RTAP_TXATTENUATION] = TRUE;
rtap_position += RTAP_L_TXATTENUATION ;
break ;
case RTAP_TXATTENUATIONDB:
check[RTAP_TXATTENUATIONDB] = TRUE;
rtap_position += RTAP_L_TXATTENUATIONDB ;
break ;
case RTAP_TXATTENUATIONDBM:
check[RTAP_TXATTENUATIONDBM] = TRUE;
rtap_position += RTAP_L_TXATTENUATIONDBM ;
break ;
case RTAP_ANTENNA:
check[RTAP_ANTENNA] = TRUE;
rtap_position += RTAP_L_ANTENNA ;
break ;
case RTAP_ANTENNASIGNALDB:
check[RTAP_ANTENNASIGNALDB] = TRUE;
rtap_position += RTAP_L_ANTENNASIGNALDB ;
break ;
case RTAP_ANTENNANOISEDB:
check[RTAP_ANTENNANOISEDB] = TRUE;
rtap_position += RTAP_L_ANTENNANOISEDB ;
break ;
case RTAP_FCS:
check[RTAP_FCS] = TRUE;
rtap_position += RTAP_L_FCS ;
break ;
}
}
rtap_presentflags /= 2 ;
}
if (GET_VERBOSE())
{
char *ap_mac_string =
mac_bytes_to_string(couple.ap_mac_addr_bytes) ;
char *mobile_mac_string =
mac_bytes_to_string(couple.mobile_mac_addr_bytes) ;
printf("*** Couple to send ***\n"
"\tMAC AP: %s\n"
"\tMobile MAC: %s\n"
"\tSequence number (request time): %llu\n"
"\tRequest arrival time on the AP: %llu\n"
"\tSignal: %d dBm\n"
"\tPosition X: %f\n"
"\tPosition Y: %f\n"
"\tPosition Z: %f\n"
"\tDirection: %hhd\n"
,
ap_mac_string,
mobile_mac_string,
timeval_to_ms(couple.request_time),
timeval_to_ms(couple.start_time),
couple.antenna_signal_dbm - 0x100,
couple.x_position,
couple.y_position,
couple.z_position,
couple.direction
) ;
free(ap_mac_string) ;
free(mobile_mac_string) ;
}
/* Send couple to the aggregator */
nsent =
sendto(aggregation_sockfd, (void *) &couple, sizeof(couple), 0,
(struct sockaddr *) &aggregation_server,
(socklen_t) sizeof(aggregation_server)) ;
if (nsent != (ssize_t) sizeof(couple))
{
perror("Error sending couple to the aggregation server") ;
return ;
}
}
/*
* Get our own MAC address and copy it to 'mac_bytes'.
*/
void get_mac_addr(char *eth, unsigned char mac_bytes[6])
{
struct ifreq ifr;
int sockfd ;
bzero(mac_bytes, sizeof(unsigned char) * 6) ; // Empty mac_bytes
sockfd = socket(AF_INET, SOCK_DGRAM, 0) ;
if(sockfd < 0)
perror("Cannot open socket to read MAC address") ;
strncpy(ifr.ifr_name, eth, IFNAMSIZ) ;
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
return ;
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0)
return ;
memcpy(mac_bytes, ifr.ifr_hwaddr.sa_data, 6) ;
}
2010-07-13 15:09:07 +02:00
void print_usage()
{
printf("Usage :\n"
"\t%s [-f config_file] [-m mode] [-d aggregation_ip]"
" [-l listening_port] [-p aggregation_port] -r rtap_iface"
" [-w wifi_iface] [-k] [-v | -q]\n"
"Main options:\n"
2010-07-13 14:42:33 +02:00
"\t-h\t\tPrint this help.\n"
"\t-f config_file\tUse 'config_file' instead of the default"
" configuration file (%s). Available only if program was"
" compiled with libconfuse.\n"
"Capture options:\n"
"\t-m mode\t\t\tCapture mode: a(ctive), p(assive), m(ixed)"
" (default: a).\n"
"\t-d aggregation_ip\tIP address of the aggregation server"
" (default: 127.0.0.1)\n"
"\t-l aggregation_port\tListening port on the aggregation server"
" (default: %d).\n"
"\t-r rtap_iface\t\tRadiotap capture interface.\n"
"\t-w wifi_iface\t\tPhysical interface behind rtap_iface"
" (default: rtap_iface).\n"
"Other options:\n"
"\t-k\tKeep the monitor mode up on wifi_iface. Use it with buggy"
" drivers that disable monitor mode periodically. Available"
" only if the program was compiled with support of POSIX"
" threads.\n"
"\t-v\tVerbose mode (display captured packets).\n"
"\t-q\tQuiet mode (default).\n"
,
2010-07-13 15:09:07 +02:00
program_name,
DEFAULT_CONFIG_FILE,
AGGREGATE_DEFAULT_PORT
) ;
}