4 * Copyright (C) 2008 Dave Hansen <dave@sr71.net>
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.
17 #include <sys/types.h>
22 #define O_DIRECT 00040000 /* direct disk access hint */
24 #define MOUNT "/media/EYE-FI/"
25 #define PATH MOUNT "eyefi/"
26 #define REQC PATH "REQC"
27 #define REQM PATH "REQM"
28 #define RSPC PATH "RSPC"
29 #define RSPM PATH "RSPM"
32 #define EYEFI_BUF_SIZE 16384
33 char unaligned_buf[BUFSZ*10];
38 #define debug_printf(level, args...) do { \
39 if ((level) <= debug_level) \
40 fprintf(stderr, ## args); \
44 * Do some kernel-style types to make
45 * definitions shorter.
47 typedef unsigned long u32;
48 typedef unsigned char u8;
50 static inline u32 swap_bytes(u32 src)
52 unsigned int dest = 0;
53 dest |= (src & 0xff000000) >> 24;
54 dest |= (src & 0x00ff0000) >> 8;
55 dest |= (src & 0x0000ff00) << 8;
56 dest |= (src & 0x000000ff) << 24;
61 * Just a few functions so that I can't easily forget about
66 } __attribute__((packed));
67 typedef struct __be32 be32;
70 * These two obviously need to get fixed for
71 * big endian machines.
73 u32 be32_to_u32(be32 src)
75 return swap_bytes(src.val);
77 be32 u32_to_be32(u32 src)
80 ret.val = swap_bytes(src);
84 void dumpbuf(const char *buffer, int bytesToWrite)
87 static char linebuf[500];
89 for (i=0; i < bytesToWrite; i += 16) {
90 char *tmpbuf = &linebuf[0];
91 unsigned long sum = 0;
93 #define lprintf(args...) do { \
94 tmpbuf += sprintf(tmpbuf, ## args);\
97 lprintf("[%03d]: ", i);
98 for (j=0; j < 16; j++) {
99 u8 c = ((unsigned char *)buffer)[i+j];
100 lprintf("%02x ", (unsigned int)c);
104 for (j=0; j < 16; j++) {
105 u8 c = ((unsigned char *)buffer)[i+j];
106 if (c >= 'a' && c <= 'z')
108 else if (c >= 'A' && c <= 'Z')
110 else if (c >= '0' && c <= '9')
112 else if (c >= 0x20 && c <= 127)
120 printf("%s", linebuf);
126 struct card_seq_num {
128 } __attribute__((packed));
130 void read_from(char *file);
131 void write_to(char *file, void *stuff, int len);
132 struct card_seq_num read_seq_from(char *file)
134 struct card_seq_num *ret;
141 * For O_DIRECT writes to files, we need
142 * to be 512 byte aligned on Linux, I think.
143 * So, just align this to something big
144 * and be done with it. FIXME :)
148 unsigned long addr = (unsigned long)&unaligned_buf[BUFSZ];
151 debug_printf(4, "buf: %p\n", buf);
152 debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]);
155 struct card_seq_num seq;
158 * The real manager does this so we might
161 void zero_card_files(void)
163 write_to(REQM, buf, BUFSZ);
164 write_to(REQC, buf, BUFSZ);
165 write_to(RSPM, buf, BUFSZ);
166 write_to(RSPC, buf, BUFSZ);
181 seq = read_seq_from(RSPC);
186 void open_error(char *file)
188 fprintf(stderr, "unable to open '%s'\n", file);
189 fprintf(stderr, "Is the Eye-Fi card inserted and mounted at: %s ?\n", MOUNT);
190 fprintf(stderr, "Do you have write permissions to it?\n");
196 void read_from(char *file)
206 fd = open(file, O_RDONLY);
209 retcntl = fcntl(fd, F_SETFL, O_DIRECT);
214 ret = read(fd, buf, BUFSZ);
221 debug_printf(3, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl);
222 for (i=0; i < BUFSZ; i++) {
223 c = ((char *)buf)[i];
230 // printf(" zeros: %d", zeros);
235 void write_to(char *file, void *stuff, int len)
237 //printf("not writing to '%s'\n", file);
247 memset(buf, 0, BUFSZ);
248 memcpy(buf, stuff, len);
249 fd = open(file, O_RDWR|O_DIRECT|O_CREAT, 0600);
250 //ret = lseek(fd, 0, SEEK_SET);
255 ret = write(fd, buf, BUFSZ);
258 debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len);
264 * Most of the eyefi strings are pascal-style with
265 * a length byte preceeding content. (Did pascal
266 * have just a byte for length or more??)
268 struct pascal_string {
271 } __attribute__((packed));
273 void print_pascal_string(struct pascal_string *str)
276 for (i = 0; i < str->length; i++)
277 printf("%c", str->value[i]);
281 * The 'o' command has several sub-commands:
283 enum card_info_subcommand {
288 UNKNOWN1 = 5, // Chris says these are
289 UNKNOWN2 = 6, // checksums
293 struct card_info_req {
296 } __attribute__((packed));
298 struct card_info_rsp_key {
299 struct pascal_string key;
306 } __attribute__((packed));
308 struct card_info_api_url {
309 struct pascal_string key;
312 struct card_info_log_len {
315 } __attribute__((packed));
317 #define write_struct(file, s) write_to((file), s, sizeof(*(s)))
319 void print_mac(struct mac_address *mac)
322 for (i=0; i < MAC_BYTES-1; i++) {
323 printf("%02x:", mac->mac[i]);
325 printf("%02x\n", mac->mac[i]);
330 //u32 tmpseq = be32_to_u32(seq.seq);
331 //seq.seq = u32_to_be32(tmpseq+1);
333 write_struct(REQC, &seq);
336 u32 current_seq(void)
341 void wait_for_response(void)
344 debug_printf(3, "waiting for response...\n");
346 for (i = 0; i < 50; i++) {
347 struct card_seq_num cardseq = read_seq_from(RSPC);
348 u32 rsp = cardseq.seq;
349 debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, current_seq(),
351 if (rsp == current_seq())
355 debug_printf(3, "got good seq, reading RSPM...\n");
357 debug_printf(3, "done reading RSPM\n");
359 struct byte_response {
372 char essid[ESSID_LEN];
373 signed char strength;
375 } __attribute__((packed));
377 struct scanned_net_list {
379 struct scanned_net nets[100];
380 } __attribute__((packed));
382 struct configured_net {
383 char essid[ESSID_LEN];
384 } __attribute__((packed));
386 struct configured_net_list {
388 struct configured_net nets[100];
389 } __attribute__((packed));
391 char *net_test_states[] = {
394 "verifying network key",
396 "testing connection to Eye-Fi server",
400 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
402 char *net_test_state_name(u8 state)
404 int size = ARRAY_SIZE(net_test_states);
407 return net_test_states[state];
410 char *net_types[] = {
418 char *net_type_name(u8 type)
420 int size = ARRAY_SIZE(net_types);
423 return net_types[type];
426 #define WPA_KEY_BYTES 32
428 u8 key[WPA_KEY_BYTES];
429 } __attribute((packed));
431 #define WEP_KEY_BYTES 32
433 u8 key[WEP_KEY_BYTES];
434 } __attribute((packed));
442 } __attribute((packed));
448 char essid[ESSID_LEN];
449 struct network_key key;
450 } __attribute((packed));
454 if ((c >= 'A') && (c <= 'Z'))
462 if ((c >= '0') && (c <= '9'))
464 else if ((c >= 'a') && (c <= 'z'))
465 return (c - 'a') + 10;
466 debug_printf(0, "non-hex character: '%c'/'%c'\n", c, lc);
471 * Take a string like "0ab1" and make it
472 * a series of bytes: { 0x0a, 0xb1 }
474 * Destroys the original string.
476 char *convert_ascii_to_hex(char *ascii, int len)
480 fprintf(stderr, "%s() must be even number of bytes: %d\n",
484 for (i=0; i < len; i+=2) {
485 u8 high = atoh(ascii[i]);
486 u8 low = atoh(ascii[i+1]);
487 u8 byte = (high<<4 | low);
488 debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte);
491 for (i=len/2; i < len; i++)
496 #define PASSPHRASE_PROG "wpa_passphrase"
498 struct wpa_key *make_wpa_key(char *essid, char *pass)
500 char program[] = PASSPHRASE_PROG;
501 // 7 for 2 spaces, 4 quotes and a \0
502 char redirect[] = " 2> /dev/null";
503 char *cmdbuf = malloc(strlen(essid) + strlen(pass) + strlen(program) + 7 +
509 sprintf(cmdbuf, "%s '%s' '%s' %s", program, essid, pass, redirect);
510 FILE *pipe = popen(cmdbuf, "r");
512 perror("\nunable to execute " PASSPHRASE_PROG);
516 int key_chars = WPA_KEY_BYTES*2;
517 char hex_key_in_ascii[key_chars+1];
520 while (fgets(&line[0], 1023, pipe)) {
521 debug_printf(4, "read from %s: '%s'\n", PASSPHRASE_PROG, line);
522 read = sscanf(&line[0], " psk=%64s", &hex_key_in_ascii[0]);
527 int exit_code = pclose(pipe);
528 if (!read || exit_code) {
529 fprintf(stderr, "\nunable to read wpa key from %s\n", PASSPHRASE_PROG);
530 fprintf(stderr, "Is wpa_supplicant installed?\n");
533 debug_printf(4, "ascii key: '%s'\n", hex_key_in_ascii);
534 char *hex_key = convert_ascii_to_hex(hex_key_in_ascii, key_chars);
535 struct wpa_key *key = malloc(sizeof(*key));
536 memcpy(&key->key[0], hex_key, WPA_KEY_BYTES);
541 void card_info_cmd(enum card_info_subcommand cmd)
543 struct card_info_req cir;
545 cir.subcommand = cmd;
547 write_struct(REQM, &cir);
551 u32 fetch_log_length(void)
553 card_info_cmd(LOG_LEN);
554 struct card_info_log_len *loglen = buf;
555 return be32_to_u32(loglen->val);
558 void print_log_len(void)
560 u32 len = fetch_log_length();
561 printf("log len: %08lx\n", len);
564 void print_card_mac(void)
566 debug_printf(2, "%s()\n", __func__);
567 card_info_cmd(MAC_ADDRESS);
568 struct mac_address *mac = buf;
569 assert(mac->length == MAC_BYTES);
570 printf("card mac address: ");
574 void print_card_key(void)
576 debug_printf(2, "%s()\n", __func__);
577 card_info_cmd(CARD_KEY);
578 struct card_info_rsp_key *foo = buf;
579 printf("card key (len: %d): '", foo->key.length);
580 print_pascal_string(&foo->key);
584 struct noarg_request {
588 void issue_noarg_command(u8 cmd)
590 struct noarg_request req;
592 write_struct(REQM, &req);
596 void scan_print_nets(void)
600 debug_printf(2, "%s()\n", __func__);
601 issue_noarg_command('g');
602 struct scanned_net_list *scanned = buf;
603 if (scanned->nr == 0) {
604 printf("unable to detect any wireless networks\n");
607 printf("Scanned wireless networks:\n");
608 for (i=0; i < scanned->nr; i++) {
609 struct scanned_net *net = &scanned->nets[i];
610 printf("'%s' type(%d): %s, strength: %d\n", net->essid,
612 net_type_name(net->type),
617 void print_configured_nets(void)
620 struct configured_net_list *configured;
622 debug_printf(2, "%s()\n", __func__);
623 issue_noarg_command('l');
625 if (configured->nr == 0) {
626 printf("No wireless networks configured on card\n");
629 printf("configured wireless networks:\n");
630 for (i=0; i < configured->nr; i++) {
631 struct configured_net *net = &configured->nets[i];
632 printf("'%s'\n", net->essid);
636 void reboot_card(void)
638 debug_printf(2, "%s()\n", __func__);
639 issue_noarg_command('b');
642 void copy_wep_key(struct wep_key *dst, struct wep_key *src)
644 memcpy(&dst->key, &src->key, sizeof(*dst));
647 void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src)
649 memcpy(&dst->key, &src->key, sizeof(*dst));
652 void network_action(char cmd, char *essid, char *wpa_ascii)
654 struct net_request nr;
655 memset(&nr, 0, sizeof(nr));
658 strcpy(&nr.essid[0], essid);
659 nr.essid_len = strlen(essid);
660 struct wpa_key *wpakey;
662 wpakey = make_wpa_key(essid, wpa_ascii);
663 nr.key.len = sizeof(*wpakey);
664 copy_wpa_key(&nr.key.wpa, wpakey);
666 write_struct(REQM, &nr);
670 void add_network(char *essid, char *wpa_ascii)
672 debug_printf(2, "%s()\n", __func__);
673 network_action('a', essid, wpa_ascii);
676 void remove_network(char *essid)
678 debug_printf(2, "%s()\n", __func__);
679 network_action('d', essid, NULL);
682 int try_connection_to(char *essid, char *wpa_ascii)
687 char *type = net_type_name(WPA);
689 type = net_type_name(UNSECURED);
690 printf("trying to connect to %s network: '%s'", type, essid);
692 printf(" with passphrase: '%s'", wpa_ascii);
696 network_action('t', essid, wpa_ascii);
700 for (i=0; i < 200; i++) {
701 struct byte_response *r;
702 issue_noarg_command('s');
705 char *state = net_test_state_name(rsp);
706 if (rsp == last_rsp) {
711 printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state);
715 if (!strcmp("success", state)) {
719 if (!strcmp("not scanning", state))
721 if (!strcmp("unknown", state))
726 printf("Succeeded connecting to: '%s'\n", essid);
728 printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid,
729 rsp, net_test_state_name(rsp));
734 struct fetch_log_cmd {
737 } __attribute__((packed));
740 * When you ask for the log at offset 0x0, you
741 * get back 8 bytes of offsets into the rest of
744 struct first_log_response {
747 u8 data[EYEFI_BUF_SIZE-8];
748 } __attribute__((packed));
750 struct rest_log_response {
751 u8 data[EYEFI_BUF_SIZE];
752 } __attribute__((packed));
754 unsigned char *get_log_at_offset(u32 offset)
756 struct fetch_log_cmd cmd;
758 cmd.offset = u32_to_be32(offset);
760 debug_printf(2, "getting log at offset: %08lx\n", offset);
761 write_struct(REQM, &cmd);
772 u32 log_size = fetch_log_length();
773 char *resbuf = malloc(log_size);
775 int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE;
776 for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) {
777 debug_printf(1, "fetching EyeFi card log part %d/%d...",
778 i+1, nr_bufs_per_log);
780 get_log_at_offset(EYEFI_BUF_SIZE*i);
781 debug_printf(1, "done\n");
785 struct first_log_response *log = buf;
786 log_end = be32_to_u32(log->log_end);
787 log_start = be32_to_u32(log->log_start);
788 debug_printf(2, "log end: 0x%04lx\n", log_end);
789 debug_printf(2, "log start: 0x%04lx\n", log_start);
790 log_data = &log->data[0];
791 log_size = ARRAY_SIZE(log->data);
793 struct rest_log_response *log = buf;
794 log_data = &log->data[0];
795 log_size = ARRAY_SIZE(log->data);
797 debug_printf(3, "writing %ld bytes to resbuf[%d]\n",
798 log_size, total_bytes);
799 memcpy(&resbuf[total_bytes], log_data, log_size);
800 total_bytes += log_size;
802 // The last byte *should* be a null, and the
803 // official software does not print it.
804 for (i = 0; i < total_bytes-1; i++) {
805 int offset = (log_start+i)%total_bytes;
806 char c = resbuf[offset];
807 // the official software converts UNIX to DOS-style
808 // line breaks, so we'll do the same
814 // just some simple sanity checking to make sure what
815 // we are fetching looks valid
816 int null_bytes_left = 20;
817 if (resbuf[log_end] != 0) {
818 fprintf(stderr, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n",
819 log_end, log_end, resbuf[log_end]);
820 for (i=0; i<log_size; i++) {
823 if (null_bytes_left <= 0)
826 debug_printf(2, "null byte %d\n", i);
836 printf(" eyefitest [OPTIONS]\n");
837 printf(" -a ESSID add network (implies test unless --force)\n");
838 printf(" -t ESSID test network\n");
839 printf(" -p KEY set WPA key for add/test\n");
840 printf(" -r ESSID remove network\n");
841 printf(" -s scan for networks\n");
842 printf(" -c list configured networks\n");
843 printf(" -b reboot card\n");
844 printf(" -d level set debugging level (default: 1)\n");
845 printf(" -k print card unique key\n");
846 printf(" -m print card mac\n");
850 int main(int argc, char **argv)
855 debug_printf(3, "%s starting...\n", argv[0]);
857 //static int passed_wep = 0;
858 //static int passed_wpa = 0;
859 static int force = 0;
860 static struct option long_options[] = {
861 //{"wep", 'x', &passed_wep, 1},
862 //{"wpa", 'y', &passed_wpa, 1},
863 {"force", 0, &force, 1},
864 {"help", 'h', NULL, 1},
871 char network_action = 0;
872 debug_printf(3, "about to parse arguments\n");
873 while ((c = getopt_long_only(argc, argv, "a:bcd:klmp:r:st:",
874 &long_options[0], &option_index)) != -1) {
875 debug_printf(3, "argument: '%c' %d optarg: '%s'\n", c, c, optarg);
878 // was a long argument
890 print_configured_nets();
893 debug_level = atoi(optarg);
916 debug_printf(3, "after arguments essid: '%s' passwd: '%s'\n", essid, passwd);
917 if (network_action && essid) {
919 switch (network_action) {
921 ret = try_connection_to(essid, passwd);
925 ret = try_connection_to(essid, passwd);
927 debug_printf(1, "forced: skipping network test\n");
930 printf("Error connecting to network '%s', not adding.\n", essid);
931 printf("use --force to override\n");
934 add_network(essid, passwd);
937 remove_network(essid);