From 29d23523ffd5a523c8a967f21962cecc4d2daa4d Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Thu, 14 Feb 2008 07:54:51 +0000 Subject: [PATCH] Import initial (TO) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Travail de l'UV TO52 à l'UTBM, par Matteo Cypriani et Pierre-Frédéric Rossel. Une partie du code provient du travail sur la TX. git-svn-id: https://pif.pu-pm.univ-fcomte.fr/svn/loc@3 785a6c6c-259e-4ff1-8b91-dc31627914f0 --- loc-bts/code/Makefile | 75 ++++ loc-bts/code/ap/Makefile | 75 ++++ loc-bts/code/ap/ap.h | 28 ++ loc-bts/code/ap/apd.c | 311 +++++++++++++++++ loc-bts/code/ap/apd_test.c | 303 +++++++++++++++++ loc-bts/code/client/Makefile | 74 ++++ loc-bts/code/client/locclient.c | 108 ++++++ loc-bts/code/librtaputil/Makefile | 137 ++++++++ loc-bts/code/librtaputil/librtaputil.c | 224 ++++++++++++ loc-bts/code/librtaputil/rtaputil.h | 122 +++++++ loc-bts/code/rtap.sh | 5 + loc-bts/code/rtapaggregate/Makefile | 74 ++++ loc-bts/code/rtapaggregate/rtapaggregate.h | 61 ++++ loc-bts/code/rtapaggregate/rtapaggregated.c | 359 ++++++++++++++++++++ 14 files changed, 1956 insertions(+) create mode 100644 loc-bts/code/Makefile create mode 100644 loc-bts/code/ap/Makefile create mode 100644 loc-bts/code/ap/ap.h create mode 100644 loc-bts/code/ap/apd.c create mode 100644 loc-bts/code/ap/apd_test.c create mode 100644 loc-bts/code/client/Makefile create mode 100644 loc-bts/code/client/locclient.c create mode 100644 loc-bts/code/librtaputil/Makefile create mode 100644 loc-bts/code/librtaputil/librtaputil.c create mode 100644 loc-bts/code/librtaputil/rtaputil.h create mode 100755 loc-bts/code/rtap.sh create mode 100644 loc-bts/code/rtapaggregate/Makefile create mode 100644 loc-bts/code/rtapaggregate/rtapaggregate.h create mode 100644 loc-bts/code/rtapaggregate/rtapaggregated.c diff --git a/loc-bts/code/Makefile b/loc-bts/code/Makefile new file mode 100644 index 0000000..b1ab5aa --- /dev/null +++ b/loc-bts/code/Makefile @@ -0,0 +1,75 @@ +.PHONY : all librtapanalyser librtaputil rtapaggregate ap client clean purge help install install-librtaputil install-rtapaggregate install-ap install-client + +all : librtaputil rtapaggregate ap client + +install : install-librtaputil install-rtapaggregate install-ap install-client + +uninstall : uninstall-librtaputil uninstall-rtapaggregate uninstall-ap uninstall-client + +librtaputil : + @cd librtaputil && make + +rtapaggregate : librtaputil + @cd rtapaggregate && make + +ap : librtaputil + @cd ap && make + +client : librtaputil + @cd client && make + +install-librtaputil : librtaputil + @cd librtaputil && make install + +install-rtapaggregate : rtapaggregate install-librtaputil + @cd rtapaggregate && make install + +install-ap : ap install-librtaputil + @cd ap && make install + +install-client : client install-librtaputil + @cd client && make install + +uninstall-librtaputil : librtaputil + @cd librtaputil && make uninstall + +uninstall-rtapaggregate : rtapaggregate + @cd rtapaggregate && make uninstall + +uninstall-ap : ap + @cd ap && make uninstall + +uninstall-client : client + @cd client && make uninstall + +clean : + @cd rtapaggregate && make clean + @cd librtaputil && make clean + @cd ap && make clean + @cd client && make clean + +purge : + @cd rtapaggregate && make purge + @cd librtaputil && make purge + @cd ap && make purge + @cd client && make purge + +help : + @echo "Bibliothèques nécessaires à la compilation :\n\ + libpcap0.8-dev\n\ + librtaputil1.0 (fournie)\n\ + \n\ + Cibles possibles :\n\ + all (cible par défaut) : Compile tous les modules.\n\ + : Compile uniquement le module (et ses dépendances).\n\ + \n\ + install : Installe tous les modules.\n\ + install- : Installe uniquement le module (et ses dépendances).\n\ + \n\ + uninstall : Désinstalle tous les modules.\n\ + uninstall- : Désinstalle uniquement le module (et ses dépendances).\n\ + \n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence /usr/local. Modifiez la variable PREFIX de chaque Makefile pour changer ce comportement." diff --git a/loc-bts/code/ap/Makefile b/loc-bts/code/ap/Makefile new file mode 100644 index 0000000..46b5a6f --- /dev/null +++ b/loc-bts/code/ap/Makefile @@ -0,0 +1,75 @@ +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/sbin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +CC = gcc + +# Commandes d'installation et de désinstallation +RM=rm -fv +CP=cp -v + +# Cible +TARGET=apd +HEADER=ap.h + +# Flags +CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. +DEPFLAGS=-MMD +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG=-fPIC +LIBS=-lm -lpcap ../librtaputil/librtaputil.so.1.0 + + +## Cibles de compilation standard ## + +.PHONY : all install uninstall clean purge help + +all : $(TARGET) + +% : %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS) +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< + +# Compilation du programme +$(TARGET) : $(TARGET).o $(HEADER) + + +## Installation / désinstallation ## + +install : $(TARGET) + @$(CP) $(TARGET) $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(TARGET) ; chmod 755 $(TARGET) + +uninstall : + @$(RM) $(INSTALL_DIR)/$(TARGET) + + +## Nettoyage ## + +clean : + @$(RM) -fv *~ *.o *.d + +purge : clean + @$(RM) -fv $(TARGET) + + +## Aide ## + +help : + @echo "Bibliothèques nécessaires à la compilation :\n\ + libpcap0.8-dev\n\ + librtaputil1.0 (fournie)\n\ + \n\ + Cibles possibles :\n\ + $(TARGET) (cible par défaut) : Compile le programme $(TARGET).\n\ + install : Installe le programme $(TARGET).\n\ + uninstall : Désinstalle le programme $(TARGET).\n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence $(PREFIX). Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/loc-bts/code/ap/ap.h b/loc-bts/code/ap/ap.h new file mode 100644 index 0000000..91e77c4 --- /dev/null +++ b/loc-bts/code/ap/ap.h @@ -0,0 +1,28 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "../librtaputil/rtaputil.h" +#include +#include + +// Pour la fonction get_mac_addr() : +#include +#include +#include +#include +#include + + +/* Codes d'erreurs */ +#define ERR_CREATING_SOCKET 1 // Erreur lors de la création de la socket d'envoi +#define ERR_OPENING_IFACE 2 // Erreur lors de l'ouverture de l'interface de capture +#define ERR_BAD_USAGE 3 // Mauvais appel au programme + + +/* En-têtes des fonctions */ +int capture(char *capture_iface, BOOL print_values) ; +void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server, BOOL print_values) ; +void get_mac_addr(char *eth, unsigned char mac_bytes[6]) ; +void print_usage(char *prog) ; diff --git a/loc-bts/code/ap/apd.c b/loc-bts/code/ap/apd.c new file mode 100644 index 0000000..2c01452 --- /dev/null +++ b/loc-bts/code/ap/apd.c @@ -0,0 +1,311 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "ap.h" + + +unsigned char mac[6] ; // Adresse MAC de l'AP + + +int main(int argc, char *argv[]) +{ + struct sigaction action ; // Structure de mise en place des gestionnaires de signaux + int ret ; + char *mac_string ; + + if (argc != 3) + { + print_usage(argv[0]) ; + return ERR_BAD_USAGE ; + } + + run = TRUE ; + + /* Mise en place des gestionnaires de signaux */ + 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(argv[2], mac) ; + mac_string = mac_bytes_to_string(mac) ; + printf("Ma mac est : %s\n", mac_string) ; + free(mac_string) ; + + ret = capture(argv[1], TRUE) ; + + printf("%s : fin.\n", argv[0]) ; + return ret ; +} + + + + +/* Capture des paquets en utilisant l'interface "capture_iface" pendant "capture_time" mili-secondes. + Les informations concernant les mobiles effectuant des requêtes sont conservées dans la liste "known_mobiles". + Les données capturées sont envoyées au serveur d'aggrégation à travers la socket UDP "socket". +*/ +int capture(char *capture_iface, BOOL print_values) +{ + pcap_t *handle ; // Descripteur de capture de paquets + char errbuf[PCAP_ERRBUF_SIZE] ;// Message d'erreur + // struct timeval tbegin, tcurrent ; + int sockfd ; // Descripteur de la socket vers le serveur d'aggrégation + struct sockaddr_in server, client ; + + + /* Sous-fonction de traitement des paquets capturés */ + void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) + { + read_packet(args, header, packet, sockfd, &server, print_values) ; // On appelle la fonction read_packet() avec les mêmes arguments, plus "print_values" qui indique si on doit afficher le paquet. + } + + + handle = pcap_open_live(capture_iface, BUFSIZ, 1, 1000, errbuf) ; // Début de la capture + if (handle == NULL) // Le lancement de la capture a-t-il échoué ? + { + fprintf(stderr, "Impossible d'ouvrir l'interface « %s » : %s\n", capture_iface, errbuf) ; + return ERR_OPENING_IFACE ; + } + + /* Ouverture de la socket UDP vers le serveur d'aggrégation */ + sockfd = create_udp_sending_socket("127.0.0.1", AGGREGATE_DEFAULT_PORT, &server, &client); + if (sockfd < 0) + { + perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n"); + return ERR_CREATING_SOCKET ; + } + + while(run) + { + pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets + } + + pcap_close(handle) ; // Arrêt de la capture. + (void) close(sockfd) ; // Fermeture de la socket + + return 0 ; +} + + + +/* Traite un paquet et l'envoie au serveur d'agrégation */ +void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server, BOOL print_values) +{ + unsigned char *data = (unsigned char *) packet ; // Recopie dans data l'adresse du paquet capturé + unsigned short int rtap_bytes ; // Taille des données reçues + unsigned char c ; + int i ; + unsigned int rtap_presentflags, rtap_position ; + couple_message couple ; + ssize_t nsent ; // Retour de sendto + BOOL check[15] ; // Champs présents + char packet_type ; + + memcpy(&rtap_bytes, &data[2], sizeof(unsigned short int)) ; // Recopie les deux octets à partir du troisième octet de donnée qui est la taille de l'en-tête rtap (change avec des flags) + c = data[rtap_bytes] ; // Au bout de l'en-tête rtap il y a celle du 802.11 dont le premier determine le type (beacon ou pas) + if (c == 0x08 // Si le paquet est de type data, + && data[rtap_bytes+24+8+9] == 0x11 // et de protocole UDP (24 : en-tête 802.11, 8 : en-tête LLC, 9 : position du champ "Protocol" de l'en-tête IP), + && data[rtap_bytes+24+8+20+2] == 0x26 && data[rtap_bytes+24+8+20+3] == 0xac) // et le port de destination est 9900 (20 : longueur de l'en-tête IP, le port de destination étant les troisièmes et quatrièmes octet suivant). + { + memcpy(couple.ap_mac_addr_bytes, mac, 6); // On copie la MAC de l'AP + memcpy(couple.mobile_mac_addr_bytes, &data[rtap_bytes+10], 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin + gettimeofday(&couple.start_time, NULL) ; + + packet_type = data[rtap_bytes+24+8+20+8] ; + + memcpy(&couple.request_time, &data[rtap_bytes+24+8+20+8+1], sizeof(struct timeval)); + + + switch(packet_type) + { + case PACKET_TYPE_NORMAL : + if (print_values) + printf("Paquet normal reçu.\n") ; + couple.direction = 0 ; + couple.x_position = 0 ; + couple.y_position = 0 ; + couple.z_position = 0 ; + break ; + + case PACKET_TYPE_CALIBRATION : + if (print_values) + printf("Paquet de calibration reçu.\n") ; + couple.direction = data[rtap_bytes+24+8+20+8 + 9]; + memcpy(&couple.x_position, &data[rtap_bytes+24+8+20+8+10], sizeof(float)); + memcpy(&couple.y_position, &data[rtap_bytes+24+8+20+8+14], sizeof(float)); + memcpy(&couple.z_position, &data[rtap_bytes+24+8+20+8+18], sizeof(float)); + break ; + + default : + if (print_values) + printf("Paquet bizarre reçu.\n") ; + fprintf(stderr, "Erreur ! Type de paquet inconnu (%d).\n", packet_type) ; + return ; + } + + + memcpy(&rtap_presentflags, &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS); // Récupère les flags de l'en-tête rtap + + for (i = 0 ; i < 15 ; i++) + check[i] = FALSE ; + rtap_position = 8 ; // début des champs déterminés par le present flag + + for(i=0 ; i < 14 ; i++) // on teste les 15 premiers bits du champ flag afin de valider la présence et de les copier + { + 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 (print_values) + 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 (print_values) + printf("\n") ; + + if (print_values) + { + 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("\n\ +*** Couple à envoyer ***\n\ +\tMAC AP : %s\n\ +\tMAC mobile : %s\n\ +\tNuméro de séquence (heure de la demande) : %lu\n\ +\tHeure d'arrivée de la demande de localisation sur l'AP : %lu\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) ; + } + + /* Envoi du couple au serveur d'aggrégation */ + nsent = sendto(sockfd, (void *) &couple, sizeof(couple), 0, (struct sockaddr *) server, (socklen_t) sizeof(*server)) ; + if (nsent != (ssize_t) sizeof(couple)) + { + perror("Erreur lors de l'envoi du couple au serveur ") ; + return ; + } + } +} + + + + +/* Fonction permettant de récupérer sa propre adresse MAC (interface 'eth') dans le tableau '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) ; // RàZ + + sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; + if(sockfd < 0) + printf("Can't open socket\n") ; + + 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) ; +} + + + + +/* Affiche le mode d'emploi du programme */ +void print_usage(char *prog) +{ + printf("Usage :\n\ +\t%s rtap_iface wifi_iface\n\ +- rtap_iface est l'interface de capture radiotap.\n\ +- wifi_iface est l'interface physique correspondant à rtap_iface.\n\ +", prog) ; +} diff --git a/loc-bts/code/ap/apd_test.c b/loc-bts/code/ap/apd_test.c new file mode 100644 index 0000000..d0f0370 --- /dev/null +++ b/loc-bts/code/ap/apd_test.c @@ -0,0 +1,303 @@ +/* + * This is the rtapanalyser library, Wi-Fi packet sniffer and analyser, + * thanks to the radiotap header of each packet. + */ + + +#include "ap.h" + +extern BOOL run ; + +unsigned char *mac ; + + +int main() +{ + struct sigaction action ; // Structure de mise en place des gestionnaires de signaux + int sockfd ; // Descripteur de la socket vers le serveur d'aggrégation + struct sockaddr_in server, client ; + sockfd = create_udp_sending_socket("127.0.0.1", AGGREGATE_DEFAULT_PORT, &server, &client); + mac = malloc(sizeof(unsigned char) * 6) ; // Adresse MAC de l'AP + + /* Mise en place des gestionnaires de signaux */ + 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("eth1", mac) ; + printf("ma mac est %s\n", mac_bytes_to_string(mac)) ; + + while (run) + { + couple_message couple ; + memcpy(couple.ap_mac_addr_bytes, mac, 6); // On copie la MAC de l'AP + gettimeofday(&couple.start_time, NULL) ; + memcpy(&couple.request_time, &couple.mobile_mac_addr_bytes[3], sizeof(struct timeval)); + couple.request_time.tv_usec = abs(couple.request_time.tv_usec) ; + memcpy(&couple.mobile_mac_addr_bytes, &couple.start_time, 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin + couple.antenna_signal_dbm = couple.mobile_mac_addr_bytes[0] ; + couple.x_position = 4644.647 ; + couple.y_position = 43.788 ; + couple.z_position = 553.99 ; + couple.direction = SOUTH ; + + printf("\ncouple à envoyer :\nAP MAC : %s\nMobile MAC : %s\nRequest time : %ld\nsignal : %u\nX : %f\nY : %f\nZ : %f\nDirection : %hhd\n", mac_bytes_to_string(couple.ap_mac_addr_bytes), mac_bytes_to_string(couple.mobile_mac_addr_bytes), couple.request_time.tv_usec, couple.antenna_signal_dbm, couple.x_position, couple.y_position, couple.z_position, couple.direction) ; + + /* Envoi du couple au serveur d'aggrégation */ + sendto(sockfd, (void *) &couple, sizeof(couple), 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; + + sleep(1) ; + } + + //capture("rtap0", TRUE) ; + + /* + memcpy(mac, "abcdef", 6) ; + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + memcpy(mac, "azerty", 6) ; + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + memcpy(mac, "ghijkl", 6) ; + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + printf("%lu\n", get_mobile_sequence(&known_mobiles, mac)); + */ + + printf("apd : fin\n") ; + return 0 ; +} + + + + +/* Capture des paquets en utilisant l'interface "capture_iface" pendant "capture_time" mili-secondes. + Les informations concernant les mobiles effectuant des requêtes sont conservées dans la liste "known_mobiles". + Les données capturées sont envoyées au serveur d'aggrégation à travers la socket UDP "socket". +*/ +int capture(char *capture_iface, BOOL print_values) +{ + pcap_t *handle ; // Descripteur de capture de paquets + char errbuf[PCAP_ERRBUF_SIZE] ;// Message d'erreur + // struct timeval tbegin, tcurrent ; + int sockfd ; // Descripteur de la socket vers le serveur d'aggrégation + struct sockaddr_in server, client ; + + + /* Sous-fonction de traitement des paquets capturés */ + void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) + { + read_packet(args, header, packet, sockfd, &server, print_values) ; // On appelle la fonction read_packet() avec les mêmes arguments, plus "print_values" qui indique si on doit afficher le paquet. + } + + + handle = pcap_open_live(capture_iface, BUFSIZ, 1, 1000, errbuf) ; // Début de la capture + if (handle == NULL) // Le lancement de la capture a-t-il échoué ? + { + fprintf(stderr, "Impossible d'ouvrir l'interface « %s » : %s\n", capture_iface, errbuf) ; + return(ERR_OPENING_IFACE) ; + } + + /* Ouverture de la socket UDP vers le serveur d'aggrégation */ + sockfd = create_udp_sending_socket("127.0.0.1", AGGREGATE_DEFAULT_PORT, &server, &client); + if (sockfd < 0) + { + perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n"); + exit(-1); // FIXME + } + + while(run) + { + pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets + } + + pcap_close(handle) ; // Arrêt de la capture. + (void) close(sockfd) ; // Fermeture de la socket + + return 0 ; +} + + + +/* Traite un paquet et l'envoie au serveur d'agrégation */ +void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, int sockfd, struct sockaddr_in *server, BOOL print_values) +{ + unsigned char *data = (unsigned char *) packet ; // Recopie dans data l'adresse du paquet capturé + unsigned short int rtap_bytes ; // Taille des données reçues + unsigned char c ; + int i ; + unsigned int rtap_presentflags, rtap_position ; + couple_message couple ; + ssize_t nsent ; // Retour de sendto + BOOL check[15] ; // Champs présents + char packet_type ; + //char offset = 1 ; + char direction ; // Direction de la calibration + float posX, posY, posZ; + FILE *fd ; + + memcpy(&rtap_bytes, &data[2], sizeof(unsigned short int)) ; // Recopie les deux octets à partir du troisième octet de donnée qui est la taille de l'en-tête rtap (change avec des flags) + c = data[rtap_bytes] ; // Au bout de l'en-tête rtap il y a celle du 802.11 dont le premier determine le type (beacon ou pas) + if (c == 0x08 // Si le paquet est de type data, + && data[rtap_bytes+24+8+9] == 0x11 // et de protocole UDP (24 : en-tête 802.11, 8 : en-tête LLC, 9 : position du champ "Protocol" de l'en-tête IP), + && data[rtap_bytes+24+8+20+2] == 0x26 && data[rtap_bytes+24+8+20+3] == 0xac) // et le port de destination est 9900 (20 : longueur de l'en-tête IP, le port de destination étant les troisièmes et quatrièmes octet suivant). + { + memcpy(couple.ap_mac_addr_bytes, mac, 6); // On copie la MAC de l'AP + memcpy(couple.mobile_mac_addr_bytes, &data[rtap_bytes+10], 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin + gettimeofday(&couple.start_time, NULL) ; + + packet_type = data[rtap_bytes+24+8+20+8] ; + + memcpy(&couple.request_time, &data[rtap_bytes+24+8+20+8+1], sizeof(struct timeval)); + + +printf("coin\n"); + + if (packet_type == 0) + printf("Paquet normal\n") ; + else if (packet_type == 1) + { + printf("Paquet de calibration\n") ; + + direction = data[rtap_bytes+24+8+20+8 + 9]; + + memcpy(&posX, &data[rtap_bytes+24+8+20+8+10], sizeof(float)); + memcpy(&posY, &data[rtap_bytes+24+8+20+8+14], sizeof(float)); + memcpy(&posZ, &data[rtap_bytes+24+8+20+8+18], sizeof(float)); + } + + if (print_values) + printf("[%s]\n", mac_bytes_to_string(couple.mobile_mac_addr_bytes)) ; + + memcpy(&rtap_presentflags, &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS); // Récupère les flags de l'en-tête rtap + + + for (i = 0 ; i < 15 ; i++) + check[i] = FALSE ; + rtap_position = 8 ; // début des champs déterminés par le present flag + + for(i=0 ; i < 14 ; i++) // on teste les 15 premiers bits du champ flag afin de valider la présence et de les copier + { + if((rtap_presentflags % 2) == 1) + { + switch(i) + { + case RTAP_MACTS: + check[RTAP_MACTS] = TRUE ; + rtap_position += RTAP_L_MACTS ; + break ; + case RTAP_FLAGS: + // memcpy(&(tmp_ss->flags), &data[rtap_position], RTAP_L_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 (print_values) + 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 (packet_type == 1) + { + // coord direction mac_ap puissance +printf("hey\n") ; + fd = fopen("./calibration.out", "a") ; + fprintf(fd, "%f, %f, %f, %d, %s, %d\n", posX, posY, posZ, direction, mac_bytes_to_string(mac), couple.antenna_signal_dbm - 0x100) ; + } + + if (print_values) + printf("\n") ; + + printf("couple à envoyer :\nAP MAC : %s\nMobile MAC : %s\nRequest time : %ld\n", mac_bytes_to_string(couple.ap_mac_addr_bytes), mac_bytes_to_string(couple.mobile_mac_addr_bytes), couple.request_time.tv_usec) ; + + /* Envoi du couple au serveur d'aggrégation */ + nsent = sendto(sockfd, (void *) &couple, sizeof(couple), 0, (struct sockaddr *) server, (socklen_t) sizeof(*server)) ; + if (nsent != (ssize_t) sizeof(couple)) + { + perror("Erreur lors de l'envoi du couple au serveur ") ; + return ; + } + } +} + + + + +/* Fonction permettant de récupérer sa propre adresse MAC (interface 'eth') dans le tableau '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) ; // RàZ + + sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; + if(sockfd < 0) + printf("Can't open socket\n") ; + + 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) ; +} diff --git a/loc-bts/code/client/Makefile b/loc-bts/code/client/Makefile new file mode 100644 index 0000000..75d6392 --- /dev/null +++ b/loc-bts/code/client/Makefile @@ -0,0 +1,74 @@ +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/bin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +CC = gcc + +# Commandes d'installation et de désinstallation +RM=rm -fv +CP=cp -v + +# Cible +TARGET=locclient +HEADER= + +# Flags +CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. +DEPFLAGS=-MMD +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG=-fPIC +LIBS=../librtaputil/librtaputil.so.1.0 + + +## Cibles de compilation standard ## + +.PHONY : all install uninstall clean purge help + +all : $(TARGET) + +% : %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS) +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< + +# Compilation du programme +$(TARGET) : $(TARGET).o $(HEADER) + + +## Installation / désinstallation ## + +install : $(TARGET) + @$(CP) $(TARGET) $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(TARGET) ; chmod 755 $(TARGET) + +uninstall : + @$(RM) $(INSTALL_DIR)/$(TARGET) + + +## Nettoyage ## + +clean : + @$(RM) -fv *~ *.o *.d + +purge : clean + @$(RM) -fv $(TARGET) + + +## Aide ## + +help : + @echo "Bibliothèques nécessaires à la compilation :\n\ + librtaputil1.0 (fournie)\n\ + \n\ + Cibles possibles :\n\ + $(TARGET) (cible par défaut) : Compile le programme $(TARGET).\n\ + install : Installe le programme $(TARGET).\n\ + uninstall : Désinstalle le programme $(TARGET).\n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence $(PREFIX). Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/loc-bts/code/client/locclient.c b/loc-bts/code/client/locclient.c new file mode 100644 index 0000000..5a1f149 --- /dev/null +++ b/loc-bts/code/client/locclient.c @@ -0,0 +1,108 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "../librtaputil/rtaputil.h" + + +/* Codes d'erreurs */ +#define ERR_CREATING_SOCKET 1 +#define ERR_BAD_NUMBER_OF_ARGS 2 +#define ERR_SENDING_INFO 3 + + +/* Affiche le mode d'emploi du programme */ +void print_usage(char *prog) +{ + printf("Usage :\n\ +\t- Demande de localisation : %s ip_serveur\n\ +\t- Requête de calibration : %s ip_serveur direction x y z\n\ +", prog, prog) ; +} + + + +int main(int argc, char *argv[]) +{ + struct timeval request_time ; + char *buf = NULL ; + int buf_offset ; + ssize_t nsent ; // Retour de sendto + struct sockaddr_in server, client ; + int sockfd ; + int buf_size ; + int i ; + + gettimeofday(&request_time, NULL) ; + + if(argc == 2) // Paquet normal + { + printf("Envoi normal effectué à : %lu\n", timeval_to_ms(request_time)) ; + buf_size = sizeof(char) + sizeof(struct timeval) ; + buf = malloc(buf_size) ; + buf[0] = PACKET_TYPE_NORMAL ; // Type de paquet = demande + memcpy(&buf[1], &request_time, sizeof(request_time)) ; + } + + else if(argc == 6) // Paquet calibration + { + printf("Envoi Calibration effectué à : %lu\n", timeval_to_ms(request_time)) ; + + buf_offset = 0 ; + buf_size = sizeof(char) * 2 + sizeof(struct timeval) + sizeof(float) * 3 ; + buf = malloc(buf_size) ; + + buf[buf_offset++] = PACKET_TYPE_CALIBRATION ; // Type de paquet = calibration + memcpy(&buf[buf_offset], &request_time, sizeof(request_time)) ; + buf_offset += sizeof(request_time) ; + buf[buf_offset++] = atoi(argv[2]) ; // Direction + float posX = atof(argv[3]) ; + float posY = atof(argv[4]) ; + float posZ = atof(argv[5]) ; + memcpy(&buf[buf_offset], &posX, sizeof(float)) ; + buf_offset += sizeof(float) ; + memcpy(&buf[buf_offset], &posY, sizeof(float)) ; + buf_offset += sizeof(float) ; + memcpy(&buf[buf_offset], &posZ, sizeof(float)) ; + } + + else + { + print_usage(argv[0]) ; + return ERR_BAD_NUMBER_OF_ARGS ; + } + + + /* Ouverture de la socket UDP vers le serveur d'aggrégation */ + sockfd = create_udp_sending_socket(argv[1], AGGREGATE_DEFAULT_PORT, &server, &client) ; + if (sockfd < 0) + { + perror("Erreur ! Impossible de créer la socket vers le serveur d'aggrégation \n"); + return ERR_CREATING_SOCKET ; + } + + + /* Envoi des infos au serveur d'aggrégation */ + nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; + if (nsent != (ssize_t) buf_size) + { + perror("Erreur lors de l'envoi des infos au serveur ") ; + return ERR_SENDING_INFO ; + } + + if (argc == 6) + for (i = 0 ; i < 19 ; i++) + { + nsent = sendto(sockfd, (void *) buf, buf_size, 0, (struct sockaddr *) &server, (socklen_t) sizeof(server)) ; + if (nsent != (ssize_t) buf_size) + { + perror("Erreur lors de l'envoi des infos au serveur ") ; + return ERR_SENDING_INFO ; + } + } + + (void) close(sockfd) ; + + return 0 ; +} diff --git a/loc-bts/code/librtaputil/Makefile b/loc-bts/code/librtaputil/Makefile new file mode 100644 index 0000000..aa9514d --- /dev/null +++ b/loc-bts/code/librtaputil/Makefile @@ -0,0 +1,137 @@ +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/sbin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +CC = gcc + +# Autres outils +AR = ar +RANLIB = ranlib + +# Commandes d'installation et de désinstallation +RM=rm -fv +CP=cp -v + +# Variables générales +LIB_CIBLE=librtaputil +VERSION=1.0 + +# Cibles à construire +STATIC=$(LIB_CIBLE).a +DYNAMIC=$(LIB_CIBLE).so.$(VERSION) +#PROGS= +HEADER=rtaputil.h +#HEADERS= + +# Composition de la bibliothèque +OBJS=$(LIB_CIBLE).o + +# Flags +CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. +DEPFLAGS=-MMD +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG=-fPIC +LIBS= +#STRIPFLAGS= -Wl,-s + + +## Cibles de compilation standard ## + +.PHONY : all dynamic static install install-dynamic install-static install-header uninstall uninstall-dynamic uninstall-static uninstall-header clean purge help + +all : dynamic static +dynamic : $(DYNAMIC) +static : $(STATIC) + +% : %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< +%.so : %.c $(HEADER) + $(CC) $(XCFLAGS) $(PICFLAG) -c -o $@ $< + +# Compilation de la bibliothèque dynamique +$(DYNAMIC) : $(OBJS:.o=.so) + $(CC) -shared -o $@ -Wl,-soname,$@ $(STRIPFLAGS) $(LIBS) -lc $^ + +# Compilation de la bibliothèque statique +$(STATIC) : $(OBJS:.o=.so) + $(RM) $@ + $(AR) cru $@ $^ + $(RANLIB) $@ + + +## Installation ## + +install : install-static install-dynamic + +install-dynamic : install-header $(DYNAMIC) + @$(CP) $(DYNAMIC) $(INSTALL_LIB) &&\ + chmod 644 $(INSTALL_LIB)/$(DYNAMIC) &&\ + chown root:root $(INSTALL_LIB)/$(DYNAMIC) &&\ + echo -e "\n!!! Installation de la bibliothèque dynamique effectuée avec succès.\n!!! Ajoutez une ligne « $(INSTALL_LIB) » dans le fichier /etc/ld.so.conf\n ou dans un nouveau fichier de /etc/ld.so.conf.d/, si ce n'est déjà fait.\n!!! Exécutez ldconfig ensuite.\n" + +install-static : install-header $(STATIC) + @$(CP) $(STATIC) $(INSTALL_LIB) &&\ + chmod 644 $(INSTALL_LIB)/$(STATIC) &&\ + chown root:root $(INSTALL_LIB)/$(STATIC) + +install-header : $(HEADER) + @$(CP) $(HEADER) $(INSTALL_INC) &&\ + chmod 644 $(INSTALL_INC)/$(HEADER) &&\ + chown root:root $(INSTALL_INC)/$(HEADER) + + +## Désinstallation ## + +uninstall : uninstall-dynamic uninstall-static + +uninstall-dynamic : uninstall-header + @$(RM) $(INSTALL_LIB)/$(DYNAMIC) + ldconfig + +uninstall-static : uninstall-header + @$(RM) $(INSTALL_LIB)/$(STATIC) + +uninstall-header : + @$(RM) $(INSTALL_INC)/$(HEADER) + + +## Nettoyage ## + +clean : + @$(RM) *~ *.o $(LIB_CIBLE).so *.d + +purge : clean + @$(RM) $(DYNAMIC) $(STATIC) $(PROGS) + + +## Aide ## + +help : + @echo "Aucune bibliothèques nécessaires à la compilation.\n\ + \n\ + Cibles possibles :\n\ + all (cible par défaut) : Compile la bibliothèque et le programme d'exemple (tx).\n\ + dynamic : Compile la bibilothèque partagée (.so).\n\ + static : Compile la bibliothèque statique (.a).\n\ + tx : Compile le programme d'exemple.\n\ + \n\ + install : Installe la bibliothèque partagée, statique, ainsi que le programme d'exemple.\n\ + install-dynamic : N'installe que la bibliothèque partagée.\n\ + install-static : N'installe que la bibliothèque statique.\n\ + install-tx : N'installe que le programme d'exemple.\n\ + \n\ + uninstall : Désinstalle tout ce qu'il est possible de désinstaller.\n\ + uninstall-dynamic : Désinstalle la bibliothèque partagée.\n\ + uninstall-static : Désinstalle la bibliothèque statique.\n\ + uninstall-tx : Désinstalle le programme d'exemple.\n\ + \n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence $(PREFIX). Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/loc-bts/code/librtaputil/librtaputil.c b/loc-bts/code/librtaputil/librtaputil.c new file mode 100644 index 0000000..b0924a1 --- /dev/null +++ b/loc-bts/code/librtaputil/librtaputil.c @@ -0,0 +1,224 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "rtaputil.h" + + +BOOL run = TRUE ; + + + +/* Convertit une adresse MAC en octets en une chaîne de caractères. + * ¡ Il est nécessaire de libérer manuellement le retour de cette fonction ! + */ +char* mac_bytes_to_string(unsigned char *mac_binary) +{ + char *ret = malloc(sizeof(char) * 18) ; + + sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x", mac_binary[0], mac_binary[1], mac_binary[2], mac_binary[3], mac_binary[4], mac_binary[5]) ; + ret[17] = '\0' ; + + return ret ; +} + + + +/* Convertit un identifiant de canal en son numéro (0 si la fréquence est erronée) */ +char frequency_to_channel(unsigned short channel) +{ + char c = 0 ; // Résultat + + switch (channel) + { + case 2412 : + c = 1 ; + break ; + case 2417 : + c = 2 ; + break ; + case 2422 : + c = 3 ; + break ; + case 2427 : + c = 4 ; + break ; + case 2432 : + c = 5 ; + break ; + case 2437 : + c = 6 ; + break ; + case 2442 : + c = 7 ; + break ; + case 2447 : + c = 8 ; + break ; + case 2452 : + c = 9 ; + break ; + case 2457 : + c = 10 ; + break ; + case 2462 : + c = 11 ; + break ; + case 2467 : + c = 12 ; + break ; + case 2472 : + c = 13 ; + break ; + case 2477 : + c = 14 ; + break ; + } + + return c ; +} + + + +/* Retourne une date au format struct timeval en mili-secondes */ +unsigned long timeval_to_ms(struct timeval d) +{ + return d.tv_sec * 1000 + d.tv_usec / 1000 ; +} + + + +/* Retourne le temps (en mili-secondes) écoulé entre deux dates */ +unsigned long sub_date(struct timeval sup, struct timeval inf) +{ + unsigned long sup_ms = sup.tv_sec * 1000 + sup.tv_usec / 1000 ; + unsigned long inf_ms = inf.tv_sec * 1000 + inf.tv_usec / 1000 ; + + return abs(sup_ms - inf_ms) ; +} + + + +/* Compare deux adresses MAC : retourne TRUE si elles sont égales, FALSE sinon */ +BOOL mac_cmp(unsigned char *mac1, unsigned char *mac2) +{ + int i ; + for(i=0 ; i < 6 ; i++) + if(mac1[i] != mac2[i]) + return FALSE ; + return TRUE ; +} + + + +/* Crée une socket d'envoi UDP et retourne son descripteur. + * Paramètres : + * - server_address : l'adresse IP du serveur. + * - server_port : le port d'écoute du serveur. + * - server_description (paramètre résultat) : la structure dans laquelle sera enregistrée la description du serveur. + * - client_description (paramètre résultat) : la structure dans laquelle sera enregistrée la description du client. + */ +int create_udp_sending_socket(char *server_address, int server_port, struct sockaddr_in *server_description, struct sockaddr_in * client_description) +{ + int sockfd ; // Descripteur de la socket + int ret = 0 ; // Valeur de retour + + /* Ceation de la socket UDP */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; + if (sockfd < 0) + { + perror("Échec de la création de la socket ") ; + return(sockfd) ; + } + + /* Remise à zéro et initialisation de la structure du client */ + bzero((char *) client_description, sizeof(*client_description)) ; + client_description->sin_family = AF_INET ; // Socket INET + client_description->sin_addr.s_addr = htonl(INADDR_ANY) ; // Toutes les connexions + client_description->sin_port = htons(0) ; // N'importe quel port + + /* Réservation d'un port quelconque pour le client */ + ret = bind(sockfd, (struct sockaddr *) client_description, sizeof(*client_description)) ; + if (ret < 0) + { + perror("Impossible de créer la socket (bind) ") ; + (void) close (sockfd) ; + return ret ; + } + + /* Remise à zéro et initialisation de la structure du serveur */ + bzero((char *) server_description, sizeof(*server_description)) ; // RÀZ + server_description->sin_family = AF_INET ; // Socket INET + server_description->sin_addr.s_addr = inet_addr(server_address) ; // Adresse du serveur + server_description->sin_port = htons(server_port) ; // Port d'écoute du serveur + + return (sockfd) ; // On retourne le descripteur de la socket créée +} + + + +/* Crée une socket d'écoute UDP et retourne son descripteur. + * Paramètres : + * - port est le port sur lequel écouter. + */ +int create_udp_listening_socket(int port) +{ + int sockfd ; // Descripteur de la socket + struct sockaddr_in server_description ; // Structure du serveur + int ret = 0 ; // Valeur de retour + + /* Création d'une socket UDP */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0) ; + if (sockfd < 0) + { + perror("Échec de la création de la socket ") ; + return(sockfd) ; + } + + /* Remise à zéro et initialisation de la structure du serveur */ + bzero((char *) &server_description, sizeof(server_description)) ; // RÀZ + server_description.sin_family = AF_INET ; // Socket INET + server_description.sin_addr.s_addr = htonl(INADDR_ANY) ; // Toutes les connexions sont acceptées + server_description.sin_port = htons(port) ; // Port d'écoute + + /* Réservation du port */ + ret = bind(sockfd, (struct sockaddr*) &server_description, sizeof(server_description)) ; + if (ret < 0) + { + perror("Impossible de créer la socket (bind) ") ; + (void) close(sockfd) ; + return ret ; + } + + return sockfd ; // On retourne le descripteur de la socket créée +} + + + +void sigint_handler(int num) +{ + if (num != SIGINT) + { + fprintf(stderr, "Erreur ! Gestionnaire de SIGINT appelé mais le signal n'est pas SIGINT.\n") ; + exit(1) ; + } + + run = FALSE ; + + printf("\nSignal reçu : fin du programme.\n"); + fflush(NULL) ; +} + + + +void sigterm_handler(int num) +{ + if (num != SIGTERM) + { + fprintf(stderr, "Erreur ! Gestionnaire de SIGTERM appelé mais le signal n'est pas SIGINT.\n") ; + exit(1) ; + } + + sigint_handler(SIGINT) ; +} diff --git a/loc-bts/code/librtaputil/rtaputil.h b/loc-bts/code/librtaputil/rtaputil.h new file mode 100644 index 0000000..226094b --- /dev/null +++ b/loc-bts/code/librtaputil/rtaputil.h @@ -0,0 +1,122 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AGGREGATE_DEFAULT_PORT 9900 // Port d'échange des données + + +/* Type booléen */ +typedef enum {FALSE, TRUE} BOOL ; + + +/* Type direction */ +typedef enum {NORTH = 1, EAST, SOUTH, WEST} DIRECTION ; + + +/* Message envoyé par l'AP à l'agrégateur */ +typedef struct _couple_message +{ + unsigned char ap_mac_addr_bytes[6] ; // Adresse MAC de l'AP émetteur de l'info en octets + unsigned char mobile_mac_addr_bytes[6] ; // Adresse MAC du mobile en octets + struct timeval request_time ; // Identifiant du paquet = date sur le client + struct timeval start_time ; // Heure d'arrivée du premier paquet du couple + unsigned char antenna_signal_dbm ; // Puissance du signal reçu par l'AP du mobile + /* Données pour la calibration */ + float x_position ; + float y_position ; + float z_position ; + DIRECTION direction ; // Orientation de la demande de localisation +} couple_message ; + + +/* Types de paquets */ +#define PACKET_TYPE_NORMAL 0 +#define PACKET_TYPE_CALIBRATION 1 + + +/* Position des champs fixes de l'en-tête rtap (octets) */ +#define RTAP_P_HREVISION 0 // Header revision +#define RTAP_P_HPAD 1 // Header pad +#define RTAP_P_HLENGTH 2 // Header length +#define RTAP_P_PRESENTFLAGS 4 // Present flags + + +/* Longueur des champs de l'en-tête rtap (octets) */ +#define RTAP_L_HREVISION 1 // Header revision +#define RTAP_L_HPAD 1 // Header pad +#define RTAP_L_HLENGTH 2 // Header length +#define RTAP_L_PRESENTFLAGS 4 // Present flags +#define RTAP_L_MACTS 8 // MAC timestamp +#define RTAP_L_FLAGS 1 // autre champ de flags +#define RTAP_L_RATE 1 // Data rate +#define RTAP_L_CHANNEL 2 // Channel +#define RTAP_L_CHANNELTYPE 2 // Channel type +#define RTAP_L_ANTENNASIGNALDBM 1 // SSI signal dBm +#define RTAP_L_ANTENNANOISEDBM 1 // SSI noise dBm +#define RTAP_L_ANTENNA 1 // Antenna +#define RTAP_L_FHSS 2 +#define RTAP_L_LOCKQUALITY 2 +#define RTAP_L_TXATTENUATION 2 +#define RTAP_L_TXATTENUATIONDB 2 +#define RTAP_L_TXATTENUATIONDBM 1 +#define RTAP_L_ANTENNASIGNALDB 1 // en dB +#define RTAP_L_ANTENNANOISEDB 1 // en dB +#define RTAP_L_FCS 4 +#define RTAP_L_EXT // Non implémenté + + +/* Positions pour affichage (tableau check de ss_list) */ +#define RTAP_MACTS 0 +#define RTAP_FLAGS 1 +#define RTAP_RATE 2 +#define RTAP_CHANNEL 3 // ainsi que RTAP_CHANNELTYPE +#define RTAP_FHSS 4 +#define RTAP_ANTENNASIGNALDBM 5 +#define RTAP_ANTENNANOISEDBM 6 +#define RTAP_LOCKQUALITY 7 +#define RTAP_TXATTENUATION 8 +#define RTAP_TXATTENUATIONDB 9 +#define RTAP_TXATTENUATIONDBM 10 +#define RTAP_ANTENNA 11 +#define RTAP_ANTENNASIGNALDB 12 +#define RTAP_ANTENNANOISEDB 13 +#define RTAP_FCS 14 + + +/* Variables globales */ +BOOL run ; + + +/* En-têtes de fonctions */ +// Fonctions utilitaires +char* mac_bytes_to_string(unsigned char *mac_binary) ; +char frequency_to_channel(unsigned short channel) ; +unsigned long timeval_to_ms(struct timeval date) ; +unsigned long sub_date(struct timeval sup, struct timeval inf) ; +BOOL mac_cmp(unsigned char *mac1, unsigned char *mac2) ; + +// Signaux +void sigint_handler(int num) ; +void sigterm_handler(int num) ; + +// Réseau +int create_udp_listening_socket(int port) ; +int create_udp_sending_socket(char *server_address, int server_port, struct sockaddr_in *server_description, struct sockaddr_in * client_description) ; diff --git a/loc-bts/code/rtap.sh b/loc-bts/code/rtap.sh new file mode 100755 index 0000000..a318f82 --- /dev/null +++ b/loc-bts/code/rtap.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +rmmod ipw2200 +modprobe ipw2200 rtap_iface=1 +ifconfig rtap0 up diff --git a/loc-bts/code/rtapaggregate/Makefile b/loc-bts/code/rtapaggregate/Makefile new file mode 100644 index 0000000..92fe491 --- /dev/null +++ b/loc-bts/code/rtapaggregate/Makefile @@ -0,0 +1,74 @@ +# Répertoire d'installation +PREFIX=/usr/local +INSTALL_DIR= $(PREFIX)/bin +INSTALL_LIB= $(PREFIX)/lib +INSTALL_INC= $(PREFIX)/include +INSTALL_MAN= $(PREFIX)/share/man + +# Compilateur +CC = gcc + +# Commandes d'installation et de désinstallation +RM=rm -fv +CP=cp -v + +# Cible +TARGET=rtapaggregated +HEADER=rtapaggregate.h + +# Flags +CFLAGS=-O2 -W -Wall -Wstrict-prototypes -I. +DEPFLAGS=-MMD +XCFLAGS=$(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS) +PICFLAG=-fPIC +LIBS=-lpthread ../librtaputil/librtaputil.so.1.0 + + +## Cibles de compilation standard ## + +.PHONY : all install uninstall clean purge help + +all : $(TARGET) + +% : %.o + $(CC) $(LDFLAGS) $(STRIPFLAGS) $(XCFLAGS) -o $@ $^ $(LIBS) +%.o : %.c $(HEADER) + $(CC) $(XCFLAGS) -c $< + +# Compilation du programme +$(TARGET) : $(TARGET).o $(HEADER) + + +## Installation / désinstallation ## + +install : $(TARGET) + @$(CP) $(TARGET) $(INSTALL_DIR) + @cd $(INSTALL_DIR) ; chown root:root $(TARGET) ; chmod 755 $(TARGET) + +uninstall : + @$(RM) $(INSTALL_DIR)/$(TARGET) + + +## Nettoyage ## + +clean : + @$(RM) -fv *~ *.o *.d + +purge : clean + @$(RM) -fv $(TARGET) + + +## Aide ## + +help : + @echo "Bibliothèques nécessaires à la compilation :\n\ + librtaputil1.0 (fournie)\n\ + \n\ + Cibles possibles :\n\ + $(TARGET) (cible par défaut) : Compile le programme $(TARGET).\n\ + install : Installe le programme $(TARGET).\n\ + uninstall : Désinstalle le programme $(TARGET).\n\ + clean : Supprime les fichiers temporaires.\n\ + purge : Supprime le résultat de la compilation.\n\ + \n\ + Note : l'installation se fait dans l'arborescence $(PREFIX). Modifiez la variable PREFIX du Makefile pour changer ce comportement." diff --git a/loc-bts/code/rtapaggregate/rtapaggregate.h b/loc-bts/code/rtapaggregate/rtapaggregate.h new file mode 100644 index 0000000..8cf7cc4 --- /dev/null +++ b/loc-bts/code/rtapaggregate/rtapaggregate.h @@ -0,0 +1,61 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "../librtaputil/rtaputil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define AGGREGATE_TIMEOUT 500 // Timeout d'agrégation (en mili-secondes) +#define KEEP_TIMEOUT 2000 // Temps que l'on conserve les données dans la liste (en mili-secondes) +#define CHECK_INTERVAL 500000 // Temps entre deux vérifications de la liste (en micro-secondes) + +/* Codes d'erreur */ +#define ERR_NO_MESSAGE_RECEIVED 1 // Erreur lors de la lecture sur la socket +#define ERR_CREATING_SOCKET 2 // Erreur lors de la création de la socket d'écoute +#define ERR_BAD_USAGE 3 // Mauvais appel au programme + + +/* Liste chaînée des informations concernant un couple MAC / séquence */ +typedef struct _couple_info_list +{ + unsigned char ap_mac_addr_bytes[6] ; // Adresse MAC de l'AP émetteur de l'info en octets + unsigned char antenna_signal_dbm ; // Puissance du signal reçu par l'AP du mobile + struct _couple_info_list *next ; +} couple_info_list ; + + +/* Liste chaînée des couples MAC / séquence */ +typedef struct _couple_list +{ + unsigned char mobile_mac_addr_bytes[6] ; // Adresse MAC du mobile en octets + struct timeval request_time ; // Numéro de séquence de la demande de localisation du mobile (heure de la demande sur le mobile) + struct timeval start_time ; // Heure d'arrivée du premier paquet du couple + couple_info_list *info ; // Liste des informations pour ce couple + struct _couple_list *next ; + /* Données pour la calibration */ + float x_position ; + float y_position ; + float z_position ; + DIRECTION direction ; // Orientation de la demande de localisation +} couple_list ; + + +/* En-têtes de fonctions */ +void got_couple_info(couple_list **couples, couple_message message) ; +void free_couple_list(couple_list **couples) ; +void print_couple_list(couple_list *couples) ; +void print_couple_info(couple_info_list *info) ; +void* monitor_couple_list(couple_list **couples) ; +void print_usage(char *prog) ; diff --git a/loc-bts/code/rtapaggregate/rtapaggregated.c b/loc-bts/code/rtapaggregate/rtapaggregated.c new file mode 100644 index 0000000..8663e66 --- /dev/null +++ b/loc-bts/code/rtapaggregate/rtapaggregated.c @@ -0,0 +1,359 @@ +/* + * This file is part of the rtap localisation project. + */ + + +#include "rtapaggregate.h" + + +char *out_file ; + + +int main(int argc, char **argv) +{ + int ret = 0 ; // Valeur de retour du programme + couple_list *couples = NULL ; // Liste des données traitées + struct sigaction action ; // Structure de mise en place des gestionnaires de signaux + int sockfd ; // Socket d'écoute UDP + int nread ; // Retour de recvfrom + struct sockaddr_in client; // Structure pour le client UDP + socklen_t client_len = sizeof(client) ; // Taille du client pour la socket + couple_message message ; // Message lu sur la socket + pthread_t thread ; // Thread pour la fonction de surveillance de la liste d'informations agrégées + char *ap_mac_string, *mobile_mac_string ; // Pointeurs pour retour de mac_bytes_to_string() + + if (argc != 2) + { + print_usage(argv[0]) ; + return ERR_BAD_USAGE ; + } + + run = TRUE ; + + + /* Fichier de sortie */ + out_file = malloc((strlen(argv[1]) + 1) * sizeof(char)) ; + strcpy(out_file, argv[1]) ; + + + /* Mise en place des gestionnaires de signaux */ + sigemptyset(&action.sa_mask) ; + action.sa_handler = sigint_handler ; + sigaction(SIGINT, &action, NULL) ; + action.sa_handler = sigterm_handler ; + sigaction(SIGTERM, &action, NULL) ; + + /* Création de la socket UDP */ + if ((sockfd = create_udp_listening_socket(AGGREGATE_DEFAULT_PORT)) < 0) + { + fprintf(stderr, "Erreur ! Impossible d'écouter sur le port %d.\n", AGGREGATE_DEFAULT_PORT) ; + exit(ERR_CREATING_SOCKET) ; + } + + /* Création du thread */ + pthread_create(&thread, NULL, (void *) &monitor_couple_list, &couples) ; + + /* Lecture sur la socket */ + while (run) + { + nread = recvfrom(sockfd, &message, sizeof(message), 0, (struct sockaddr *) &client, &client_len) ; + + if (nread <= 0) + { + if (run) + { + fprintf(stderr, "Aucun message reçu du client !\n") ; + ret = ERR_NO_MESSAGE_RECEIVED ; + } + break ; + } + ap_mac_string = mac_bytes_to_string(message.ap_mac_addr_bytes) ; + mobile_mac_string = mac_bytes_to_string(message.mobile_mac_addr_bytes) ; + printf("\n\ +*** Message reçu du client ***\n\ +\tMAC AP : %s\n\ +\tMAC mobile : %s\n\ +\tNuméro de séquence (heure de la demande) : %lu\n\ +\tHeure d'arrivée de la demande de localisation sur l'AP : %lu\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(message.request_time), + timeval_to_ms(message.start_time), + message.antenna_signal_dbm - 0x100, + message.x_position, + message.y_position, + message.z_position, + message.direction + ) ; + free(ap_mac_string) ; + free(mobile_mac_string) ; + + got_couple_info(&couples, message) ; + } + + (void) close(sockfd) ; // Fermeture de la socket + free_couple_list(&couples) ; // Nettoyage + free(out_file) ; + + printf("%s : fin.\n", argv[0]) ; + return ret ; +} + + + +/* Fonction du thread, qui surveille la liste et envoie les infos au serveur de localisation au bout du timeout */ +void* monitor_couple_list(couple_list **couples) +{ + couple_list *couple_ptr, *couple_prev ; + couple_info_list *couple_info_ptr ; + struct timeval current_time ; + FILE *fd = NULL ; + char *ap_mac_string ; + + fd = fopen(out_file, "a") ; // Ouverture du fichier de sortie en ajout + if (fd == NULL) // Si ouverture échouée, + { + perror("Impossible d'ouvrir le fichier de sortie ") ; + fprintf(stderr, "Redirection de la sortie sur la sortie standard.") ; + fd = stdout ; // on redirige sur stdout + } + + while (run) + { + couple_ptr = *couples ; + couple_prev = NULL ; + couple_info_ptr = NULL ; + gettimeofday(¤t_time, NULL) ; + + while (couple_ptr != NULL) // Parcours de la liste + { + if (couple_ptr->info != NULL) // Si le couple atteint n'a pas déjà été traité + { + if (sub_date(couple_ptr->start_time, current_time) > AGGREGATE_TIMEOUT) // Si le timeout est atteint, + { + printf("* Timeout dépassé.\n") ; + fprintf(fd, "%f;%f;%f;%hhd", couple_ptr->x_position, couple_ptr->y_position, couple_ptr->z_position, couple_ptr->direction) ; // Inscription des infos du couple dans le fichier + + couple_info_ptr = couple_ptr->info ; + while (couple_info_ptr != NULL) // On vide la liste des infos + { + // Inscription des infos de l'AP dans le fichier + ap_mac_string = mac_bytes_to_string(couple_info_ptr->ap_mac_addr_bytes) ; + fprintf(fd, ";%s;%d", ap_mac_string, couple_info_ptr->antenna_signal_dbm - 0x100) ; + free(ap_mac_string) ; + + // Suppression du maillon + couple_info_ptr = couple_info_ptr->next ; + free(couple_ptr->info) ; + couple_ptr->info = couple_info_ptr ; + } + + fprintf(fd, "\n") ; + } + } + + else if (sub_date(couple_ptr->start_time, current_time) > KEEP_TIMEOUT) // Si le couple a été traité et que le temps de garde est écoulé + { + couple_list *couple_tmp = couple_ptr ; + + printf("* Délai de garde dépassé.\n") ; + + couple_ptr = couple_ptr->next ; + + if (couple_prev == NULL) // Si on est en tête de liste, + *couples = couple_ptr ; // on positionne la tête sur le suivant + else + couple_prev->next = couple_ptr ; // sinon on positionne le suivant du précédent sur le suivant. + + free(couple_tmp) ; + + continue ; // On saute les instructions pour aller au suivant puisque c'est déjà fait + } + + // Couple suivant + couple_prev = couple_ptr ; + couple_ptr = couple_ptr->next ; + } + + fflush(NULL) ; + usleep(CHECK_INTERVAL) ; // On attend avant de vérifier à nouveau + } + + fclose(fd) ; + + return NULL ; +} + + + +/* Fonction appelée lors de la réception d'un paquet */ +void got_couple_info(couple_list **couples, couple_message message) +{ + couple_list *tmp_couple = NULL ; + couple_info_list *tmp_info = NULL ; + + tmp_info = malloc(sizeof(couple_info_list)) ; + memcpy(tmp_info->ap_mac_addr_bytes, message.ap_mac_addr_bytes, 6) ; + tmp_info->antenna_signal_dbm = message.antenna_signal_dbm ; + tmp_info->next = NULL ; + + tmp_couple = *couples ; + if (*couples == NULL) // Si la liste de couples n'existe pas encore, + { + printf("Création de la liste des couples.\n") ; + tmp_couple = malloc(sizeof(couple_list)) ; // on la crée. + memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ; + tmp_couple->request_time = message.request_time ; + tmp_couple->start_time = message.start_time ; + tmp_couple->x_position = message.x_position ; + tmp_couple->y_position = message.y_position ; + tmp_couple->z_position = message.z_position ; + tmp_couple->direction = message.direction ; + tmp_couple->next = NULL ; + tmp_couple->info = tmp_info ; + *couples = tmp_couple ; + } + else + { + while (tmp_couple != NULL) // Sinon on cherche si le couple existe déjà dans la liste + { + if(mac_cmp(message.mobile_mac_addr_bytes, tmp_couple->mobile_mac_addr_bytes) == 1 + && message.request_time.tv_usec == tmp_couple->request_time.tv_usec) // Si le couple existe déjà, + break ; // on s'arrête dessus. + tmp_couple = tmp_couple->next ; + } + + if (tmp_couple == NULL) // Si couple inexistant dans la liste + { + printf("Création du couple.\n") ; + tmp_couple = malloc(sizeof(couple_list)) ; // on crée un nouveau couple. + memcpy(tmp_couple->mobile_mac_addr_bytes, message.mobile_mac_addr_bytes, 6) ; + tmp_couple->request_time = message.request_time ; + tmp_couple->start_time = message.start_time ; + tmp_couple->x_position = message.x_position ; + tmp_couple->y_position = message.y_position ; + tmp_couple->z_position = message.z_position ; + tmp_couple->direction = message.direction ; + tmp_couple->next = *couples ; + tmp_couple->info = tmp_info ; + *couples = tmp_couple ; + } + else // Si couple trouvé dans la liste + { + if (tmp_couple->info == NULL) // Si on a déjà envoyé les infos de ce couple au serveur + { + printf("Demande déjà traitée.\n") ; + free(tmp_info) ; + } + else + { + printf("Ajout des informations au couple.\n") ; + tmp_info->next = tmp_couple->info ; // on ajoute l'info. + tmp_couple->info = tmp_info ; + } + } + } +} + + + +/* Vide la liste chaînée de couples */ +void free_couple_list(couple_list **couples) +{ + couple_list *couple_ptr = *couples ; + couple_info_list *couple_info_ptr = NULL ; + + if (*couples != NULL) + { + while (couple_ptr != NULL) + { + couple_info_ptr = couple_ptr->info ; + while (couple_info_ptr != NULL) + { + couple_info_ptr = couple_info_ptr->next ; + free(couple_ptr->info) ; + couple_ptr->info = couple_info_ptr ; + } + couple_ptr = couple_ptr->next ; + free(*couples) ; + *couples = couple_ptr ; + } + } +} + + + +/* Affiche la liste des couples */ +void print_couple_list(couple_list *couples) +{ + couple_list *couple_ptr = couples ; + couple_info_list *info_ptr = NULL ; + char *mobile_mac_string ; + + if (couples == NULL) // Si la liste est vide + { + printf("Aucun couple.\n") ; // on l'affiche. + return ; + } + + while (couple_ptr != NULL) + { + info_ptr = couple_ptr->info ; // On récupère le pointeur de la sous-liste + + mobile_mac_string = mac_bytes_to_string(couple_ptr->mobile_mac_addr_bytes) ; + printf("MAC du mobile : %s\n\ +Numéro de séquence : %lu\n\ +Heure de réception de la demande de localisation : %lu\n\ +\n", + mobile_mac_string, + couple_ptr->request_time.tv_usec, + couple_ptr->start_time.tv_usec + ) ; + free(mobile_mac_string) ; + + while (info_ptr != NULL) // On parcourt toutes les informations relative au couple courant + { + print_couple_info(info_ptr) ; + putchar('\n') ; + info_ptr = info_ptr->next ; + } + + printf("\n\n") ; + + couple_ptr = couple_ptr->next ; + } +} + + + +/* Affiche un maillon d'une couple_info_list */ +void print_couple_info(couple_info_list *info) +{ + char *ap_mac_string ; + if (info == NULL) + return ; + + ap_mac_string = mac_bytes_to_string(info->ap_mac_addr_bytes) ; + printf("\tMAC de l'AP : %s\n\ +\tPuissance du signal : %d dBm\n", + ap_mac_string, + info->antenna_signal_dbm - 0x100 + ) ; + free(ap_mac_string) ; +} + + + +/* Affiche le mode d'emploi du programme */ +void print_usage(char *prog) +{ + printf("Usage :\n\ +\t%s fichier_sortie\n\ +", prog) ; +}