/* * 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 * *********************************************************************** * * 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 #include #include #include #include #include #include #include #include #include #ifdef USE_CONFIG_FILE # include #endif // USE_CONFIG_FILE #ifdef USE_PTHREAD # include #endif // USE_PTHREAD #ifdef ENABLE_KEEP_MONITOR # include #endif // ENABLE_KEEP_MONITOR // Used by get_mac_addr(): #include #include #include #include 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 ) ; }