owlps/owlps-listener/owlps-listenerd.c

1684 lines
51 KiB
C

/*
* This file is part of the Owl Positioning System (OwlPS).
* OwlPS is a project of the University of Franche-Comte
* (Université de Franche-Comté), France.
*
* Copyright © Université de Franche-Comté 2007-2012.
*
* Corresponding author: Matteo Cypriani <mcy@lm7.fr>
*
***********************************************************************
*
* This software is governed by the CeCILL license under French law and
* abiding by the rules of distribution of free software. You can use,
* modify and/or redistribute the software under the terms of the CeCILL
* license as circulated by CEA, CNRS and INRIA at the following URL:
* http://www.cecill.info
*
* As a counterpart to the access to the source code and rights to copy,
* modify and redistribute granted by the license, users are provided
* only with a limited warranty and the software's authors, the holder
* of the economic rights, and the successive licensors have only
* limited liability.
*
* In this respect, the user's attention is drawn to the risks
* associated with loading, using, modifying and/or developing or
* reproducing the software by the user in light of its specific status
* of free software, that may mean that it is complicated to manipulate,
* and that also therefore means that it is reserved for developers and
* experienced professionals having in-depth computer knowledge. Users
* are therefore encouraged to load and test the software's suitability
* as regards their requirements in conditions enabling the security of
* their systems and/or data to be ensured and, more generally, to use
* and operate it in the same conditions as regards security.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL license and that you accept its terms.
*
***********************************************************************
*
* This is the main source file of OwlPS Listener, the program that
* captures the requests sent by the mobile terminals and forwards them
* to the Aggregator.
*/
#include "owlps-listener.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/ethernet.h>
#ifdef USE_CONFIG_FILE
# include <confuse.h>
#endif // USE_CONFIG_FILE
#ifdef USE_PTHREAD
# include <pthread.h>
#endif // USE_PTHREAD
#ifdef ENABLE_KEEP_MONITOR
# include <iwlib.h>
#endif // ENABLE_KEEP_MONITOR
// Used by get_mac_addr():
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <assert.h>
char *program_name = NULL ;
uint8_t my_mac_bytes[ETHER_ADDR_LEN] ; // AP MAC address
char my_ip[INET_ADDRSTRLEN] ; // AP IP address
pcap_t *capture_handler = NULL ; // Packet capture descriptor
int aggregation_sockfd ;
struct sockaddr_in aggregation_server ;
#ifdef USE_PTHREAD
int autocalibration_send_sockfd ;
struct sockaddr_in autocalibration_send_server ;
// owl_true if the coordinates of the listener were provided by the user:
owl_bool coordinates_provided = owl_false ;
#endif // USE_PTHREAD
#ifdef USE_CONFIG_FILE
cfg_t *cfg = NULL ; // Configuration structure
#else // USE_CONFIG_FILE
/* If we do not use libconfuse, we declare a structure to store getopt
* options.
*/
struct {
owl_bool daemon ;
char mode ;
char aggregation_ip[INET_ADDRSTRLEN] ;
uint_fast16_t aggregation_port ;
uint_fast16_t listening_port ;
#ifdef ENABLE_KEEP_MONITOR
owl_bool keep_monitor ;
#endif // ENABLE_KEEP_MONITOR
char rtap_iface[IFNAMSIZ + 1] ;
char wifi_iface[IFNAMSIZ + 1] ;
#ifdef USE_PTHREAD
owl_bool autocalibration ;
char autocalibration_ip[INET_ADDRSTRLEN] ;
uint_fast16_t autocalibration_request_port ;
uint_fast16_t autocalibration_order_port ;
uint_fast16_t autocalibration_hello_port ;
uint_fast32_t autocalibration_hello_delay ;
uint_fast32_t autocalibration_delay ;
uint_fast16_t autocalibration_nb_packets ;
owl_direction my_direction ;
float my_position_x ;
float my_position_y ;
float my_position_z ;
#endif // USE_PTHREAD
uint_fast8_t verbose ;
} options = { // Initalise default options:
owl_false, // daemon
MODE_ACTIVE, // mode
"127.0.0.1", // aggregation_ip
OWL_DEFAULT_LISTENER_PORT, // aggregation_port
OWL_DEFAULT_REQUEST_PORT, // listening_port
#ifdef ENABLE_KEEP_MONITOR
owl_false, // keep_monitor
#endif // ENABLE_KEEP_MONITOR
"", // rtap_iface
"", // wifi_iface
#ifdef USE_PTHREAD
owl_false, // autocalibration
"", // autocalibration_ip
0, // autocalibration_request_port
OWL_DEFAULT_AUTOCALIBRATION_ORDER_PORT, // autocalibration_order_port
OWL_DEFAULT_AUTOCALIBRATION_HELLO_PORT, // autocalibration_hello_port
DEFAULT_AUTOCALIBRATION_HELLO_DELAY, // autocalibration_hello_delay
DEFAULT_AUTOCALIBRATION_DELAY, // autocalibration_delay
DEFAULT_AUTOCALIBRATION_NBPKT, // autocalibration_nb_packets
0, 0, 0, 0, // Calibration data
#endif // USE_PTHREAD
0 // verbose
} ;
#endif // USE_CONFIG_FILE
int main(int argc, char *argv[])
{
struct sigaction action ; // Signal handler structure
int ret ; // Program return value
#ifdef USE_PTHREAD
pthread_t
autocalibration_thread,
autocalibration_hello_thread ;
#endif // USE_PTHREAD
#ifdef ENABLE_KEEP_MONITOR
pthread_t keep_monitor_thread ;
#endif // ENABLE_KEEP_MONITOR
owl_run = owl_true ;
program_name = argv[0] ;
ret = initialise_configuration(argc, argv) ;
if (! owl_run)
goto exit ;
if (GET_DAEMON())
{
if (VERBOSE_WARNING)
fprintf(stderr, "Detaching to background...\n") ;
if (daemon(0, 0))
perror("Cannot daemonize") ;
}
/* Set up signal handlers */
action.sa_flags = 0 ;
sigemptyset(&action.sa_mask) ;
action.sa_handler = sigint_handler ;
sigaction(SIGINT, &action, NULL) ;
action.sa_handler = sigterm_handler ;
sigaction(SIGTERM, &action, NULL) ;
get_mac_addr(GET_WIFI_IFACE(), my_mac_bytes) ;
get_ip_addr(GET_WIFI_IFACE(), my_ip) ;
if (VERBOSE_INFO)
printf("My MAC address is: %s\n"
"My IP address is: %s\n",
owl_mac_bytes_to_string(my_mac_bytes),
my_ip) ;
#ifdef USE_PTHREAD
/* Set up threads */
# ifdef ENABLE_KEEP_MONITOR
if (GET_KEEP_MONITOR())
{
ret = pthread_create(&keep_monitor_thread, NULL,
&keep_mode_monitor, GET_WIFI_IFACE()) ;
if (ret != 0)
{
perror("Cannot create keep monitor thread") ;
ret = OWL_ERR_THREAD_CREATE ;
goto exit ;
}
}
# endif // ENABLE_KEEP_MONITOR
if (GET_AUTOCALIBRATION())
{
ret = pthread_create(&autocalibration_thread, NULL,
&autocalibrate, NULL) ;
if (ret != 0)
{
perror("Cannot create autocalibration thread") ;
ret = OWL_ERR_THREAD_CREATE ;
goto exit ;
}
ret = pthread_create(&autocalibration_hello_thread, NULL,
&autocalibrate_hello, NULL) ;
if (ret != 0)
{
perror("Cannot create autocalibration hello thread") ;
ret = OWL_ERR_THREAD_CREATE ;
goto exit ;
}
}
#endif // USE_PTHREAD
ret = capture() ; // Capture loop
/* Wait for the threads to terminate */
#ifdef USE_PTHREAD
# ifdef ENABLE_KEEP_MONITOR
if (GET_KEEP_MONITOR())
{
if (VERBOSE_WARNING)
fprintf(stderr, "Waiting for the keep mode monitor thread... ") ;
if (pthread_join(keep_monitor_thread, NULL) != 0)
perror("Cannot join keep mode monitor thread") ;
else if (VERBOSE_WARNING)
fprintf(stderr, "OK.\n") ;
}
# endif // ENABLE_KEEP_MONITOR
if (GET_AUTOCALIBRATION())
{
// We must cancel this thread because it can be blocked on the
// recvfrom() call:
if (VERBOSE_WARNING)
fprintf(stderr, "Cancelling the autocalibration thread... ") ;
if (pthread_cancel(autocalibration_thread) != 0)
perror("Cannot cancel autocalibration thread") ;
else if (VERBOSE_WARNING)
fprintf(stderr, "OK.\n") ;
if (VERBOSE_WARNING)
fprintf(stderr, "Waiting for the autocalibration thread... ") ;
if (pthread_join(autocalibration_thread, NULL) != 0)
perror("Cannot join autocalibration thread") ;
else if (VERBOSE_WARNING)
fprintf(stderr, "OK.\n") ;
// We must cancel this thread if we do not want to wait
// autocalibration_hello_delay seconds (in the worst case):
if (VERBOSE_WARNING)
fprintf(stderr,
"Cancelling the autocalibration hello thread... ") ;
if (pthread_cancel(autocalibration_hello_thread) != 0)
perror("Cannot cancel autocalibration hello thread") ;
else if (VERBOSE_WARNING)
fprintf(stderr, "OK.\n") ;
if (VERBOSE_WARNING)
fprintf(stderr,
"Waiting for the autocalibration hello thread... ") ;
if (pthread_join(autocalibration_hello_thread, NULL) != 0)
perror("Cannot join autocalibration hello thread") ;
else if (VERBOSE_WARNING)
fprintf(stderr, "OK.\n") ;
}
#else // USE_PTHREAD
// Just to avoid a warning when compiling without threads' support:
goto exit ;
#endif // USE_PTHREAD
/* Last cleaning tasks */
exit:
#ifdef USE_CONFIG_FILE
cfg_free(cfg) ; // Clean configuration
#endif // USE_CONFIG_FILE
printf("%s: end.\n", program_name) ;
return ret ;
}
/*
* Read the configuration from both the command line and the
* configuration file.
* Returns an error code, or 0 in case of success. If the program should
* stop (because of a special option or a configuration error), owl_run
* is set to false.
*/
int initialise_configuration(int argc, char **argv)
{
int ret ;
ret = parse_config_file(argc, argv) ;
if (! owl_run)
return ret ;
ret = parse_command_line(argc, argv) ;
if (! owl_run)
return ret ;
ret = check_configuration() ;
if (! owl_run)
return ret ;
if (VERBOSE_INFO)
print_configuration() ;
return 0 ;
}
int parse_config_file(int argc, char **argv)
{
#ifdef USE_CONFIG_FILE
// If we use libconfuse, we declare options:
cfg_opt_t opts[] =
{
// Daemon mode:
CFG_BOOL("daemon", cfg_false, CFGF_NONE),
// 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", OWL_DEFAULT_LISTENER_PORT, CFGF_NONE),
// Port on which mobiles send active requests:
CFG_INT("listening_port", OWL_DEFAULT_REQUEST_PORT, CFGF_NONE),
#ifdef ENABLE_KEEP_MONITOR
// 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 // ENABLE_KEEP_MONITOR
// 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),
#ifdef USE_PTHREAD
// Autocalibration activated?
CFG_BOOL("autocalibration", cfg_false, CFGF_NONE),
// Destination IP address of the autocalibration requests (default:
// none, but will be set to aggregation_ip in the config check):
CFG_STR("autocalibration_ip", "", CFGF_NONE),
// Port on which autocalibration requests are sent (default: 0,
// but will be set to listening_port in the config check):
CFG_INT("autocalibration_request_port", 0, CFGF_NONE),
// Port on which autocalibration orders are received:
CFG_INT("autocalibration_order_port",
OWL_DEFAULT_AUTOCALIBRATION_ORDER_PORT, CFGF_NONE),
// Port on which autocalibration hello are sent:
CFG_INT("autocalibration_hello_port",
OWL_DEFAULT_AUTOCALIBRATION_HELLO_PORT, CFGF_NONE),
// Delay between two hello messages:
CFG_INT("autocalibration_hello_delay",
DEFAULT_AUTOCALIBRATION_HELLO_DELAY,
CFGF_NONE),
// Delay between two calibration packet transmission:
CFG_INT("autocalibration_delay", DEFAULT_AUTOCALIBRATION_DELAY,
CFGF_NONE),
// Number of packets for a calibration request:
CFG_INT("autocalibration_nb_packets",
DEFAULT_AUTOCALIBRATION_NBPKT, CFGF_NONE),
// Direction
CFG_INT("my_direction", 0, CFGF_NONE),
// Position X
CFG_FLOAT("my_position_x", 0, CFGF_NONE),
// Position Y
CFG_FLOAT("my_position_y", 0, CFGF_NONE),
// Position Z
CFG_FLOAT("my_position_z", 0, CFGF_NONE),
#endif // USE_PTHREAD
// Verbose level:
CFG_INT("verbose", 0, CFGF_NONE),
CFG_END()
} ;
char *config_file = NULL ; // Configuration file name
#endif // USE_CONFIG_FILE
// Option -f specifies a config file, options -h and -V exit the
// program, so we search for them first
int opt ;
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case '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
break ;
case 'h' :
print_usage() ;
owl_run = owl_false ;
return EXIT_SUCCESS ;
case 'V' :
print_version() ;
owl_run = owl_false ;
return EXIT_SUCCESS ;
}
}
#ifdef USE_CONFIG_FILE
// If -f isn't found, we use the default config file
if (config_file == NULL)
{
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) ;
owl_run = owl_false ;
return OWL_ERR_CONFIG_FILE ;
}
free(config_file) ;
#endif // USE_CONFIG_FILE
return 0 ;
}
int parse_command_line(int argc, char **argv)
{
int ret ;
ret = parse_main_options(argc, argv) ;
if (! owl_run)
return ret ;
#ifdef USE_PTHREAD
ret = parse_calibration_data(argc, argv) ;
if (! owl_run)
return ret ;
#endif // USE_PTHREAD
return 0 ;
}
int parse_main_options(int argc, char **argv)
{
int opt ;
optind = 1 ; // Rewind argument parsing
while ((opt = getopt(argc, argv, OPTIONS)) != -1)
{
switch (opt)
{
case 'A' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION() ;
#else // USE_PTHREAD
fprintf(stderr, "Warning! The program was compiled without"
" support of POSIX threads, so -A (autocalibration)"
" is not available and will be ignored. All other"
" autocalibration-related options will also be"
" ignored.\n") ;
#endif // USE_PTHREAD
break ;
case 'D' :
SET_DAEMON() ;
break ;
case 'f' : // Config file
break ; // (already parsed)
case 'H' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_HELLO_PORT(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'i' :
SET_AGGREGATION_IP(optarg) ;
break ;
case 'I' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_IP(optarg) ;
#endif // USE_PTHREAD
break ;
case 'K' :
#ifdef ENABLE_KEEP_MONITOR
SET_KEEP_MONITOR() ;
#else // ENABLE_KEEP_MONITOR
fprintf(stderr, "Warning! The program was compiled without"
" enabling the -K option (monitor mode keeping-up)."
".\n") ;
#endif // ENABLE_KEEP_MONITOR
break ;
case 'l' :
SET_LISTENING_PORT(strtol(optarg, NULL, 0)) ;
break ;
case 'm' :
SET_MODE(optarg[0]) ;
break ;
case 'n' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_NBPKT(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'O' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_ORDER_PORT(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'p' :
SET_AGGREGATION_PORT(strtol(optarg, NULL, 0)) ;
break ;
case 'P' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_REQUEST_PORT(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'q' :
RESET_VERBOSE() ;
break ;
case 'r' :
SET_RTAP_IFACE(optarg) ;
break ;
case 't' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_DELAY(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'T' :
#ifdef USE_PTHREAD
SET_AUTOCALIBRATION_HELLO_DELAY(strtol(optarg, NULL, 0)) ;
#endif // USE_PTHREAD
break ;
case 'v' :
INCREMENT_VERBOSE() ;
break ;
case 'w' :
SET_WIFI_IFACE(optarg) ;
break ;
default :
print_usage() ;
owl_run = owl_false ;
return OWL_ERR_BAD_USAGE ;
}
}
return 0 ;
}
#ifdef USE_PTHREAD
int parse_calibration_data(int argc, char **argv)
{
/* Parse remaining arguments (possible calibration data) */
if (argc - optind != 0)
{
if (argc - optind == 4)
{
coordinates_provided = owl_true ;
SET_MY_DIRECTION(strtoul(argv[optind++], NULL, 0)) ;
SET_MY_POSITION_X(strtod(argv[optind++], NULL)) ;
SET_MY_POSITION_Y(strtod(argv[optind++], NULL)) ;
SET_MY_POSITION_Z(strtod(argv[optind], NULL)) ;
}
else // Bad number of arguments
{
print_usage() ;
owl_run = owl_false ;
return OWL_ERR_BAD_USAGE ;
}
}
return 0 ;
}
#endif // USE_PTHREAD
int 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()) ;
print_usage() ;
owl_run = owl_false ;
return OWL_ERR_BAD_USAGE ;
}
if (GET_RTAP_IFACE()[0] == '\0')
{
fprintf(stderr, "Error! You must specify a radiotap interface"
" for the capture.\n") ;
print_usage() ;
owl_run = owl_false ;
return OWL_ERR_BAD_USAGE ;
}
if (GET_WIFI_IFACE()[0] == '\0')
{
if (VERBOSE_WARNING)
fprintf(stderr, "No Wi-Fi interface was specified. Failing back"
" to the radiotap interface (%s) instead.\n",
GET_RTAP_IFACE()) ;
SET_WIFI_IFACE(GET_RTAP_IFACE()) ;
}
// Port numbers //
if (GET_AGGREGATION_PORT() < 1 || GET_AGGREGATION_PORT() > 65535)
{
if (VERBOSE_WARNING)
fprintf(stderr, "Warning! Bad aggregation_port:"
" failing back to the default value.\n") ;
SET_AGGREGATION_PORT(OWL_DEFAULT_LISTENER_PORT) ;
}
if (GET_LISTENING_PORT() < 1 || GET_LISTENING_PORT() > 65535)
{
if (VERBOSE_WARNING)
fprintf(stderr, "Warning! Bad listening_port:"
" failing back to the default value.\n") ;
SET_LISTENING_PORT(OWL_DEFAULT_REQUEST_PORT) ;
}
// Autocalibration stuff //
#ifdef USE_PTHREAD
if (GET_AUTOCALIBRATION())
{
if (GET_AUTOCALIBRATION_IP()[0] == '\0')
{
if (VERBOSE_WARNING)
fprintf(stderr, "No autocalibration IP specified, we will"
" use the aggregation IP as the destination of"
" autocalibration requests.\n") ;
SET_AUTOCALIBRATION_IP(GET_AGGREGATION_IP()) ;
}
if (GET_AUTOCALIBRATION_NBPKT() < 1)
fprintf(stderr, "Warning! autocalibration_nb_packets is null,"
" no autocalibration request will be sent!\n") ;
if (coordinates_provided)
if (GET_MY_DIRECTION() < OWL_DIRECTION_MIN ||
GET_MY_DIRECTION() > OWL_DIRECTION_MAX)
fprintf(stderr, "Warning! \"%d\" is not a valid"
" direction.\n", (int) GET_MY_DIRECTION()) ;
// Autocalibration port numbers
if (GET_AUTOCALIBRATION_REQUEST_PORT() > 65535 && VERBOSE_WARNING)
fprintf(stderr, "Warning! Bad autocalibration_request_port:"
" failing back to the default value.\n") ;
if (GET_AUTOCALIBRATION_REQUEST_PORT() < 1 ||
GET_AUTOCALIBRATION_REQUEST_PORT() > 65535)
SET_AUTOCALIBRATION_REQUEST_PORT(GET_LISTENING_PORT()) ;
if (GET_AUTOCALIBRATION_ORDER_PORT() < 1 ||
GET_AUTOCALIBRATION_ORDER_PORT() > 65535)
{
if (VERBOSE_WARNING)
fprintf(stderr, "Warning! Bad autocalibration_order_port:"
" failing back to the default value.\n") ;
SET_AUTOCALIBRATION_ORDER_PORT(OWL_DEFAULT_AUTOCALIBRATION_ORDER_PORT) ;
}
if (GET_AUTOCALIBRATION_HELLO_PORT() < 1 ||
GET_AUTOCALIBRATION_HELLO_PORT() > 65535)
{
if (VERBOSE_WARNING)
fprintf(stderr, "Warning! Bad autocalibration_hello_port:"
" failing back to the default value.\n") ;
SET_AUTOCALIBRATION_HELLO_PORT(OWL_DEFAULT_AUTOCALIBRATION_HELLO_PORT) ;
}
}
#endif // USE_PTHREAD
return 0 ;
}
void print_configuration()
{
fprintf(stderr, "Configuration:\n") ;
#ifdef USE_CONFIG_FILE
cfg_print(cfg, stderr) ;
#else // USE_CONFIG_FILE
fprintf(stderr,
"mode = %c\n"
"aggregation_ip = \"%s\"\n"
"aggregation_port = %"PRIuFAST16"\n"
"listening_port = %"PRIuFAST16"\n"
"rtap_iface = \"%s\"\n"
"wifi_iface = \"%s\"\n"
#ifdef ENABLE_KEEP_MONITOR
"keep_monitor = %s\n"
#endif // ENABLE_KEEP_MONITOR
#ifdef USE_PTHREAD
"autocalibration = %s\n"
"autocalibration_ip = \"%s\"\n"
"autocalibration_request_port = %"PRIuFAST16"\n"
"autocalibration_order_port = %"PRIuFAST16"\n"
"autocalibration_hello_port = %"PRIuFAST16"\n"
"autocalibration_hello_delay = %"PRIuFAST32"\n"
"autocalibration_delay = %"PRIuFAST32"\n"
"autocalibration_nb_packets = %"PRIuFAST16"\n"
"my_direction = %"PRIu8"\n"
"my_position_x = %f\n"
"my_position_y = %f\n"
"my_position_z = %f\n"
#endif // USE_PTHREAD
"verbose = %"PRIuFAST8"\n"
,
GET_MODE(),
GET_AGGREGATION_IP(),
GET_AGGREGATION_PORT(),
GET_LISTENING_PORT(),
GET_RTAP_IFACE(),
GET_WIFI_IFACE(),
#ifdef ENABLE_KEEP_MONITOR
OWL_BOOL_TO_STRING(GET_KEEP_MONITOR()),
#endif // ENABLE_KEEP_MONITOR
#ifdef USE_PTHREAD
OWL_BOOL_TO_STRING(GET_AUTOCALIBRATION()),
GET_AUTOCALIBRATION_IP(),
GET_AUTOCALIBRATION_REQUEST_PORT(),
GET_AUTOCALIBRATION_ORDER_PORT(),
GET_AUTOCALIBRATION_HELLO_PORT(),
GET_AUTOCALIBRATION_HELLO_DELAY(),
GET_AUTOCALIBRATION_DELAY(),
GET_AUTOCALIBRATION_NBPKT(),
GET_MY_DIRECTION(),
GET_MY_POSITION_X(),
GET_MY_POSITION_Y(),
GET_MY_POSITION_Z(),
#endif // USE_PTHREAD
GET_VERBOSE()
) ;
#endif // USE_CONFIG_FILE
}
#ifdef ENABLE_KEEP_MONITOR
/*
* Thread function. Switches interface 'iface' to monitor mode every
* second.
*/
void* keep_mode_monitor(void *iface)
{
if (VERBOSE_WARNING)
fprintf(stderr, "Thread for keeping monitor mode launched.\n") ;
while (owl_run)
{
// Switch the interface to monitor mode:
iface_mode_monitor((char*) iface) ;
sleep(1) ; // Wait for 1 second
}
pthread_exit(NULL) ;
}
/*
* Switches the IEEE 802.11 interface 'iface' to Monitor mode.
*/
int iface_mode_monitor(const char *const iface)
{
struct iwreq wrq ;
int sockfd = iw_sockets_open() ;
strncpy((&wrq)->ifr_name, iface, IFNAMSIZ) ;
if (ioctl(sockfd, SIOCGIWMODE, &wrq) == -1) // Get current mode
{
perror("Error reading interface mode") ;
return OWL_ERR_IFACE_MODE_GET ;
}
// If interface is not yet in Monitor mode
if (wrq.u.mode != IW_MODE_MONITOR)
{
wrq.u.mode = IW_MODE_MONITOR ;
if (ioctl(sockfd, SIOCSIWMODE, &wrq) == -1) // Set up Monitor mode
{
perror("Error setting up Monitor mode") ;
return OWL_ERR_IFACE_MODE_SET ;
}
}
close(sockfd) ;
return 0 ;
}
#endif // ENABLE_KEEP_MONITOR
/*
* Captures packets using the radiotap interface.
* Captured data is transmitted to the aggregator.
*/
int capture()
{
char errbuf[PCAP_ERRBUF_SIZE] ; // Error message
// Start capture:
capture_handler =
pcap_open_live(GET_RTAP_IFACE(), BUFSIZ, 1, 1000, errbuf) ;
if (capture_handler == NULL) // Capture starting failed
{
fprintf(stderr, "Cannot open capture interface %s\n", errbuf) ;
return OWL_ERR_IFACE_PCAP_OPEN ;
}
/* Open UDP socket to the aggregator */
aggregation_sockfd =
owl_create_trx_socket(GET_AGGREGATION_IP(), GET_AGGREGATION_PORT(),
&aggregation_server, NULL) ;
while (owl_run)
// Capture one packet at time, and call read_packet() on it:
pcap_loop(capture_handler, 1, read_packet, NULL) ;
pcap_close(capture_handler) ; // Stop capture
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)
{
owl_captured_request request ; // Message to send to the aggregator
uint16_t rtap_bytes ; // Radiotap header size
uint_fast16_t offset ; // Offset to read the packet
owl_bool rtap_fields[15] ; // Present flags
uint8_t raw_packet_fc1 ; // First byte of the received frame's FC
uint8_t raw_packet_fc2 ; // Second byte of the received frame's FC
// Size of the IEEE 802.11 header:
uint_fast8_t ieee80211_header_size = IEEE80211_HEADER_SIZE_DATA ;
uint16_t 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 ;
// Localisation request type (request, calibration, autocalibration):
// Is the packet an explicit request?
owl_bool is_explicit_packet = owl_true ;
// Is the packet an autocalibration positioning request?
owl_bool uses_autocalibration_request_port = owl_false ;
ssize_t nsent ; // sendto return value
// Blank the request:
memset(&request, 0, sizeof(request)) ;
/* Common treatements */
// Copy 2 bytes from the 3rd packet byte, that is the size of the rtap
// header (changes with the flags):
offset = 2 ;
memcpy(&rtap_bytes, &packet[offset], sizeof(rtap_bytes)) ;
// Radiotap header is little-endian
rtap_bytes = le16toh(rtap_bytes) ;
// Check rtap_bytes for buggy values
if (rtap_bytes > 100)
return ;
// After the rtap header, there is the 802.11 header; the first byte
// is the first byte of the Frame Control (FC) field, which contains
// the type of the packet (Management, Control or Data) and its subtype
// (QoS, etc.):
offset = rtap_bytes ;
raw_packet_fc1 = packet[offset] ;
// The second byte of the FC field contains the frame flags. The two
// first bits indicate the frame source and destination types: the
// first bit is "To DS" and the second is "From DS", so if the second
// bit is 0 the frame comes from a STA. That's what we want for an
// explicit packet:
offset = rtap_bytes + 1 ;
raw_packet_fc2 = packet[offset] ;
if (! IS_DATA_FRAME(raw_packet_fc1)) // Data frame?
goto not_explicit_packet ;
if (DATA_FRAME_IS_QOS(raw_packet_fc1)) // QoS Data frame?
ieee80211_header_size += 2 ; // 2 bytes of QoS information
if (! IS_FRAME_FROM_STA(raw_packet_fc2))
goto not_explicit_packet ;
// Get the packet type (protocol, 2 bytes) from the LLC header:
offset = rtap_bytes + ieee80211_header_size + 6 ;
memcpy(&llc_packet_type, &packet[offset], 2) ;
llc_packet_type = ntohs(llc_packet_type) ;
if (llc_packet_type != ETHERTYPE_IP) // IP packet?
goto not_explicit_packet ;
offset = rtap_bytes + ieee80211_header_size + LLC_HEADER_SIZE ;
packet_ip_header = (struct iphdr *) &packet[offset] ;
// Get the source IP:
memcpy(request.mobile_ip_addr_bytes, &packet_ip_header->saddr, 4) ;
if (GET_MODE() != MODE_PASSIVE) // If mode is active or mixed
{
uint_fast16_t dest_port ;
// Protocol for an explicit request is UDP
if (packet_ip_header->protocol != IPPROTO_UDP)
goto not_explicit_packet ;
// Check destination port:
offset =
rtap_bytes + ieee80211_header_size +
LLC_HEADER_SIZE + sizeof(struct iphdr) ;
packet_udp_header = (struct udphdr *) &packet[offset] ;
dest_port = ntohs(packet_udp_header->dest) ;
#ifdef USE_PTHREAD
if (GET_AUTOCALIBRATION() && dest_port ==
(uint_fast16_t) GET_AUTOCALIBRATION_REQUEST_PORT())
uses_autocalibration_request_port = owl_true ;
else
#endif // USE_PTHREAD
if (dest_port != (uint_fast16_t) GET_LISTENING_PORT())
goto not_explicit_packet ;
}
goto process_packet ;
not_explicit_packet :
if (GET_MODE() == MODE_ACTIVE)
return ;
is_explicit_packet = owl_false ;
process_packet :
if (IS_RETRY(raw_packet_fc2) && VERBOSE_CHATTERBOX)
printf("This packet is a Retry.\n") ;
// Source MAC address is 10 bytes after the 802.11 packet type:
offset = rtap_bytes + 10 ;
memcpy(request.mobile_mac_addr_bytes, &packet[offset], ETHER_ADDR_LEN) ;
// Drop the packet if it comes from the AP itself:
if (owl_mac_equals(my_mac_bytes, request.mobile_mac_addr_bytes))
return ;
// Copy AP MAC :
memcpy(request.ap_mac_addr_bytes, my_mac_bytes, ETHER_ADDR_LEN) ;
// Capture time is in the pcap header (host-endian):
owl_timeval_to_timestamp(&header->ts, &request.capture_time) ;
owl_hton_timestamp(&request.capture_time) ;
/* Active mode */
if (is_explicit_packet
&& (GET_MODE() == MODE_ACTIVE || GET_MODE() == MODE_MIXED)
// FIXME: should we really ignore Retries?
&& ! IS_RETRY(raw_packet_fc2))
{
offset =
rtap_bytes + ieee80211_header_size + LLC_HEADER_SIZE +
sizeof(struct iphdr) + sizeof(struct udphdr) ;
request.type = packet[offset] ;
extract_packet_numbers(&packet[++offset], &request) ;
offset += 2 * sizeof(uint16_t) ;
// Copy the timestamp "as is" (i.e. without changing endianess)
// because it will return to the network soon:
memcpy(&request.request_time, &packet[offset],
sizeof(owl_timestamp)) ;
offset += sizeof(owl_timestamp) ;
switch(request.type)
{
case OWL_REQUEST_NORMAL :
if (VERBOSE_INFO)
printf("\nExplicit packet received.\n") ;
break ;
case OWL_REQUEST_CALIBRATION :
if (VERBOSE_INFO)
printf("\nExplicit calibration packet received.\n") ;
extract_calibration_data(&packet[offset], &request) ;
break ;
case OWL_REQUEST_AUTOCALIBRATION :
if (VERBOSE_INFO)
{
printf("\nAutocalibration packet received.") ;
if (! uses_autocalibration_request_port)
printf(".. on the wrong port!") ;
putchar('\n') ;
}
extract_calibration_data(&packet[offset], &request) ;
break ;
default :
if (VERBOSE_INFO)
printf("\nStrange explicit packet received\n") ;
fprintf(stderr,
"Error! Unknown request type (%d).\n", request.type) ;
if (GET_MODE() == MODE_ACTIVE)
return ;
else
{
if (VERBOSE_INFO)
printf("\nThis strange explicit packet will be handled"
" as an implicit one.\n") ;
request.type = OWL_REQUEST_IMPLICIT ;
}
}
}
else if (GET_MODE() == MODE_PASSIVE || GET_MODE() == MODE_MIXED)
{
if (VERBOSE_CHATTERBOX)
printf("\nImplicit packet received.\n") ;
request.type = OWL_REQUEST_IMPLICIT ;
}
else // Active mode, packet was not an explicit request
return ;
/* Radiotap header handling */
extract_radiotap_data(packet, &request, rtap_fields) ;
/* Display the packet details */
if (VERBOSE_DISPLAY_CAPTURED)
{
owl_timestamp tmp_time ;
char
request_time_str[OWL_TIMESTAMP_STRLEN],
capture_time_str[OWL_TIMESTAMP_STRLEN],
ap_mac_addr_str[OWL_ETHER_ADDR_STRLEN],
mobile_mac_addr_str[OWL_ETHER_ADDR_STRLEN],
mobile_ip_str[INET_ADDRSTRLEN] ;
tmp_time = request.request_time ;
owl_ntoh_timestamp(&tmp_time) ;
owl_timestamp_to_string(&tmp_time, request_time_str) ;
tmp_time = request.capture_time ;
owl_ntoh_timestamp(&tmp_time) ;
owl_timestamp_to_string(&tmp_time, capture_time_str) ;
owl_mac_bytes_to_string_r(request.ap_mac_addr_bytes,
ap_mac_addr_str) ;
owl_mac_bytes_to_string_r(request.mobile_mac_addr_bytes,
mobile_mac_addr_str) ;
inet_ntop(AF_INET, &request.mobile_ip_addr_bytes,
mobile_ip_str, INET_ADDRSTRLEN) ;
printf("*** Request to send ***\n"
"\tType: %"PRIu8"\n"
"\tMAC AP: %s\n"
"\tMobile MAC: %s\n"
"\tMobile IP: %s\n"
"\tRequest timestamp: %s\n"
"\tRequest arrival time on the AP: %s\n"
"\tSignal: %d dBm\n"
"\tPosition X: %f\n"
"\tPosition Y: %f\n"
"\tPosition Z: %f\n"
"\tDirection: %hhd\n"
"\tPacket number: %"PRIu16"/%"PRIu16"\n"
"\tPacket size: %"PRIu32"\n"
,
request.type,
ap_mac_addr_str,
mobile_mac_addr_str,
mobile_ip_str,
request_time_str,
capture_time_str,
rtap_fields[RTAP_ANTENNASIGNALDBM] ?
request.ss_dbm - 256 : 0,
owl_ntohf(request.x_position),
owl_ntohf(request.y_position),
owl_ntohf(request.z_position),
request.direction,
ntohs(request.packet_id),
ntohs(request.nb_packets),
header->len
) ;
}
/* Send the request to the aggregator */
nsent =
sendto(aggregation_sockfd, &request, sizeof(request), 0,
(struct sockaddr *) &aggregation_server,
(socklen_t) sizeof(aggregation_server)) ;
if (nsent != (ssize_t) sizeof(request))
{
perror("Error sending request to the aggregation server") ;
return ;
}
}
/*
* Fills 'request' with the calibration data extracted from 'packet'.
* Note: 'packet' is read from its first byte, therefore you must not
* pass the whole received packet to this function.
*/
void extract_calibration_data(const u_char *packet,
owl_captured_request *request)
{
request->direction = packet[0] ;
assert(sizeof(float) == 4) ;
memcpy(&request->x_position, &packet[1], sizeof(float)) ;
memcpy(&request->y_position, &packet[5], sizeof(float)) ;
memcpy(&request->z_position, &packet[9], sizeof(float)) ;
}
/*
* Fills 'request' with the number of packets and packet ID extracted
* from 'packet'.
* Note: 'packet' is read from its first byte, therefore you must not
* pass the whole received packet to this function.
*/
void extract_packet_numbers(const u_char *packet,
owl_captured_request *request)
{
// Current packet's ID:
memcpy(&request->packet_id, packet,
sizeof(uint16_t)) ;
request->packet_id = request->packet_id ;
// Number of packets:
memcpy(&request->nb_packets, &packet[sizeof(uint16_t)],
sizeof(uint16_t)) ;
request->nb_packets = request->nb_packets ;
}
/*
* Fills 'request' with the required data extracted from the Radiotap
* header of 'packet'. The elements of 'rtap_fields' are set to owl_true
* when the corresponding Radiotap flag is found in the packet.
*/
void extract_radiotap_data(const u_char *packet,
owl_captured_request *request,
owl_bool rtap_fields[15])
{
uint32_t rtap_presentflags ;
uint_fast16_t rtap_position ;
int i ; // Iterator
// Get rtap flags:
memcpy(&rtap_presentflags,
&packet[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ;
// The Radiotap header is little-endian
rtap_presentflags = le32toh(rtap_presentflags) ;
for (i = 0 ; i < 15 ; ++i) // Initialise present flags structure
rtap_fields[i] = owl_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:
rtap_fields[RTAP_MACTS] = owl_true ;
rtap_position += RTAP_L_MACTS ;
break ;
case RTAP_FLAGS:
rtap_fields[RTAP_FLAGS] = owl_true;
rtap_position += RTAP_L_FLAGS ;
break ;
case RTAP_RATE:
rtap_fields[RTAP_RATE] = owl_true;
rtap_position += RTAP_L_RATE ;
break ;
case RTAP_CHANNEL:
rtap_position += RTAP_L_CHANNEL ;
rtap_position += RTAP_L_CHANNELTYPE ;
break ;
case RTAP_FHSS:
rtap_fields[RTAP_FHSS] = owl_true;
rtap_position += RTAP_L_FHSS ;
break ;
case RTAP_ANTENNASIGNALDBM:
memcpy(&request->ss_dbm,
&packet[rtap_position], RTAP_L_ANTENNASIGNALDBM) ;
rtap_fields[RTAP_ANTENNASIGNALDBM] = owl_true;
if (VERBOSE_INFO)
printf("Antenna signal: %d dBm\n",
request->ss_dbm - 256);
rtap_position += RTAP_L_ANTENNASIGNALDBM ;
break ;
case RTAP_ANTENNANOISEDBM:
rtap_fields[RTAP_ANTENNANOISEDBM] = owl_true;
rtap_position += RTAP_L_ANTENNANOISEDBM ;
break ;
case RTAP_LOCKQUALITY:
rtap_fields[RTAP_LOCKQUALITY] = owl_true;
rtap_position += RTAP_L_LOCKQUALITY ;
break ;
case RTAP_TXATTENUATION:
rtap_fields[RTAP_TXATTENUATION] = owl_true;
rtap_position += RTAP_L_TXATTENUATION ;
break ;
case RTAP_TXATTENUATIONDB:
rtap_fields[RTAP_TXATTENUATIONDB] = owl_true;
rtap_position += RTAP_L_TXATTENUATIONDB ;
break ;
case RTAP_TXATTENUATIONDBM:
rtap_fields[RTAP_TXATTENUATIONDBM] = owl_true;
rtap_position += RTAP_L_TXATTENUATIONDBM ;
break ;
case RTAP_ANTENNA:
rtap_fields[RTAP_ANTENNA] = owl_true;
rtap_position += RTAP_L_ANTENNA ;
break ;
case RTAP_ANTENNASIGNALDB:
rtap_fields[RTAP_ANTENNASIGNALDB] = owl_true;
rtap_position += RTAP_L_ANTENNASIGNALDB ;
break ;
case RTAP_ANTENNANOISEDB:
rtap_fields[RTAP_ANTENNANOISEDB] = owl_true;
rtap_position += RTAP_L_ANTENNANOISEDB ;
break ;
case RTAP_FCS:
rtap_fields[RTAP_FCS] = owl_true;
rtap_position += RTAP_L_FCS ;
break ;
}
}
rtap_presentflags /= 2 ;
}
}
/*
* Get our own MAC address and copy it to 'mac_bytes'.
*/
void get_mac_addr(char *eth, uint8_t mac_bytes[ETHER_ADDR_LEN])
{
struct ifreq ifr;
int sockfd ;
// Empty mac_bytes:
memset(mac_bytes, 0, sizeof(uint8_t) * ETHER_ADDR_LEN) ;
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, ETHER_ADDR_LEN) ;
}
/*
* Get our own IP address and copy it to 'ip'.
*/
void get_ip_addr(char *eth, char ip[INET_ADDRSTRLEN])
{
struct ifreq ifr;
int sockfd ;
struct sockaddr_in sa ;
struct in_addr ip_addr ;
sockfd = socket(AF_INET, SOCK_DGRAM, 0) ;
if(sockfd < 0)
perror("Cannot open socket to read IP address") ;
strncpy(ifr.ifr_name, eth, IFNAMSIZ) ;
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
return ;
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)
return ;
memcpy(&ip_addr, &ifr.ifr_addr.sa_data[sizeof(sa.sin_port)],
sizeof(ip_addr)) ;
inet_ntop(AF_INET, &ip_addr, ip, INET_ADDRSTRLEN) ;
}
/* *** Autocalibration functions *** */
#ifdef USE_PTHREAD
void* autocalibrate_hello(void *NULL_value)
{
int send_sockfd ;
struct sockaddr_in serv;
owl_autocalibration_hello message ;
if (VERBOSE_WARNING)
fprintf(stderr, "Autocalibration Hello thread launched.\n") ;
send_sockfd =
owl_create_trx_socket(GET_AGGREGATION_IP(),
GET_AUTOCALIBRATION_HELLO_PORT(),
&serv, NULL) ;
pthread_cleanup_push(&owl_close_fd, &send_sockfd) ;
memcpy(&message.ap_mac_addr_bytes, my_mac_bytes, ETHER_ADDR_LEN) ;
while (owl_run)
{
owl_send_packet(send_sockfd, &serv,
&message, sizeof(message)) ;
sleep(GET_AUTOCALIBRATION_HELLO_DELAY()) ;
}
/* Close the socket */
pthread_cleanup_pop(1) ;
pthread_exit(NULL_value) ;
}
void* autocalibrate(void *NULL_value)
{
int nread ; // recvfrom return value
struct sockaddr_in client; // UDP client structure
socklen_t client_len = sizeof(client) ; // Size of clients
int listen_sockfd ;
owl_autocalibration_order message ;
if (VERBOSE_WARNING)
fprintf(stderr, "Autocalibration thread launched.\n") ;
// Socket to send autocalibration positioning requests
autocalibration_send_sockfd =
owl_create_trx_socket(GET_AUTOCALIBRATION_IP(),
GET_AUTOCALIBRATION_REQUEST_PORT(),
&autocalibration_send_server,
GET_WIFI_IFACE()) ;
// Socket to receive orders from the aggregator
listen_sockfd =
owl_create_udp_listening_socket(GET_AUTOCALIBRATION_ORDER_PORT()) ;
if (listen_sockfd < 0)
{
perror("Error! Cannot create UDP listening socket from the"
" aggregation server") ;
exit(OWL_ERR_SOCKET_CREATE) ;
}
pthread_cleanup_push(&owl_close_fd, &listen_sockfd) ;
while (owl_run)
{
nread = recvfrom(listen_sockfd, &message, sizeof(message), 0,
(struct sockaddr *) &client, &client_len) ;
if (nread <= 0 && owl_run)
{
if (owl_run)
perror("No message received from aggregator") ;
continue ;
}
if (message.order == AUTOCALIBRATION_ORDER_SEND)
{
if (VERBOSE_INFO)
fprintf(stderr, "I was just ordered to send an"
" autocalibration request...\n") ;
send_autocalibration_request() ;
}
else
fprintf(stderr,
"Autocalibration order unknown: %d.\n", message.order) ;
}
/* Close the socket */
pthread_cleanup_pop(1) ;
pthread_exit(NULL_value) ;
}
void send_autocalibration_request()
{
uint8_t *packet ;
uint_fast16_t packet_size = make_packet(&packet) ;
owl_send_request(autocalibration_send_sockfd,
&autocalibration_send_server,
packet, packet_size,
GET_AUTOCALIBRATION_NBPKT(),
GET_AUTOCALIBRATION_DELAY()) ;
free(packet) ;
}
/*
* Creates the calibration packet to send.
* The packet must be freed by the calling function.
* Returns the size of the packet.
*/
uint_fast16_t make_packet(uint8_t **packet)
{
uint8_t *pkt ;
uint_fast16_t size ; // Packet size
uint_fast16_t offset ; // Index used to create the packet
owl_timestamp request_time ;
float
my_position_x = owl_htonf(GET_MY_POSITION_X()),
my_position_y = owl_htonf(GET_MY_POSITION_Y()),
my_position_z = owl_htonf(GET_MY_POSITION_Z()) ;
uint16_t npkt ;
owl_timestamp_now(&request_time) ;
if (VERBOSE_CHATTERBOX)
{
char request_time_str[OWL_TIMESTAMP_STRLEN] ;
owl_timestamp_to_string(&request_time, request_time_str) ;
printf("Autocalibration time: %s\n", request_time_str) ;
}
owl_hton_timestamp(&request_time) ;
offset = 0 ;
size =
sizeof(uint8_t) * 2 + sizeof(owl_timestamp) + sizeof(float) * 3 +
sizeof(uint16_t) * 2 ;
pkt = malloc(size) ;
// Request type:
memset(&pkt[offset++], OWL_REQUEST_AUTOCALIBRATION, 1) ;
// Number of the current packet (1 for the first):
npkt = htons(1u) ;
memcpy(&pkt[offset], &npkt, sizeof(uint16_t)) ;
offset += sizeof(uint16_t) ;
// Number of packets:
npkt = htons(GET_AUTOCALIBRATION_NBPKT()) ;
memcpy(&pkt[offset], &npkt, sizeof(uint16_t)) ;
offset += sizeof(uint16_t) ;
// Timestamp:
memcpy(&pkt[offset], &request_time, sizeof(request_time)) ;
offset += sizeof(request_time) ;
// Coordinates:
pkt[offset++] = GET_MY_DIRECTION() ;
memcpy(&pkt[offset], &my_position_x, sizeof(float)) ;
offset += sizeof(float) ;
memcpy(&pkt[offset], &my_position_y, sizeof(float)) ;
offset += sizeof(float) ;
memcpy(&pkt[offset], &my_position_z, sizeof(float)) ;
#ifndef NDEBUG
offset += sizeof(float) ;
assert(offset == size) ;
#endif // NDEBUG
*packet = pkt ;
return size ;
}
#endif // USE_PTHREAD
/* *** End of autocalibration functions *** */
void sigint_handler(int num)
{
owl_sigint_handler(num) ;
pcap_breakloop(capture_handler) ;
}
void sigterm_handler(int num)
{
owl_sigterm_handler(num) ;
pcap_breakloop(capture_handler) ;
}
void print_usage()
{
printf("Usage :\n"
"\t%s"
" [-f config_file]"
" [-D]"
" [-v[v[v[v]]] | -q]"
"\n\t"
" -r rtap_iface"
" [-w wifi_iface]"
" [-K]"
" [-m mode]"
"\n\t"
" [-i aggregation_ip]"
" [-l listening_port]"
" [-p aggregation_port]"
"\n\t"
" [-A]"
" [-I autocalibration_ip]"
" [-P autocalibration_request_port]"
"\n\t"
" [-a autocalibration_port]"
" [-H autocalibration_hello_delay]"
"\n\t"
" [-t autocalibration_delay]"
" [-n autocalibration_nb_packets]"
"\n\t"
" [direction x y z]\n"
"\t%s -h\n"
"\t%s -V\n"
"Main options:\n"
"\t-h\t\tPrint this help.\n"
"\t-V\t\tShow version information.\n"
"\t-f config_file\tUse 'config_file' instead of the default"
" configuration\n\t\t\tfile (%s).\n\t\t\tAvailable only if the"
" program was linked against\n\t\t\tlibconfuse.\n"
"\t-D\t\tDaemon mode.\n"
"\t-v\t\tBe verbose. You can use this option up to 3 times to"
"\n\t\t\tincrease the level of verbosity (1 = warnings,"
"\n\t\t\t2 = useful information, 3 = a lot of information,"
"\n\t\t\t4 = display each captured packet).\n"
"\t-q\t\tQuiet mode (default): sets the verbose level to 0.\n"
"Capture options:\n"
"\t-m mode\t\t\tCapture mode: a(ctive), p(assive), m(ixed)"
"\n\t\t\t\t(default: a).\n"
"\t-l listening_port\tPort on which explicit positioning"
" requests are\n\t\t\t\tsent by mobiles (default: %d).\n"
"\t-i aggregation_ip\tIP address of the aggregation server"
" (default:\n\t\t\t\t127.0.0.1)\n"
"\t-p aggregation_port\tRequests are transmitted to the"
" aggregation\n\t\t\t\tserver on this port (default: %d).\n"
"\t-r rtap_iface\t\tRadiotap capture interface.\n"
"\t-w wifi_iface\t\tPhysical interface behind rtap_iface"
" (default:\n\t\t\t\trtap_iface).\n"
"Autocalibration options:\n"
"(These options are available only if the program was compiled"
" with support of\nthe POSIX threads and the adequate"
" compilation-time option.)\n"
"\t-A\t\t\tEnable autocalibration (default: disabled).\n"
"\t-I autocalib_ip\t\tDestination IP of the autocalibration"
" requests\n\t\t\t\t(default: aggregation_ip).\n"
"\t-P autocalib_req_port\tPort on which autocalibration"
" requests are sent\n\t\t\t\t(default: listening_port).\n"
"\t-O order_port\t\tPort on which autocalibration orders are"
"\n\t\t\t\treceived from the aggregation server (default:"
"\n\t\t\t\t%d).\n"
"\t-H hello_port\t\tPort on which hello messages are sent to"
" the\n\t\t\t\taggregation server (default: %d).\n"
"\t-T hello_delay\t\tTime between each hello message sent to"
" the\n\t\t\t\taggregation server, in seconds (default:"
" %d s).\n"
"\t-t delay\t\tTime between each autocalibration"
" packet\n\t\t\t\ttransmission, in milliseconds (default:"
" %d ms).\n"
"\t-n nb_packets\t\tNumber of packet transmitted"
" for one\n\t\t\t\tautocalibration request (default: %d).\n"
"\tdirection x y z\t\tThe coordinates of the listener"
" (direction is an\n\t\t\t\tinteger; x, y, z are floats).\n"
"Miscelanneous options:\n"
"\t-K\tKeep the monitor mode up on wifi_iface. Use it with"
" buggy\n\t\tdrivers that disable monitor mode periodically."
" Available only\n\t\tif the program was compiled with the"
" option ENABLE_KEEP_MONITOR.\n"
,
program_name,
program_name,
program_name,
DEFAULT_CONFIG_FILE,
OWL_DEFAULT_REQUEST_PORT,
OWL_DEFAULT_LISTENER_PORT,
OWL_DEFAULT_AUTOCALIBRATION_ORDER_PORT,
OWL_DEFAULT_AUTOCALIBRATION_HELLO_PORT,
DEFAULT_AUTOCALIBRATION_HELLO_DELAY,
DEFAULT_AUTOCALIBRATION_DELAY,
DEFAULT_AUTOCALIBRATION_NBPKT
) ;
}
void print_version()
{
printf("This is OwlPS Listener, part of the Owl Positioning"
" System project.\n"
"Version: %s.\n"
"Compilation-time options:\n"
"\tSupport for configuration file (libconfuse): %s.\n"
"\tSupport for POSIX threads: %s.\n"
"\tOption -K: %s.\n",
#ifdef OWLPS_VERSION
OWLPS_VERSION
#else // OWLPS_VERSION
"unknown version"
#endif // OWLPS_VERSION
,
#ifdef USE_CONFIG_FILE
"YES"
#else // USE_CONFIG_FILE
"NO"
#endif // USE_CONFIG_FILE
,
#ifdef USE_PTHREAD
"YES"
#else // USE_PTHREAD
"NO"
#endif // USE_PTHREAD
,
#ifdef ENABLE_KEEP_MONITOR
"YES"
#else // ENABLE_KEEP_MONITOR
"NO"
#endif // ENABLE_KEEP_MONITOR
) ;
}