]> CyberLeo.Net >> Repos - SourceForge/eyefi-config.git/blob - eyefi-config.c
Add standalone crypto implementation. Thanks wpa_supplicant!
[SourceForge/eyefi-config.git] / eyefi-config.c
1 /*
2  * eyefitest.c
3  *
4  * Copyright (C) 2008 Dave Hansen <dave@sr71.net>
5  *
6  * This software may be redistributed and/or modified under the terms of
7  * the GNU General Public License ("GPL") version 2 as published by the
8  * Free Software Foundation.
9  */
10
11 #include <assert.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <getopt.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <errno.h>
21
22 #include "eyefi-config.h"
23
24 #define O_DIRECT        00040000        /* direct disk access hint */
25
26 enum eyefi_file {
27         REQC,
28         REQM,
29         RSPC,
30         RSPM
31 };
32  
33 #define PATHNAME_MAX 4096
34 char eyefi_mount[PATHNAME_MAX]; // PATH_MAX anyone?
35 static char *__eyefi_file(enum eyefi_file file)
36 {
37         switch (file) {
38         case REQC: return "reqc";
39         case REQM: return "reqm";
40         case RSPC: return "rspc";
41         case RSPM: return "rspm";
42         }
43
44         return NULL;
45 }
46
47 static char *eyefi_file(enum eyefi_file file)
48 {
49         char *filename = __eyefi_file(file);
50         char *full = malloc(PATHNAME_MAX);
51
52         sprintf(&full[0], "%s/EyeFi/%s", eyefi_mount, filename);
53         return full;
54 }
55
56
57 #define BUFSZ 16384
58 #define EYEFI_BUF_SIZE 16384
59 char unaligned_buf[BUFSZ*2];
60 void *buf;
61
62
63 int debug_level = 1;
64 #define debug_printf(level, args...) do {       \
65         if ((level) <= debug_level)             \
66                 fprintf(stderr, ## args);       \
67         } while(0)
68
69 /*
70  * Just a few functions so that I can't easily forget about
71  * endinness.
72  */
73 struct __be32 {
74         u32 val;
75 } __attribute__((packed));
76 typedef struct __be32 be32;
77
78 /*
79  * These two obviously need to get fixed for
80  * big endian machines.
81  */
82 u32 be32_to_u32(be32 src)
83 {
84         return swap_bytes(src.val);
85 }
86 be32 u32_to_be32(u32 src)
87 {
88         be32 ret;
89         ret.val = swap_bytes(src);
90         return ret;
91 }
92
93 void dumpbuf(const char *buffer, int bytesToWrite)
94 {
95     int i;
96     static char linebuf[500];
97
98     for (i=0; i < bytesToWrite; i += 16) {
99         char *tmpbuf = &linebuf[0];
100         unsigned long sum = 0;
101         int j;
102 #define lprintf(args...)        do {            \
103         tmpbuf += sprintf(tmpbuf, ## args);\
104 } while (0)
105
106         lprintf("[%03d]: ", i);
107         for (j=0; j < 16; j++) {
108                 u8 c = ((unsigned char *)buffer)[i+j];
109                 lprintf("%02x ", (unsigned int)c);
110                 sum += c;
111         }
112         lprintf(" |");
113         for (j=0; j < 16; j++) {
114                 u8 c = ((unsigned char *)buffer)[i+j];
115                 if (c >= 'a' && c <= 'z')
116                         lprintf("%c", c);
117                 else if (c >= 'A' && c <= 'Z')
118                         lprintf("%c", c);
119                 else if (c >= '0' && c <= '9')
120                         lprintf("%c", c);
121                 else if (c >= 0x20 && c <= 127)
122                         lprintf("%c", c);
123                 else
124                         lprintf(".");
125         }
126         lprintf("|\n");
127         if (sum == 0)
128                 continue;
129         printf("%s", linebuf);
130         //if (i > 200)
131         //      break;
132     }
133 }
134
135 struct card_seq_num {
136         u32 seq;
137 } __attribute__((packed));
138
139 void read_from(enum eyefi_file);
140 void write_to(enum eyefi_file, void *, int);
141 struct card_seq_num read_seq_from(enum eyefi_file file)
142 {
143         struct card_seq_num *ret;
144         read_from(file);
145         ret = buf;
146         return *ret;
147 }
148
149 /*
150  * For O_DIRECT writes to files, we need
151  * to be 512 byte aligned on Linux, I think.
152  * So, just align this to something big
153  * and be done with it.  FIXME :)
154  */
155 void align_buf(void)
156 {
157         unsigned long addr = (unsigned long)&unaligned_buf[BUFSZ];
158         addr &= ~(BUFSZ-1);
159         buf = (void *)addr;
160         debug_printf(4, "buf: %p\n", buf);
161         debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]);
162 }
163
164 struct card_seq_num seq;
165
166 /*
167  * The real manager does this so we might
168  * as well, too.
169  */
170 void zero_card_files(void)
171 {
172         write_to(REQM, buf, BUFSZ);
173         write_to(REQC, buf, BUFSZ);
174         write_to(RSPM, buf, BUFSZ);
175         write_to(RSPC, buf, BUFSZ);
176
177         read_from(REQM);
178         read_from(REQC);
179         read_from(RSPM);
180         read_from(RSPC);
181 }
182
183 void init_card()
184 {
185         if (buf != NULL)
186                 return;
187
188         debug_printf(2, "Initializing card...\n");
189         align_buf();
190         zero_card_files();
191         seq = read_seq_from(RSPC);
192         if (seq.seq == 0)
193                 seq.seq = 0x1234;
194         debug_printf(2, "Done initializing card...\n");
195 }
196
197 void open_error(char *file)
198 {
199         fprintf(stderr, "unable to open '%s'\n", file);
200         fprintf(stderr, "Is the Eye-Fi card inserted and mounted at: %s ?\n", eyefi_mount);
201         fprintf(stderr, "Do you have write permissions to it?\n");
202         if (debug_level > 1)
203                 perror("bad open");
204         exit(1);
205 }
206
207 void read_from(enum eyefi_file __file)
208 {
209         u8 c;
210         int i;
211         int ret, retcntl;
212         int fd;
213         int zeros = 0;
214         char *file = eyefi_file(__file);
215         
216         init_card();
217
218         fd = open(file, O_RDONLY);
219         if (fd < 0) 
220                 open_error(file);
221         retcntl = fcntl(fd, F_SETFL, O_DIRECT);
222         if (retcntl < 0) {
223                 perror("bad fcntl");
224                 exit(1);
225         }
226         ret = read(fd, buf, BUFSZ);
227         if (debug_level > 3)
228                 dumpbuf(buf, 128);
229         if (ret < 0) {
230                 perror("bad read");
231                 exit(1);
232         }
233         debug_printf(3, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl);
234         for (i=0; i < BUFSZ; i++) {
235                 c = ((char *)buf)[i];
236                 if (c == '\0') {
237                         zeros++;
238                         continue;
239                 }
240         }
241         //if (zeros)
242         //      printf(" zeros: %d", zeros);
243         //fsync(fd);
244         free(file);
245         close(fd);
246 }
247
248 void write_to(enum eyefi_file __file, void *stuff, int len)
249 {
250         int ret;
251         int fd;
252         char *file = eyefi_file(__file);
253
254         init_card();
255         if (len == -1)
256                 len = strlen(stuff);
257
258         if (debug_level > 3) {
259                 debug_printf(3, "%s('%s', ..., %d)\n", __func__, file, len);
260                 dumpbuf(stuff, len);
261         }
262         memset(buf, 0, BUFSZ);
263         memcpy(buf, stuff, len);
264         fd = open(file, O_RDWR|O_DIRECT|O_CREAT, 0600);
265         //ret = lseek(fd, 0, SEEK_SET);
266         if (fd < 0)
267                 open_error(file);
268         if (debug_level > 3)
269                 dumpbuf(buf, 128);
270         ret = write(fd, buf, BUFSZ);
271         //fsync(fd);
272         close(fd);
273         debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len);
274         if (ret < 0)
275                 exit(ret);
276         free(file);
277 }       
278
279 /*
280  * Most of the eyefi strings are pascal-style with
281  * a length byte preceeding content.  (Did pascal
282  * have just a byte for length or more??)
283  */
284 struct pascal_string {
285         u8 length;
286         u8 value[32];
287 } __attribute__((packed));
288
289 void print_pascal_string(struct pascal_string *str)
290 {
291         int i;
292         for (i = 0; i < str->length; i++)
293                 printf("%c", str->value[i]);
294 }
295
296 /*
297  * The 'o' command has several sub-commands:
298  */
299 enum card_info_subcommand {
300         MAC_ADDRESS   = 1,
301         FIRMWARE_INFO = 2,
302         CARD_KEY      = 3,
303         API_URL       = 4,
304         UNKNOWN1      = 5, // Chris says these are 
305         UNKNOWN2      = 6, // checksums
306         LOG_LEN       = 7,
307 };
308
309 struct card_info_req {
310         u8 o;
311         u8 subcommand;
312 } __attribute__((packed));
313
314 struct card_info_rsp_key {
315         struct pascal_string key;
316 };
317
318 #define MAC_BYTES 6
319 struct mac_address {
320         u8 length;
321         u8 mac[MAC_BYTES];
322 } __attribute__((packed));
323
324 struct card_info_api_url {
325         struct pascal_string key;
326 };
327
328 struct card_info_log_len {
329         u8 len;
330         be32 val;
331 } __attribute__((packed));
332
333 #define write_struct(file, s) write_to((file), s, sizeof(*(s)))
334
335 void print_mac(struct mac_address *mac)
336 {
337         int i;
338         for (i=0; i < MAC_BYTES-1; i++) {
339                 printf("%02x:", mac->mac[i]);
340         }
341         printf("%02x\n", mac->mac[i]);
342 }
343
344 void inc_seq(void)
345 {
346         //u32 tmpseq = be32_to_u32(seq.seq);
347         //seq.seq = u32_to_be32(tmpseq+1);
348         seq.seq++;
349         write_struct(REQC, &seq);
350 }
351
352 u32 current_seq(void)
353 {
354         return seq.seq;
355 }
356
357 void wait_for_response(void)
358 {
359         int i;
360         debug_printf(3, "waiting for response...\n");
361         inc_seq();
362         for (i = 0; i < 50; i++) {
363                 struct card_seq_num cardseq = read_seq_from(RSPC);
364                 u32 rsp = cardseq.seq;
365                 debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, current_seq(),
366                                 cardseq.seq);
367                 if (rsp == current_seq())
368                         break;
369                 usleep(300000);
370         }
371         debug_printf(3, "got good seq, reading RSPM...\n");
372         read_from(RSPM);
373         debug_printf(3, "done reading RSPM\n");
374 }
375 struct byte_response {
376         u8 response;
377 };
378
379 enum net_type {
380         UNSECURED,
381         WEP,
382         WPA,
383         WPA2
384 };
385
386 #define ESSID_LEN 32
387 struct scanned_net {
388         char essid[ESSID_LEN];
389         signed char strength;
390         u8 type;
391 } __attribute__((packed));
392
393 struct scanned_net_list {
394         u8 nr;
395         struct scanned_net nets[100];
396 } __attribute__((packed));
397
398 struct configured_net {
399         char essid[ESSID_LEN];
400 } __attribute__((packed));
401
402 struct configured_net_list {
403         u8 nr;
404         struct configured_net nets[100];
405 } __attribute__((packed));
406
407 char *net_test_states[] = {
408         "not scanning",
409         "locating network",
410         "verifying network key",
411         "waiting for DHCP",
412         "testing connection to Eye-Fi server",
413         "success",
414 };
415
416 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
417
418 char *net_test_state_name(u8 state)
419 {
420         int size = ARRAY_SIZE(net_test_states);
421         if (state >= size)
422                 return "unknown";
423         return net_test_states[state];
424 }
425
426 char *net_types[] = {
427         "No security",
428         "WEP",
429         "WPA",
430         "unknown1",
431         "WPA2",
432 };
433
434 char *net_type_name(u8 type)
435 {
436         int size = ARRAY_SIZE(net_types);
437         if (type >= size)
438                 return "unknown";
439         return net_types[type];
440 }
441
442 #define WPA_KEY_BYTES 32
443 struct wpa_key {
444         u8 key[WPA_KEY_BYTES];
445 } __attribute((packed));
446
447 #define WEP_KEY_BYTES 32
448 struct wep_key {
449         u8 key[WEP_KEY_BYTES];
450 } __attribute((packed));
451
452 struct network_key {
453         u8 len;
454         union {
455                 struct wpa_key wpa;
456                 struct wep_key wep;
457         };
458 } __attribute((packed));
459
460 #define KEY_LEN 32
461 struct net_request {
462         char req;
463         u8 essid_len;
464         char essid[ESSID_LEN];
465         struct network_key key;
466 } __attribute((packed));
467
468 char lower(char c)
469 {
470         if ((c >= 'A') && (c <= 'Z'))
471                 c += ('a' - 'A');
472         return c;
473 }
474
475 int atoh(char c)
476 {
477         char lc = lower(c);
478         if ((c >= '0') && (c <= '9'))
479                 return c - '0';
480         else if ((c >= 'a') && (c <= 'z'))
481                 return (c - 'a') + 10;
482         debug_printf(5, "non-hex character: '%c'/'%c'\n", c, lc);
483         return -1;
484 }
485
486 /*
487  * Take a string like "0ab1" and make it
488  * a series of bytes: { 0x0a, 0xb1 }
489  *
490  * @len is the strlen() of the ascii
491  *
492  * Destroys the original string.
493  */
494 char *convert_ascii_to_hex(char *ascii, int len)
495 {
496         int i;
497         if (len%2) {
498                 fprintf(stderr, "%s() must be even number of bytes: %d\n",
499                 __func__, len);
500                 exit(2);
501         }
502         for (i=0; i < len; i+=2) {
503                 int high = atoh(ascii[i]);
504                 int low  = atoh(ascii[i+1]);
505                 u8 byte = (high<<4 | low);
506                 if (high < 0 || low < 0)
507                         return NULL;
508                 debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte);
509                 ascii[i/2] = byte;
510         }
511         for (i=len/2; i < len; i++)
512                 ascii[i] = '\0';
513         return &ascii[0];
514 }
515
516 #define PASSPHRASE_PROG "wpa_passphrase"
517
518 struct wpa_key *make_wpa_key(char *essid, char *pass)
519 {
520         struct wpa_key *key = malloc(sizeof(*key));
521
522         if (strlen(pass) == WPA_KEY_BYTES*2) {
523                 char *hex_pass;
524                 debug_printf(2, "Interpreting password as hex WPA key\n");
525                 hex_pass = convert_ascii_to_hex(pass, WPA_KEY_BYTES*2);
526                 if (!hex_pass)
527                         return NULL;
528                 memcpy(&key->key[0], pass, WPA_KEY_BYTES);
529         } else {
530                 debug_printf(2, "Interpreting password as ASCII WPA key\n");
531                 pbkdf2_sha1(pass, essid, strlen(essid), 4096,
532                             &key->key[0], WPA_KEY_BYTES);
533         }
534         return key;
535 }
536
537 void card_info_cmd(enum card_info_subcommand cmd)
538 {
539         struct card_info_req cir;
540         cir.o = 'o';
541         cir.subcommand = cmd;
542
543         write_struct(REQM, &cir);
544         wait_for_response();
545 }
546
547 u32 fetch_log_length(void)
548 {
549         card_info_cmd(LOG_LEN);
550         struct card_info_log_len *loglen = buf;
551         return be32_to_u32(loglen->val);
552 }
553
554 void print_log_len(void)
555 {
556         u32 len = fetch_log_length();
557         printf("log len: %08lx\n", len);
558 }
559
560 void print_card_mac(void)
561 {
562         debug_printf(2, "%s()\n", __func__);
563         card_info_cmd(MAC_ADDRESS);
564         struct mac_address *mac = buf;
565         assert(mac->length == MAC_BYTES);
566         printf("card mac address: ");
567         print_mac(mac);
568 }
569
570 void print_card_key(void)
571 {
572         debug_printf(2, "%s()\n", __func__);
573         card_info_cmd(CARD_KEY);
574         struct card_info_rsp_key *foo = buf;
575         printf("card key (len: %d): '", foo->key.length);
576         print_pascal_string(&foo->key);
577         printf("'\n");
578 }
579
580 struct noarg_request {
581         u8 req;
582 };
583
584 void issue_noarg_command(u8 cmd)
585 {
586         struct noarg_request req;
587         req.req = cmd;
588         write_struct(REQM, &req);
589         wait_for_response();
590 }
591
592 void scan_print_nets(void)
593 {
594         int i;
595
596         debug_printf(2, "%s()\n", __func__);
597         issue_noarg_command('g');
598         struct scanned_net_list *scanned = buf;
599         if (scanned->nr == 0) {
600                 printf("unable to detect any wireless networks\n");
601                 return;
602         }
603         printf("Scanned wireless networks:\n");
604         for (i=0; i < scanned->nr; i++) {
605                 struct scanned_net *net = &scanned->nets[i];
606                 printf("'%s' type(%d): %s, strength: %d\n", net->essid,
607                                 net->type,
608                                 net_type_name(net->type),
609                                 net->strength);
610         }
611 }
612
613 void print_configured_nets(void)
614 {
615         int i;
616         struct configured_net_list *configured;
617
618         debug_printf(2, "%s()\n", __func__);
619         issue_noarg_command('l');
620         configured = buf;
621         if (configured->nr == 0) {
622                 printf("No wireless networks configured on card\n");
623                 return;
624         }
625         printf("configured wireless networks:\n");
626         for (i=0; i < configured->nr; i++) {
627                 struct configured_net *net = &configured->nets[i];
628                 printf("'%s'\n", net->essid);
629         }
630 }
631
632 void reboot_card(void)
633 {
634         debug_printf(2, "%s()\n", __func__);
635         issue_noarg_command('b');
636 }
637
638 void copy_wep_key(struct wep_key *dst, struct wep_key *src)
639 {
640         memcpy(&dst->key, &src->key, sizeof(*dst));
641 }
642
643 void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src)
644 {
645         memcpy(&dst->key, &src->key, sizeof(*dst));
646 }
647
648 void network_action(char cmd, char *essid, char *wpa_ascii)
649 {
650         struct net_request nr;
651         memset(&nr, 0, sizeof(nr));
652
653         nr.req = cmd;
654         strcpy(&nr.essid[0], essid);
655         nr.essid_len = strlen(essid);
656         struct wpa_key *wpakey;
657         if (wpa_ascii) {
658                 wpakey = make_wpa_key(essid, wpa_ascii);
659                 nr.key.len = sizeof(*wpakey);
660                 copy_wpa_key(&nr.key.wpa, wpakey);
661         }
662         write_struct(REQM, &nr);
663         wait_for_response();
664 }
665
666 void add_network(char *essid, char *wpa_ascii)
667 {
668         debug_printf(2, "%s()\n", __func__);
669         network_action('a', essid, wpa_ascii);
670 }
671
672 void remove_network(char *essid)
673 {
674         debug_printf(2, "%s()\n", __func__);
675         network_action('d', essid, NULL);
676 }
677
678 int try_connection_to(char *essid, char *wpa_ascii)
679 {
680         int i;
681         int ret = -1;
682
683         char *type = net_type_name(WPA);
684         if (!wpa_ascii)
685                 type = net_type_name(UNSECURED);
686         printf("trying to connect to %s network: '%s'", type, essid);
687         if (wpa_ascii)
688                 printf(" with passphrase: '%s'", wpa_ascii);
689         fflush(NULL);
690
691         // test network
692         network_action('t', essid, wpa_ascii);
693         u8 last_rsp = -1;
694
695         char rsp = '\0';
696         for (i=0; i < 200; i++) {
697                 struct byte_response *r;
698                 issue_noarg_command('s');
699                 r = buf;
700                 rsp = r->response;
701                 char *state = net_test_state_name(rsp);
702                 if (rsp == last_rsp) {
703                         printf(".");
704                         fflush(NULL);;
705                 } else {
706                         if (rsp)
707                                 printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state);
708                         last_rsp = rsp;
709                 }
710                 
711                 if (!strcmp("success", state)) {
712                         ret = 0;
713                         break;
714                 }
715                 if (!strcmp("not scanning", state))
716                         break;
717                 if (!strcmp("unknown", state))
718                         break;
719         }
720         printf("\n");
721         if (!ret) {
722                 printf("Succeeded connecting to: '%s'\n", essid);
723         } else {
724                 printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid,
725                                 rsp, net_test_state_name(rsp));
726         }
727         return ret;
728 }
729
730 struct fetch_log_cmd {
731         char m;
732         be32 offset;
733 } __attribute__((packed));
734
735 /*
736  * When you ask for the log at offset 0x0, you
737  * get back 8 bytes of offsets into the rest of
738  * the data
739  */
740 struct first_log_response {
741         be32 log_end;
742         be32 log_start;
743         u8 data[EYEFI_BUF_SIZE-8];
744 } __attribute__((packed));
745
746 struct rest_log_response {
747         u8 data[EYEFI_BUF_SIZE];
748 } __attribute__((packed));
749
750 unsigned char *get_log_at_offset(u32 offset)
751 {
752         struct fetch_log_cmd cmd;
753         cmd.m = 'm';
754         cmd.offset = u32_to_be32(offset);
755
756         debug_printf(2, "getting log at offset: %08lx\n", offset);
757         write_struct(REQM, &cmd);
758         wait_for_response();
759         return buf;
760 }
761
762 int get_log(void)
763 {
764         int total_bytes = 0;
765         int i;
766         u32 log_start;
767         u32 log_end;
768         u32 log_size = fetch_log_length();
769         char *resbuf = malloc(log_size);
770
771         int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE;
772         for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) {
773                 debug_printf(1, "fetching EyeFi card log part %d/%d...",
774                                 i+1, nr_bufs_per_log);
775                 fflush(NULL);
776                 get_log_at_offset(EYEFI_BUF_SIZE*i);
777                 debug_printf(1, "done\n");
778                 u32 log_size;
779                 u8 *log_data;
780                 if (i == 0) {
781                         struct first_log_response *log = buf;
782                         log_end = be32_to_u32(log->log_end);
783                         log_start = be32_to_u32(log->log_start);
784                         debug_printf(2, "log end:   0x%04lx\n", log_end);
785                         debug_printf(2, "log start: 0x%04lx\n", log_start);
786                         log_data = &log->data[0];
787                         log_size = ARRAY_SIZE(log->data);
788                 } else {
789                         struct rest_log_response *log = buf;
790                         log_data = &log->data[0];
791                         log_size = ARRAY_SIZE(log->data);
792                 }
793                 debug_printf(3, "writing %ld bytes to resbuf[%d]\n",
794                                 log_size, total_bytes);
795                 memcpy(&resbuf[total_bytes], log_data, log_size);
796                 total_bytes += log_size;
797         }
798         // The last byte *should* be a null, and the 
799         // official software does not print it.
800         for (i = 0; i < total_bytes-1; i++) {
801                 int offset = (log_start+i)%total_bytes;
802                 char c = resbuf[offset];
803                 // the official software converts UNIX to DOS-style
804                 // line breaks, so we'll do the same
805                 if (c == '\n')
806                         printf("%c", '\r');
807                 printf("%c", c);
808         }
809         printf("\n");
810         // just some simple sanity checking to make sure what
811         // we are fetching looks valid
812         int null_bytes_left = 20;
813         if (resbuf[log_end] != 0) {
814                 debug_printf(2, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n",
815                                 log_end, log_end, resbuf[log_end]);
816                 for (i=0; i<log_size; i++) {
817                         if (resbuf[i])
818                                 continue;
819                         if (null_bytes_left <= 0)
820                                 continue;
821                         null_bytes_left--;
822                         debug_printf(2, "null byte %d\n", i);
823                 }
824         }
825         free(resbuf);
826         return 0;
827 }
828
829 int atoo(char o)
830 {
831         if ((o >= '0') && (o <= '7'))
832                 return atoh(o);
833         return -1;
834 }
835
836 int octal_esc_to_chr(char *input) {
837         int i=0;
838         int ret = 0;
839         int len = strlen(input);
840
841         //intf("%s('%s')\n", __func__, input);
842         if (input[0] != '\\')
843                 return -1;
844         if (len < 4)
845                 return -1;
846
847         for (i=1; i < len ; i++) {
848                 if (i > 3)
849                         break;
850                 int tmp = atoo(input[i]);
851                 //intf("tmp: %d\n", tmp);
852                 if (tmp < 0)
853                         return tmp;
854                 ret <<= 3;
855                 ret += tmp;
856         }
857         return ret;
858 }
859
860 char *replace_escapes(char *str)
861 {
862         int i;
863         int output = 0;
864         debug_printf(4, "%s(%s)\n", __func__, str);
865         for (i=0; i < strlen(str); i++) {
866                 int esc = octal_esc_to_chr(&str[i]);
867                 if (esc >= 0) {
868                         str[output++] = esc;
869                         i += 3;
870                         continue;
871                 }
872                 str[output++] = str[i];
873         }
874         str[output] = '\0';
875         debug_printf(4, "'%s' %d\n", str, output);
876         return str;
877 }
878
879 #define LINEBUFSZ 1024
880 void locate_eyefi_mount(void)
881 {
882         char line[LINEBUFSZ];
883         FILE *mounts = fopen("/proc/mounts", "r");
884
885         char dev[LINEBUFSZ];
886         char mnt[LINEBUFSZ];
887         char fs[LINEBUFSZ];
888         char opt[LINEBUFSZ];
889         int foo;
890         int bar;
891         while (fgets(&line[0], 1023, mounts)) {
892                 int read;
893                 read = sscanf(&line[0], "%s %s %s %s %d %d",
894                                 &dev[0], &mnt[0], &fs[0], &opt[0],
895                                 &foo, &bar);
896                 // only look at fat filesystems:
897                 if (strcmp(fs, "msdos") && strcmp(fs, "vfat")) {
898                         debug_printf(2, "fs at '%s' is not fat, skipping...\n", mnt);
899                         continue;
900                 }
901                 // Linux's /proc/mounts has spaces like this \040
902                 replace_escapes(&mnt[0]);
903                 strcpy(&eyefi_mount[0], &mnt[0]);
904                 char *file = eyefi_file(REQM);
905                 debug_printf(2, "looking for EyeFi file here: '%s'\n", file);
906
907                 struct stat statbuf;
908                 int statret;
909                 statret = stat(file, &statbuf);
910                 free(file);
911                 if (statret)
912                         continue;
913                 debug_printf(1, "located EyeFi card at: %s\n", eyefi_mount);
914                 break;
915         }
916         fclose(mounts);
917 }
918
919 void usage(void)
920 {
921         printf("Usage:\n");
922         printf("  eyefitest [OPTIONS]\n");
923         printf("  -a ESSID      add network (implies test unless --force)\n");
924         printf("  -t ESSID      test network\n");
925         printf("  -p KEY        set WPA key for add/test\n");
926         printf("  -r ESSID      remove network\n");
927         printf("  -s            scan for networks\n");
928         printf("  -c            list configured networks\n");
929         printf("  -b            reboot card\n");
930         printf("  -d level      set debugging level (default: 1)\n");
931         printf("  -k            print card unique key\n");
932         printf("  -l            dump card log\n");
933         printf("  -m            print card mac\n");
934         exit(4);
935 }
936
937 int main(int argc, char **argv)
938 {
939         if (argc == 1)
940                 usage();
941
942         debug_printf(3, "%s starting...\n", argv[0]);
943         
944         locate_eyefi_mount();
945
946         //static int passed_wep = 0;
947         //static int passed_wpa = 0;
948         static int force = 0;
949         static struct option long_options[] = {
950                 //{"wep", 'x', &passed_wep, 1},
951                 //{"wpa", 'y', &passed_wpa, 1},
952                 {"force", 0, &force, 1},
953                 {"help", 'h', NULL, 1},
954         };
955
956         int option_index;
957         char c;
958         char *essid = NULL;
959         char *passwd = NULL;
960         char network_action = 0;
961         debug_printf(3, "about to parse arguments\n");
962         while ((c = getopt_long_only(argc, argv, "a:bcd:klmp:r:st:",
963                         &long_options[0], &option_index)) != -1) {
964                 debug_printf(3, "argument: '%c' %d optarg: '%s'\n", c, c, optarg);
965                 switch (c) {
966                 case 0:
967                         // was a long argument
968                         break;
969                 case 'a':
970                 case 't':
971                 case 'r':
972                         essid = optarg;
973                         network_action = c;
974                         break;
975                 case 'b':
976                         reboot_card();
977                         break;
978                 case 'c':
979                         print_configured_nets();
980                         break;
981                 case 'd':
982                         debug_level = atoi(optarg);
983                         break;
984                 case 'k':
985                         print_card_key();
986                         break;
987                 case 'l':
988                         get_log();
989                         break;
990                 case 'm':
991                         print_card_mac();
992                         break;
993                 case 'p':
994                         passwd = optarg;
995                         break;
996                 case 's':
997                         scan_print_nets();
998                         break;
999                 case 'h':
1000                 default:
1001                         usage();
1002                         break;
1003                 }
1004         }
1005         debug_printf(3, "after arguments essid: '%s' passwd: '%s'\n", essid, passwd);
1006         if (network_action && essid) {
1007                 int ret = 0;
1008                 switch (network_action) {
1009                 case 't':
1010                         ret = try_connection_to(essid, passwd);
1011                         break;
1012                 case 'a':
1013                         if (!force) {
1014                                 ret = try_connection_to(essid, passwd);
1015                         } else {
1016                                 debug_printf(1, "forced: skipping network test\n");
1017                         }
1018                         if (ret) {
1019                                 printf("Error connecting to network '%s', not adding.\n", essid);
1020                                 printf("use --force to override\n");
1021                                 break;
1022                         }
1023                         add_network(essid, passwd);
1024                         break;
1025                 case 'r':
1026                         remove_network(essid);
1027                         break;
1028                 }
1029         }
1030         return 0;
1031 }
1032
1033