owlps/loc-mobile/code/librtapanalyser/librtapanalyser.c

630 lines
20 KiB
C

/*
* This is the rtapanalyser library, Wi-Fi packet sniffer and analyser,
* thanks to the radiotap header of each packet.
*/
#include "rtapanalyser.h"
/* Convertit une adresse MAC en octets en une chaîne de caractères */
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 le temps écoulé entre deux dates */
unsigned int sub_date(struct timeb sup, struct timeb inf)
{
unsigned int ret = 0 ;
unsigned int sec_sup = sup.time ;
unsigned int sec_inf = inf.time ;
if(sup.millitm < inf.millitm)
{
ret = 1000 + sup.millitm - inf.millitm ;
sec_sup-- ;
}
else
ret = sup.millitm - inf.millitm ;
ret += (sec_sup - sec_inf) * 1000 ;
return ret ;
}
/* 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 ;
}
/* Affiche la liste chaînée des résultats */
void print_mac_list(mac_list *results, BOOL verbose)
{
mac_list *mac_ptr = results ; // Récupère la liste d'adresse MAC en entrée
ss_list *ss_ptr = NULL ; // Initialise la sous-liste
double antenna_signal_average = 0 ; // Moyenne des valeurs récupérées de antenna signal en dBm
double antenna_noise_average = 0; // Moyenne des valeurs récupérées de antenna noise en dBm
double data_rate_average = 0; // Moyenne du débit
unsigned short channel = -1 ; // Canal utilisé pour la MAC courante
unsigned short channel_type = -1 ; // Type de liaison utilisée pour la MAC courante
if (results == NULL) // Si la liste est vide
{
printf("Aucun résultat.\n") ; // on l'affiche.
return ;
}
while (mac_ptr != NULL)
{
//printf("%s\n", mac_bytes_to_string(mac_ptr->mac_addr_bytes)) ; // On convertit l'adresse MAC en chaîne de caractères pour l'afficher
ss_ptr = mac_ptr->samples_list ; // On récupère le pointeur de la sous-liste
antenna_signal_average = 0 ;
antenna_noise_average = 0 ;
data_rate_average = 0 ;
while (ss_ptr != NULL) // On parcourt toutes les valeurs de l'affaiblissement en dB et on en fait la moyenne.
{
antenna_signal_average += pow((double)10, ((double)(ss_ptr->antenna_signal_dbm - 0x100) / 10)) ; // Il faut le minorer de 256 pour avoir la vrai puissance car sinon codage serai sur plus d'un octet.
antenna_noise_average += pow((double)10, ((double)(ss_ptr->antenna_noise_dbm - 0x100) / 10)) ;
data_rate_average += ((ss_ptr->data_rate) / 2);
channel = ss_ptr->channel ;
channel_type = ss_ptr->channel_type ;
if (verbose) // Affichage du maillon si on est en mode verbeux.
{
printf("[%s]\n", mac_bytes_to_string(mac_ptr->mac_addr_bytes)) ;
print_ss_list(ss_ptr) ;
putchar('\n') ;
}
ss_ptr = ss_ptr->next ;
}
/* Calcul des moyennes */
antenna_signal_average = 10 * log10((double)(antenna_signal_average / mac_ptr->nb_samples)) ;
antenna_noise_average = 10 * log10((double)(antenna_noise_average / mac_ptr->nb_samples)) ;
data_rate_average /= (double)mac_ptr->nb_samples ;
/* Affichage */
printf("[%s] [Canal : %hhd] [Fréquence : %hu MHz] [Type de liaison : %#06x] [Moyenne du débit : %0.1f Mo/s] [Moyenne du signal : %0.1f dBm] [Moyenne du bruit : %0.1f dBm]\n", mac_bytes_to_string(mac_ptr->mac_addr_bytes), frequency_to_channel(channel), channel, channel_type, data_rate_average, antenna_signal_average, antenna_noise_average) ;
if (verbose)
printf("\n\n") ;
mac_ptr = mac_ptr->next ;
}
}
/* Affiche un maillon d'une sous-liste de résultats */
void print_ss_list(ss_list *ss)
{
if (ss == NULL)
return ;
/* Champs statiques */
printf("Header revision : %hhu\n", ss->header_revision) ;
printf("Header Pad : %hhu\n", ss->header_pad) ;
printf("Header Length : %hu\n", ss->header_length) ;
printf("Present flags : %#010lx\n", ss->present_flags) ; // Largeur de champ 10 : 2 pour "0x" et 8 pour la valeur.
/* Champs dynamiques */
if (ss->check[RTAP_MACTS])
printf("Mac timestamp : %llu\n", ss->mac_timestamp) ;
if (ss->check[RTAP_FLAGS])
printf("Flags : %hu\n", ss->flags) ;
if (ss->check[RTAP_RATE])
printf("Data rate : %hhd MB/s\n", ss->data_rate / 2) ;
if (ss->check[RTAP_CHANNEL])
printf("Channel : %hu MHz\nChannel Type : %#06x\n", ss->channel, ss->channel_type) ;
if (ss->check[RTAP_FHSS])
printf("FHSS : %hu\n", ss->fhss) ;
if (ss->check[RTAP_ANTENNASIGNALDBM])
printf("Antenna Signal : %d dBm\n", ss->antenna_signal_dbm - 0x100) ;
if (ss->check[RTAP_ANTENNANOISEDBM])
printf("Antenna Noise : %d dBm\n", ss->antenna_noise_dbm - 0x100) ;
if (ss->check[RTAP_LOCKQUALITY])
printf("Lock Quality : %hu\n", ss->lock_quality) ;
if (ss->check[RTAP_TXATTENUATION])
printf("Taux Attenuation : %hu\n", ss->tx_attenuation) ;
if (ss->check[RTAP_TXATTENUATIONDB])
printf("Atténuation : %hu dB\n", ss->tx_attenuation_db) ;
if (ss->check[RTAP_TXATTENUATIONDBM])
printf("Atténuation : %hu dBm\n", ss->tx_attenuation_dbm) ;
if (ss->check[RTAP_ANTENNA])
printf("Antenna : %hhu\n", ss->antenna) ;
if (ss->check[RTAP_ANTENNASIGNALDB])
printf("Antenna Signal : %hhu dB\n", ss->antenna_signal_db) ;
if (ss->check[RTAP_ANTENNANOISEDB])
printf("Antenna Noise : %hhu dB\n", ss->antenna_noise_db) ;
if (ss->check[RTAP_FCS])
printf("FCS : %lu\n", ss->fcs) ;
}
/* Vide la liste chaînée d'adresse MAC */
void free_mac_list(mac_list **results)
{
mac_list *mac_ptr = *results ;
ss_list *ss_ptr = NULL ;
if (*results != NULL)
{
while(mac_ptr != NULL)
{
ss_ptr = mac_ptr->samples_list ;
while (ss_ptr != NULL)
{
ss_ptr = ss_ptr->next ;
free(mac_ptr->samples_list) ;
mac_ptr->samples_list = ss_ptr ;
}
mac_ptr = mac_ptr->next ;
free(*results) ;
*results = mac_ptr ;
}
}
}
/* Enregistre la liste "results" dans le fichier "file" */
int write_mac_list_to_file(char *file, mac_list *results)
{
int fd = 0 ; // Descripteur de fichier.
mac_list *ptr ; // Tête de lecture de la liste chaînée.
ss_list *ss_ptr ; // Tête de lecture de la sous-liste.
int mac_list_size = sizeof(mac_list) ;
int ss_list_size = sizeof(ss_list) ;
//printf("Début de l'enregistrement des résulats dans le fichier « %s »...\n", file) ;
/* Ouverture du fichier */
fd = open(file, O_WRONLY | O_CREAT) ;
if (fd < 0)
{
perror("Impossible d'ouvrir le fichier de sortie ") ;
return ERR_OPENING_FILE ;
}
/* Écriture des données */
ptr = results ; // On commence par la tête de la liste (forcément...).
while (ptr != NULL)
{
//printf("Enregistrement (%s)...\n", mac_bytes_to_string(ptr->mac_addr_bytes)) ;
/* Enregistrement du maillon de la liste principale */
if (write(fd, ptr, mac_list_size) != mac_list_size)
perror("Erreur d'écriture (mac_list) ") ;
/* Enregistrement de la sous-liste */
ss_ptr = ptr->samples_list ;
while (ss_ptr != NULL)
{
if (write(fd, ss_ptr, ss_list_size) != ss_list_size) // Écriture du maillon courant.
perror("Erreur d'écriture (ss_list) ") ;
ss_ptr = ss_ptr->next ;
}
ptr = ptr->next ;
}
/* Fermeture du fichier */
if (close(fd) != 0)
perror("Erreur lors de la fermeture du fichier de sortie ") ;
return 0 ;
}
/* Lit le fichier "file" et enregistre la liste lue dans "results" */
int read_mac_list_from_file(char *file, mac_list **results)
{
int fd = 0 ; // Descripteur de fichier.
mac_list *ptr = NULL ; // Tête de lecture de la liste chaînée.
ss_list *ss_ptr ; // Tête de lecture de la sous-liste.
ss_list *ss_prev ; // Maillon précédent lors de la lecture.
int mac_list_size = sizeof(mac_list) ;
int ss_list_size = sizeof(ss_list) ;
mac_list mac_list_lu ;
ss_list ss_list_lu ;
//printf("Début de la lecture du fichier « %s »...\n", file) ;
/* Ouverture du fichier */
fd = open(file, O_RDONLY) ;
if (fd < 0)
{
perror("Impossible d'ouvrir le fichier d'entrée ") ;
return ERR_OPENING_FILE ;
}
/* Lecture des données */
while (read(fd, &mac_list_lu, mac_list_size) == mac_list_size) // Lecture du premier champ
{
//printf("Lecture (%s)...\n", mac_bytes_to_string(mac_list_lu.mac_addr_bytes)) ; // Affichage de la MAC actuelle.
/* Allocation du maillon courant */
if (*results == NULL)
{
*results = malloc(mac_list_size) ; // Création de la liste
ptr = *results ;
}
else
{
ptr->next = malloc(mac_list_size) ; // Création du maillon suivant
ptr = ptr->next ;
}
*ptr = mac_list_lu ;
/* Lecture de la sous-liste */
ss_prev = NULL ;
ss_ptr = ptr->samples_list ;
while (ss_ptr != NULL)
{
if (read(fd, &ss_list_lu, ss_list_size) != ss_list_size) // Lecture d'un maillon ss_list.
perror("Erreur de lecture (ss_list) ") ;
else // Si on a bien lu un maillon entier :
{
if (ss_prev == NULL) // Si c'est le premier maillon,
{
ptr->samples_list = malloc(ss_list_size) ; // allocation du premier maillon.
ss_ptr = ptr->samples_list ;
}
else // Si ce n'est pas le premier maillon,
{
ss_prev->next = malloc(ss_list_size) ; // allocation d'un nouveau maillon.
ss_ptr = ss_prev->next ;
}
*ss_ptr = ss_list_lu ;
ss_prev = ss_ptr ;
ss_ptr = ss_ptr->next ;
}
}
if (ss_prev != NULL)
ss_prev->next = NULL ;
}
//printf("Fin de la lecture.\n") ;
if (ptr != NULL)
ptr->next = NULL ;
/* Fermeture du fichier */
if (close(fd) != 0)
perror("Erreur lors de la fermeture du fichier de sortie ") ;
return 0 ;
}
/* Capture des paquets en utilisant l'interface "capture_iface" pendant "capture_time" mili-secondes, et enregistre les paquets lus dans "results" */
int capture(char *capture_iface, unsigned long capture_time, mac_list **results, BOOL print_values)
{
pcap_t *handle ; // Descripteur de capture de paquets
char errbuf[PCAP_ERRBUF_SIZE] ;// Message d'erreur
struct timeb tbegin, tcurrent ;
/* 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, results, print_values) ; // On appelle la fonction read_packet() avec les mêmes arguments, plus "results" que l'on passe en modification, et "print_values" qui indique si on doit afficher le paquet.
}
if (capture_time < 1) // Le temps de capture doit être d'au moins 1 ms.
{
fprintf(stderr, "Durée de capture incorrecte !\n") ;
return ERR_CAPTURE_TIME_FORMAT ;
}
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) ;
}
ftime(&tbegin) ; // Récupère l'heure courante (heure du lancement de la capture)
while(1)
{
pcap_loop(handle, 1, got_packet, NULL) ; // Collecte 1 paquet et appelle la fonction got_packet quand pcaploop a recupéré des paquets
ftime(&tcurrent) ; // Récupère l'heure courante
if(sub_date(tcurrent, tbegin) > capture_time) // Si le temps de capture est écoulé
break ; // on arrête la collecte.
}
pcap_close(handle) ; // Arrêt de la capture.
return 0 ;
}
/* Traite un paquet et enregistre les valeurs dans la liste des résultats (results) */
void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet, mac_list **results, BOOL print_values)
{
mac_list *tmp_mac = NULL ;
ss_list *tmp_ss = NULL ;
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 ;
// unsigned int ss_position = 0 ;
unsigned char mac_addr_binary[6] ;
// unsigned char *mac_addr_string ;
// int rtap_data_size[15] = {8,1,1,4,2,1,1,2,2,2,1,1,1,1,4} ;
int k=0;
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 == 0x80) // Si c'est un beacon on le traite
{
memcpy(mac_addr_binary, &data[rtap_bytes+10], 6); // Dans le cas du beacon, l'adresse MAC est 10 octets plus loin
memcpy(&rtap_presentflags, &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS); // Récupère les flags de l'en-tête rtap
/* Ajout du résultat du scan à la structure */
tmp_ss = malloc(sizeof(ss_list)) ;
tmp_ss->next = NULL ;
memcpy(&(tmp_ss->header_revision), &data[RTAP_P_HREVISION], RTAP_L_HREVISION) ;
memcpy(&(tmp_ss->header_pad), &data[RTAP_P_HPAD], RTAP_L_HPAD) ;
memcpy(&(tmp_ss->header_length), &data[RTAP_P_HLENGTH], RTAP_L_HLENGTH) ;
memcpy(&(tmp_ss->present_flags), &data[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ;
for(k=0 ; k < 15 ; k++)
tmp_ss->check[k] = FALSE ;
rtap_position = 8 ; // début des champs déterminés par le present flag
if (print_values)
{
printf("[%s]\n", mac_bytes_to_string(mac_addr_binary)) ;
printf("Header revision : %hhu\n", tmp_ss->header_revision) ;
printf("Header Pad : %hhu\n", tmp_ss->header_pad) ;
printf("Header Length : %hu\n", tmp_ss->header_length) ;
printf("Present flags : %#010lx\n", tmp_ss->present_flags) ;
}
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:
memcpy(&(tmp_ss->mac_timestamp), &data[rtap_position], RTAP_L_MACTS) ;
tmp_ss->check[RTAP_MACTS] = TRUE ;
if (print_values)
printf("Mac timestamp : %llu\n", tmp_ss->mac_timestamp) ;
rtap_position += RTAP_L_MACTS ;
break ;
case RTAP_FLAGS:
memcpy(&(tmp_ss->flags), &data[rtap_position], RTAP_L_FLAGS) ;
tmp_ss->check[RTAP_FLAGS] = TRUE;
if (print_values)
printf("Flags : %hu\n", tmp_ss->flags);
rtap_position += RTAP_L_FLAGS ;
break ;
case RTAP_RATE:
memcpy(&(tmp_ss->data_rate), &data[rtap_position], RTAP_L_RATE) ;
tmp_ss->check[RTAP_RATE] = TRUE;
if (print_values)
printf("Data rate : %hhd MB/s\n", tmp_ss->data_rate / 2) ;
rtap_position += RTAP_L_RATE ;
break ;
case RTAP_CHANNEL:
memcpy(&(tmp_ss->channel), &data[rtap_position], RTAP_L_CHANNEL) ;
rtap_position += RTAP_L_CHANNEL ;
tmp_ss->check[RTAP_CHANNEL] = TRUE;
memcpy(&(tmp_ss->channel_type), &data[rtap_position], RTAP_L_CHANNELTYPE) ;
if (print_values)
printf("Channel : %hu MHz\nChannel Type : %#06x\n", tmp_ss->channel, tmp_ss->channel_type);
rtap_position += RTAP_L_CHANNELTYPE ;
break ;
case RTAP_FHSS:
memcpy(&(tmp_ss->fhss), &data[rtap_position], RTAP_L_FHSS) ;
tmp_ss->check[RTAP_FHSS] = TRUE;
if (print_values)
printf("FHSS : %hu\n", tmp_ss->fhss);
rtap_position += RTAP_L_FHSS ;
break ;
case RTAP_ANTENNASIGNALDBM:
memcpy(&(tmp_ss->antenna_signal_dbm), &data[rtap_position], RTAP_L_ANTENNASIGNALDBM) ;
tmp_ss->check[RTAP_ANTENNASIGNALDBM] = TRUE;
if (print_values)
printf("Antenna Signal : %d dBm\n", tmp_ss->antenna_signal_dbm - 0x100);
rtap_position += RTAP_L_ANTENNASIGNALDBM ;
break ;
case RTAP_ANTENNANOISEDBM:
memcpy(&(tmp_ss->antenna_noise_dbm), &data[rtap_position], RTAP_L_ANTENNANOISEDBM) ;
tmp_ss->check[RTAP_ANTENNANOISEDBM] = TRUE;
if (print_values)
printf("Antenna Noise : %d dBm\n", tmp_ss->antenna_noise_dbm - 0x100);
rtap_position += RTAP_L_ANTENNANOISEDBM ;
break ;
case RTAP_LOCKQUALITY:
memcpy(&(tmp_ss->lock_quality), &data[rtap_position], RTAP_L_LOCKQUALITY) ;
tmp_ss->check[RTAP_LOCKQUALITY] = TRUE;
if (print_values)
printf("Lock Quality : %hu\n", tmp_ss->lock_quality);
rtap_position += RTAP_L_LOCKQUALITY ;
break ;
case RTAP_TXATTENUATION:
memcpy(&(tmp_ss->tx_attenuation), &data[rtap_position], RTAP_L_TXATTENUATION) ;
tmp_ss->check[RTAP_TXATTENUATION] = TRUE;
if (print_values)
printf("Taux Attenuation : %hu\n", tmp_ss->tx_attenuation);
rtap_position += RTAP_L_TXATTENUATION ;
break ;
case RTAP_TXATTENUATIONDB:
memcpy(&(tmp_ss->tx_attenuation_db), &data[rtap_position], RTAP_L_TXATTENUATIONDB) ;
tmp_ss->check[RTAP_TXATTENUATIONDB] = TRUE;
if (print_values)
printf("Atténuation : %hu dB\n", tmp_ss->tx_attenuation_db);
rtap_position += RTAP_L_TXATTENUATIONDB ;
break ;
case RTAP_TXATTENUATIONDBM:
memcpy(&(tmp_ss->tx_attenuation_dbm), &data[rtap_position], RTAP_L_TXATTENUATIONDBM) ;
tmp_ss->check[RTAP_TXATTENUATIONDBM] = TRUE;
if (print_values)
printf("Atténuation : %hu dBm\n", tmp_ss->tx_attenuation_dbm);
rtap_position += RTAP_L_TXATTENUATIONDBM ;
break ;
case RTAP_ANTENNA:
memcpy(&(tmp_ss->antenna), &data[rtap_position], RTAP_L_ANTENNA) ;
tmp_ss->check[RTAP_ANTENNA] = TRUE;
if (print_values)
printf("Antenna : %hhu\n", tmp_ss->antenna);
rtap_position += RTAP_L_ANTENNA ;
break ;
case RTAP_ANTENNASIGNALDB:
memcpy(&(tmp_ss->antenna_signal_db), &data[rtap_position], RTAP_L_ANTENNASIGNALDB) ;
tmp_ss->check[RTAP_ANTENNASIGNALDB] = TRUE;
if (print_values)
printf("Antenna Signal : %hhu dB\n", tmp_ss->antenna_signal_db);
rtap_position += RTAP_L_ANTENNASIGNALDB ;
break ;
case RTAP_ANTENNANOISEDB:
memcpy(&(tmp_ss->antenna_noise_db), &data[rtap_position], RTAP_L_ANTENNANOISEDB) ;
tmp_ss->check[RTAP_ANTENNANOISEDB] = TRUE;
if (print_values)
printf("Antenna Noise : %hhu dB\n", tmp_ss->antenna_noise_db);
rtap_position += RTAP_L_ANTENNANOISEDB ;
break ;
case RTAP_FCS:
memcpy(&(tmp_ss->fcs), &data[rtap_position], RTAP_L_FCS) ;
tmp_ss->check[RTAP_FCS] = TRUE;
if (print_values)
printf("FCS : %lu\n", tmp_ss->fcs) ;
rtap_position += RTAP_L_FCS ;
break ;
}
}
rtap_presentflags /= 2 ;
}
if (print_values)
printf("\n") ;
tmp_mac = *results ;
if(*results == NULL) // Si la liste de résultats n'existe pas encore,
{
tmp_mac = malloc(sizeof(mac_list)) ; // on la crée.
memcpy(tmp_mac->mac_addr_bytes, mac_addr_binary, 6) ;
tmp_mac->nb_samples = 1 ;
tmp_mac->next = NULL ;
tmp_mac->samples_list = tmp_ss ;
*results = tmp_mac ;
}
else
{
while(tmp_mac != NULL)
{
if(mac_cmp(mac_addr_binary, tmp_mac->mac_addr_bytes) == 1)
break ;
tmp_mac = tmp_mac->next ;
}
if(tmp_mac == NULL)
{
tmp_mac = malloc(sizeof(mac_list)) ;
memcpy(tmp_mac->mac_addr_bytes, mac_addr_binary, 6) ;
tmp_mac->nb_samples = 1 ;
tmp_mac->next = *results ;
tmp_mac->samples_list = tmp_ss ;
*results = tmp_mac ;
}
else
{
tmp_mac->nb_samples++ ;
tmp_ss->next = tmp_mac->samples_list ;
tmp_mac->samples_list = tmp_ss ;
}
}
}
}