00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdlib.h>
00014 #include <errno.h>
00015 #include <string.h>
00016 #include <assert.h>
00017 #include <asm/types.h>
00018 #include <sys/types.h>
00019 #include <sys/socket.h>
00020 #include <sys/ioctl.h>
00021 #include <sys/socket.h>
00022 #include <arpa/inet.h>
00023 #include <netinet/in.h>
00024 #include <linux/wireless.h>
00025
00026 #include "util.h"
00027 #include "hashtable.h"
00028 #include "dyn_iwspy_rec.h"
00029 #include "debug.h"
00030
00031 #ifndef TRUE
00032 #define TRUE 1
00033 #endif
00034
00035 #ifndef FALSE
00036 #define FALSE 0
00037 #endif
00038
00039 #define DEBUG_FLAG '5'
00040
00041
00042 #define IMG_X 1000
00043 #define IMG_Y 300
00044 #define G_IMG_X 1500
00045 #define G_IMG_Y 400
00046 #define Q_RANGE 100
00047
00048 static struct hashtable *rec_hash;
00049 static int rec_num;
00050 struct timeval start_time;
00051 int new_dump = 1;
00052
00053
00054 static int hashfunc(void *key, const int hashsize)
00055 {
00056 __u8 hash;
00057 __u32 data;
00058
00059 data = *((__u32 *) key);
00060
00061
00062 hash = (__u8)((data & 0xff000000) >> 24) ^
00063 (__u8)((data & 0x00ff0000) >> 16) ^
00064 (__u8)((data & 0x0000ff00) >> 8) ^
00065 (__u8)(data & 0x000000ff);
00066
00067 return ((int) hash);
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 static int cmpfunc(void *key, struct node *cmprd)
00083 {
00084 __u32 data1;
00085 struct hw_record *data2;
00086
00087 if (key == NULL) {
00088 DEBUG(DEBUG_FLAG, "rec, cmpfunc:\n"
00089 "value for argument 'key' was NULL !\n"
00090 "Illegal value, returning 0 ! \n");
00091 return 0;
00092 }
00093 if (cmprd == NULL) {
00094 DEBUG(DEBUG_FLAG, "rec, cmpfunc:\n"
00095 "value for argument 'cmpd' was NULL !\n"
00096 "Illegal value, returning 0 ! \n");
00097 return 0;
00098 }
00099
00100 data1 = *((__u32 *)key);
00101 data2 = (struct hw_record *) cmprd;
00102
00103
00104 if (!memcmp(&data1, &data2->hw[2], sizeof(__u32)))
00105 return 1;
00106
00107 return 0;
00108 }
00109
00110
00111 int rec_init(void)
00112 {
00113
00114 rec_num = 0;
00115 rec_hash = NULL;
00116 rec_hash = hashtable_init(REC_HASH_SIZE);
00117 if (rec_hash == NULL)
00118 return -1;
00119
00120 return 0;
00121 }
00122
00123
00124 int rec_clean(struct node *node, void *data)
00125 {
00126 struct hw_record *entry = (struct hw_record *) node;
00127 struct qual_entry *list = entry->quals;
00128 struct qual_entry *tmp;
00129
00130 DEBUG(DEBUG_FLAG, "rec_clean\n");
00131 while (list != NULL) {
00132 tmp = list;
00133 list = list->next;
00134 free(tmp);
00135 }
00136 hashtable_remove(node);
00137 free(entry);
00138 new_dump = 1;
00139
00140 return 1;
00141 }
00142
00143
00144 void rec_clean_up(void)
00145 {
00146 DEBUG(DEBUG_FLAG, "rec_clean_up\n");
00147 if (rec_hash == NULL)
00148 return;
00149 hashtable_iterator(rec_hash, rec_clean, NULL);
00150 hashtable_destroy(rec_hash);
00151 rec_hash = NULL;
00152 }
00153
00154
00155 static struct qual_entry *alloc_qual_entry(void)
00156 {
00157 struct qual_entry *qual;
00158
00159 qual = (struct qual_entry *)
00160 malloc(sizeof(struct qual_entry));
00161 if (!qual) {
00162 DEBUG(DEBUG_FLAG, "alloc_qual_entry: malloc failed\n");
00163 return NULL;
00164 }
00165 memset(qual, 0, sizeof(struct qual_entry));
00166
00167 return qual;
00168 }
00169
00170
00171
00172 static int qual_add(struct hw_record *rec,
00173 struct iw_quality *qual,
00174 struct timeval *t)
00175 {
00176 struct qual_entry *entry;
00177 unsigned int c;
00178
00179 if (!rec->quals) {
00180 rec->quals = alloc_qual_entry();
00181 if (!rec->quals) {
00182 DEBUG(DEBUG_FLAG, "qual_add:"
00183 "alloc_qual_entry failed\n");
00184 return -1;
00185 }
00186 rec->tail = rec->quals;
00187 } else if (rec->tail->current >= REC_NODE_CHUNK) {
00188 DEBUG(DEBUG_FLAG, "qual_add: New CHUNK\n");
00189
00190 rec->tail->next = (struct qual_entry *)
00191 malloc(sizeof(struct qual_entry));
00192 if (!rec->tail->next) {
00193 DEBUG(DEBUG_FLAG, "qual_add:"
00194 " malloc failed\n");
00195 return -1;
00196 }
00197 rec->tail = rec->tail->next;
00198 memset(rec->tail, 0, sizeof(struct qual_entry));
00199 }
00200
00201 entry = rec->tail;
00202 c = entry->current;
00203
00204 assert(c >= 0 && c <= REC_NODE_CHUNK);
00205
00206 if (qual->qual > 200)
00207 entry->qual[c].qual = 0;
00208 else
00209 entry->qual[c].qual = qual->qual;
00210 entry->qual[c].level = qual->level;
00211 entry->qual[c].noise = qual->noise;
00212 entry->tstamp[c].tv_sec = t->tv_sec;
00213 entry->tstamp[c].tv_usec = t->tv_usec;
00214 entry->current++;
00215
00216 DEBUG(DEBUG_FLAG, "qual_add: %s - %d\n",
00217 inet_ntoa(rec->ip_addr), entry->current);
00218
00219 return 0;
00220 }
00221
00222
00223 int rec_add_qual(char *hw, struct iw_quality *qual, struct timeval *tstamp)
00224 {
00225 struct hw_record *recs;
00226 int ret;
00227
00228 assert(rec_hash != NULL);
00229 recs = (struct hw_record *)
00230 hashtable_fetch(rec_hash, hashfunc, &hw[2], cmpfunc);
00231
00232 if (!recs) {
00233 DEBUG(DEBUG_FLAG, "rec_add_qual: record not found!\n");
00234 return 1;
00235 }
00236
00237 ret = qual_add(recs, qual, tstamp);
00238 if (ret < 0)
00239 DEBUG(DEBUG_FLAG, "rec_add_qual: qual entry add failed\n");
00240
00241 return ret;
00242 }
00243
00244
00245 int rec_add(char *hw, struct iw_quality *qual, struct timeval *t,
00246 struct in_addr addr)
00247 {
00248 struct hw_record *recs;
00249 int ret;
00250
00251 if (new_dump) {
00252 new_dump = 0;
00253 start_time.tv_sec = t->tv_sec;
00254 start_time.tv_usec = t->tv_usec;
00255 DEBUG(DEBUG_FLAG, "rec_add: start time %ld\n",
00256 start_time.tv_sec);
00257 }
00258
00259 assert(rec_hash != NULL);
00260 recs = (struct hw_record *)
00261 hashtable_fetch(rec_hash, hashfunc, &hw[2],
00262 cmpfunc);
00263
00264 if (recs) {
00265
00266 ret = qual_add(recs, qual, t);
00267 if (ret < 0)
00268 DEBUG(DEBUG_FLAG, "rec_add: qual entry add failed "
00269 "(old mac)\n");
00270 return ret;
00271 }
00272
00273
00274 recs = (struct hw_record *) malloc(sizeof(struct hw_record));
00275 if (!recs) {
00276 DEBUG(DEBUG_FLAG, "rec_add: malloc failed\n");
00277
00278
00279
00280 return -1;
00281 }
00282 memcpy(recs->hw, hw, ETH_ALEN);
00283 recs->ip_addr.s_addr = addr.s_addr;
00284 recs->quals = NULL;
00285 recs->tail = recs->quals;
00286
00287
00288 list_init_node(&recs->hashnode);
00289 ret = hashtable_add(rec_hash, hashfunc, &hw[2], &recs->hashnode);
00290 if (ret != TRUE) {
00291 DEBUG(DEBUG_FLAG, "rec_add: hashtable_add failed\n");
00292 return -1;
00293 }
00294 rec_num++;
00295
00296
00297 ret = qual_add(recs, qual, t);
00298 if (ret < 0) {
00299 DEBUG(DEBUG_FLAG, "rec_add: qual entry add "
00300 "failed (new mac)\n");
00301 return -1;
00302 }
00303
00304 return ret;
00305 }
00306
00307
00308 int rec_add_long(struct sockaddr *hwa, unsigned char *hw,
00309 struct in_addr addr, struct iw_quality *qual,
00310 struct timeval *t, int monitored)
00311 {
00312 int index = -1, i;
00313
00314
00315 DEBUG(DEBUG_FLAG, "rec_add_long (%s)\n",
00316 inet_ntoa(addr));
00317
00318 for (i = 0 ; i < monitored; i++) {
00319 if (!(memcmp(hwa[i].sa_data, hw, ETH_ALEN)))
00320 index = i;
00321 }
00322 if (index < 0) {
00323 DEBUG(DEBUG_FLAG, "rec_add: MAC address not found\n");
00324 return -1;
00325 }
00326
00327 return (rec_add((char *)&(hwa[index].sa_data), &qual[index], t, addr));
00328 }
00329
00330
00331
00332
00333
00334
00335 static int dump_fa(struct node *node, void *data)
00336 {
00337 struct hw_record *rec = (struct hw_record *) node;
00338 struct qual_entry *qual = rec->quals;
00339 FILE *fd, *header;
00340 char name[FILENAME_MAX];
00341 unsigned int i, len;
00342 unsigned long range_sec = 0, range_dmsec = 0;
00343 #ifdef TEST
00344 unsigned long diff;
00345 #endif
00346 long range_usec = 0;
00347 struct dump *info = (struct dump *)data;
00348
00349
00350 snprintf(name, FILENAME_MAX, "FA-%s-dump.dat",
00351 inet_ntoa(rec->ip_addr));
00352 fd = fopen(name, "w");
00353 if (!fd) {
00354 DEBUG(DEBUG_FLAG, "dump_fa: fopen: %s\n",
00355 strerror(errno));
00356 return -1;
00357 }
00358
00359
00360 fprintf(fd, "# %d %d\n", info->interval, info->output_type);
00361
00362 fprintf(fd, "# %s %s\n", inet_ntoa(rec->ip_addr),
00363 ether_hwtoa((unsigned char *)rec->hw));
00364 i = 0;
00365 while (qual != NULL && i <= qual->current-1) {
00366
00367 range_sec = qual->tstamp[i].tv_sec - start_time.tv_sec;
00368 if (info->output_type == 1) {
00369 fprintf(fd, "%lu %u\n", range_sec, qual->qual[i].qual);
00370 } else if (info->output_type == 2) {
00371
00372 range_usec = qual->tstamp[i].tv_usec -
00373 start_time.tv_usec;
00374 if (range_usec < 0) {
00375 range_sec--;
00376 range_usec += 1000000;
00377 }
00378 range_dmsec = range_sec * 100 + range_usec/10000;
00379 #ifdef TEST
00380 if (i > 0) {
00381 diff = (qual->tstamp[i].tv_sec -
00382 qual->tstamp[i-1].tv_sec) * 1000000 -
00383 qual->tstamp[i-1].tv_usec +
00384 qual->tstamp[i].tv_usec;
00385 }
00386 fprintf(fd, "%lu.%lu %u (%lu)\n", range_sec,
00387 range_usec, qual->qual[i].qual, diff);
00388 #else
00389 fprintf(fd, "%lu %u\n", range_dmsec,
00390 qual->qual[i].qual);
00391 #endif
00392 } else if (info->output_type == 3) {
00393 fprintf(fd, "%lu %u\n", qual->tstamp[i].tv_sec*1000+
00394 qual->tstamp[i].tv_usec/1000 -
00395 (start_time.tv_sec*1000-
00396 start_time.tv_usec/1000),
00397 qual->qual[i].qual);
00398 } else if (info->output_type == 4) {
00399
00400 fprintf(fd, "%lu %u\n", qual->tstamp[i].tv_sec*100+
00401 qual->tstamp[i].tv_usec/10000,
00402 qual->qual[i].qual);
00403 } else if (info->output_type == 0) {
00404 fprintf(fd, "%d", qual->qual[i].qual);
00405 } else {
00406 fprintf(stderr, "Unknown output type! (%d)\n",
00407 info->output_type);
00408 fclose(fd);
00409 return -1;
00410 }
00411
00412 if (qual->current >= REC_NODE_CHUNK &&
00413 i >= (qual->current-1) && qual->next != NULL) {
00414 qual = qual->next;
00415 i = 0;
00416 DEBUG(DEBUG_FLAG, "dump_fa: Next qual node\n");
00417 } else
00418 i++;
00419 }
00420
00421 if (info->output_type > 0 && range_sec > 0) {
00422
00423 snprintf(name, FILENAME_MAX, "FA-%s-dump.plot",
00424 inet_ntoa(rec->ip_addr));
00425 header = fopen(name, "w");
00426 if (!header) {
00427 DEBUG(DEBUG_FLAG, "dump_fa: fopen: %s\n",
00428 strerror(errno));
00429 fclose(fd);
00430 return -1;
00431 }
00432 fprintf(header, "set output \"%s.gif\"\n",
00433 inet_ntoa(rec->ip_addr));
00434 if (info->output_type == 1)
00435 fprintf(header, "set terminal gif small size %d,%d\n"
00436 "set xlabel \"Time t/s\"\n"
00437 "set ylabel \"Quality\"\n"
00438 "plot [0:%ld] [0:%d] 'FA-%s-dump.dat' title "
00439 "\"FA (%s)\" with lines lt 3 \n",
00440 IMG_X, IMG_Y, range_sec, Q_RANGE,
00441 inet_ntoa(rec->ip_addr),
00442 inet_ntoa(rec->ip_addr));
00443 else if (info->output_type == 2)
00444 fprintf(header, "set terminal gif small size %d,%d\n"
00445 "set xlabel \"Time t/10msec\"\n"
00446 "set ylabel \"Quality\"\n"
00447 "plot [%ld:%ld] [0:%d] 'FA-%s-dump.dat' "
00448 "title \"FA (%s)\" with lines lt 3 \n",
00449 IMG_X, IMG_Y, start_time.tv_sec*100,
00450 start_time.tv_sec*100+range_sec*100, Q_RANGE,
00451 inet_ntoa(rec->ip_addr),
00452 inet_ntoa(rec->ip_addr));
00453 else if (info->output_type == 3)
00454 fprintf(header, "set terminal gif small size %d,%d\n"
00455 "set xlabel \"Time t/ms\"\n"
00456 "set ylabel \"Quality\"\n"
00457 "plot [0:%ld] [0:%d] 'FA-%s-dump.dat' title "
00458 "\"FA (%s)\" with lines lt 3 \n",
00459 IMG_X, IMG_Y, range_sec*1000, Q_RANGE,
00460 inet_ntoa(rec->ip_addr),
00461 inet_ntoa(rec->ip_addr));
00462 else if (info->output_type == 4)
00463 fprintf(header, "set terminal gif small size %d,%d\n"
00464 "set xlabel \"Time t/ms\"\n"
00465 "set ylabel \"Quality\"\n"
00466 "plot [%ld:%ld] [0:%d] 'FA-%s-dump.dat' title "
00467 "\"FA (%s)\" with lines lt 3 \n",
00468 IMG_X, IMG_Y, start_time.tv_sec*1000,
00469 start_time.tv_sec*1000+range_sec, Q_RANGE,
00470 inet_ntoa(rec->ip_addr),
00471 inet_ntoa(rec->ip_addr));
00472
00473 len = strlen(info->plot_str);
00474 if (len + 100 < PLOT_STR_SIZE)
00475 snprintf(&info->plot_str[len], 100,
00476 "'FA-%s-dump.dat' title \"FA %s\" "
00477 "with lines, ", inet_ntoa(rec->ip_addr),
00478 inet_ntoa(rec->ip_addr));
00479 fclose(header);
00480 }
00481
00482 fclose(fd);
00483 return 1;
00484 }
00485
00486
00487 int rec_dump(int type, int interval)
00488 {
00489 struct dump info;
00490 char name[FILENAME_MAX];
00491 long range;
00492 int len;
00493 FILE *header;
00494 struct timeval stop_time;
00495
00496 DEBUG(DEBUG_FLAG, "rec_dump\n");
00497
00498 if (rec_hash == NULL) {
00499 DEBUG(DEBUG_FLAG, "rec_dump: hashtable NULL\n");
00500 return -1;
00501 }
00502 memset(&info, 0, sizeof(info));
00503 info.output_type = type;
00504 info.interval = interval;
00505 hashtable_iterator(rec_hash, dump_fa, &info);
00506 len = strlen(info.plot_str);
00507
00508 if (len <= 0) {
00509 DEBUG(DEBUG_FLAG, "rec_dump: info plot string < 0\n");
00510 return 0;
00511 }
00512
00513
00514 snprintf(name, FILENAME_MAX, "group.plot");
00515 header = fopen(name, "w");
00516 if (header == NULL) {
00517 DEBUG(DEBUG_FLAG, "rec_dump: fopen: %s\n",
00518 strerror(errno));
00519 return -1;
00520 }
00521 gettimeofday(&stop_time, NULL);
00522 range = stop_time.tv_sec - start_time.tv_sec;
00523 fprintf(header, "set output \"group.gif\"\n");
00524 if (type == 1)
00525 fprintf(header, "set terminal gif large size %d,%d\n"
00526 "set xlabel \"Time t/s\"\n"
00527 "set ylabel \"Quality\"\n"
00528 "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range,
00529 Q_RANGE);
00530 else if (type == 2 || type == 4)
00531 fprintf(header, "set terminal gif large size %d,%d\n"
00532 "set xlabel \"Time t/10msec\"\n"
00533 "set ylabel \"Quality\"\n"
00534 "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range*100,
00535 Q_RANGE);
00536
00537 else if (type == 3)
00538 fprintf(header, "set terminal gif large size %d,%d\n"
00539 "set xlabel \"Time t/ms\"\n"
00540 "set ylabel \"Quality\"\n"
00541 "plot [0:%ld] [0:%d] ", G_IMG_X, G_IMG_Y, range*1000,
00542 Q_RANGE);
00543 info.plot_str[len - 2] = '\n';
00544 info.plot_str[len - 1] = '\0';
00545 fprintf(header, info.plot_str);
00546 if (fclose(header))
00547 DEBUG(DEBUG_FLAG, "rec_dump: fclose: %s\n",
00548 strerror(errno));
00549
00550 return 0;
00551 }