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 */
31 #define PATHNAME_MAX 4096
32 char eyefi_mount[PATHNAME_MAX]; // PATH_MAX anyone?
33 static char *__eyefi_file(enum eyefi_file file)
36 case REQC: return "reqc";
37 case REQM: return "reqm";
38 case RSPC: return "rspc";
39 case RSPM: return "rspm";
45 static char *eyefi_file(enum eyefi_file file)
47 char *filename = __eyefi_file(file);
48 char *full = malloc(PATHNAME_MAX);
50 sprintf(&full[0], "%s/EyeFi/%s", eyefi_mount, filename);
56 #define EYEFI_BUF_SIZE 16384
57 char unaligned_buf[BUFSZ*2];
62 #define debug_printf(level, args...) do { \
63 if ((level) <= debug_level) \
64 fprintf(stderr, ## args); \
68 * Do some kernel-style types to make
69 * definitions shorter.
71 typedef unsigned long u32;
72 typedef unsigned char u8;
74 static inline u32 swap_bytes(u32 src)
76 unsigned int dest = 0;
77 dest |= (src & 0xff000000) >> 24;
78 dest |= (src & 0x00ff0000) >> 8;
79 dest |= (src & 0x0000ff00) << 8;
80 dest |= (src & 0x000000ff) << 24;
85 * Just a few functions so that I can't easily forget about
90 } __attribute__((packed));
91 typedef struct __be32 be32;
94 * These two obviously need to get fixed for
95 * big endian machines.
97 u32 be32_to_u32(be32 src)
99 return swap_bytes(src.val);
101 be32 u32_to_be32(u32 src)
104 ret.val = swap_bytes(src);
108 void dumpbuf(const char *buffer, int bytesToWrite)
111 static char linebuf[500];
113 for (i=0; i < bytesToWrite; i += 16) {
114 char *tmpbuf = &linebuf[0];
115 unsigned long sum = 0;
117 #define lprintf(args...) do { \
118 tmpbuf += sprintf(tmpbuf, ## args);\
121 lprintf("[%03d]: ", i);
122 for (j=0; j < 16; j++) {
123 u8 c = ((unsigned char *)buffer)[i+j];
124 lprintf("%02x ", (unsigned int)c);
128 for (j=0; j < 16; j++) {
129 u8 c = ((unsigned char *)buffer)[i+j];
130 if (c >= 'a' && c <= 'z')
132 else if (c >= 'A' && c <= 'Z')
134 else if (c >= '0' && c <= '9')
136 else if (c >= 0x20 && c <= 127)
144 printf("%s", linebuf);
150 struct card_seq_num {
152 } __attribute__((packed));
154 void read_from(enum eyefi_file);
155 void write_to(enum eyefi_file, void *, int);
156 struct card_seq_num read_seq_from(enum eyefi_file file)
158 struct card_seq_num *ret;
165 * For O_DIRECT writes to files, we need
166 * to be 512 byte aligned on Linux, I think.
167 * So, just align this to something big
168 * and be done with it. FIXME :)
172 unsigned long addr = (unsigned long)&unaligned_buf[BUFSZ];
175 debug_printf(4, "buf: %p\n", buf);
176 debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]);
179 struct card_seq_num seq;
182 * The real manager does this so we might
185 void zero_card_files(void)
187 write_to(REQM, buf, BUFSZ);
188 write_to(REQC, buf, BUFSZ);
189 write_to(RSPM, buf, BUFSZ);
190 write_to(RSPC, buf, BUFSZ);
203 debug_printf(2, "Initializing card...\n");
206 seq = read_seq_from(RSPC);
209 debug_printf(2, "Done initializing card...\n");
212 void open_error(char *file)
214 fprintf(stderr, "unable to open '%s'\n", file);
215 fprintf(stderr, "Is the Eye-Fi card inserted and mounted at: %s ?\n", eyefi_mount);
216 fprintf(stderr, "Do you have write permissions to it?\n");
222 void read_from(enum eyefi_file __file)
229 char *file = eyefi_file(__file);
233 fd = open(file, O_RDONLY);
236 retcntl = fcntl(fd, F_SETFL, O_DIRECT);
241 ret = read(fd, buf, BUFSZ);
248 debug_printf(3, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl);
249 for (i=0; i < BUFSZ; i++) {
250 c = ((char *)buf)[i];
257 // printf(" zeros: %d", zeros);
263 void write_to(enum eyefi_file __file, void *stuff, int len)
267 char *file = eyefi_file(__file);
273 if (debug_level > 3) {
274 debug_printf(3, "%s('%s', ..., %d)\n", __func__, file, len);
277 memset(buf, 0, BUFSZ);
278 memcpy(buf, stuff, len);
279 fd = open(file, O_RDWR|O_DIRECT|O_CREAT, 0600);
280 //ret = lseek(fd, 0, SEEK_SET);
285 ret = write(fd, buf, BUFSZ);
288 debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len);
295 * Most of the eyefi strings are pascal-style with
296 * a length byte preceeding content. (Did pascal
297 * have just a byte for length or more??)
299 struct pascal_string {
302 } __attribute__((packed));
304 void print_pascal_string(struct pascal_string *str)
307 for (i = 0; i < str->length; i++)
308 printf("%c", str->value[i]);
312 * The 'o' command has several sub-commands:
314 enum card_info_subcommand {
319 UNKNOWN1 = 5, // Chris says these are
320 UNKNOWN2 = 6, // checksums
324 struct card_info_req {
327 } __attribute__((packed));
329 struct card_info_rsp_key {
330 struct pascal_string key;
337 } __attribute__((packed));
339 struct card_info_api_url {
340 struct pascal_string key;
343 struct card_info_log_len {
346 } __attribute__((packed));
348 #define write_struct(file, s) write_to((file), s, sizeof(*(s)))
350 void print_mac(struct mac_address *mac)
353 for (i=0; i < MAC_BYTES-1; i++) {
354 printf("%02x:", mac->mac[i]);
356 printf("%02x\n", mac->mac[i]);
361 //u32 tmpseq = be32_to_u32(seq.seq);
362 //seq.seq = u32_to_be32(tmpseq+1);
364 write_struct(REQC, &seq);
367 u32 current_seq(void)
372 void wait_for_response(void)
375 debug_printf(3, "waiting for response...\n");
377 for (i = 0; i < 50; i++) {
378 struct card_seq_num cardseq = read_seq_from(RSPC);
379 u32 rsp = cardseq.seq;
380 debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, current_seq(),
382 if (rsp == current_seq())
386 debug_printf(3, "got good seq, reading RSPM...\n");
388 debug_printf(3, "done reading RSPM\n");
390 struct byte_response {
403 char essid[ESSID_LEN];
404 signed char strength;
406 } __attribute__((packed));
408 struct scanned_net_list {
410 struct scanned_net nets[100];
411 } __attribute__((packed));
413 struct configured_net {
414 char essid[ESSID_LEN];
415 } __attribute__((packed));
417 struct configured_net_list {
419 struct configured_net nets[100];
420 } __attribute__((packed));
422 char *net_test_states[] = {
425 "verifying network key",
427 "testing connection to Eye-Fi server",
431 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
433 char *net_test_state_name(u8 state)
435 int size = ARRAY_SIZE(net_test_states);
438 return net_test_states[state];
441 char *net_types[] = {
449 char *net_type_name(u8 type)
451 int size = ARRAY_SIZE(net_types);
454 return net_types[type];
457 #define WPA_KEY_BYTES 32
459 u8 key[WPA_KEY_BYTES];
460 } __attribute((packed));
462 #define WEP_KEY_BYTES 32
464 u8 key[WEP_KEY_BYTES];
465 } __attribute((packed));
473 } __attribute((packed));
479 char essid[ESSID_LEN];
480 struct network_key key;
481 } __attribute((packed));
485 if ((c >= 'A') && (c <= 'Z'))
493 if ((c >= '0') && (c <= '9'))
495 else if ((c >= 'a') && (c <= 'z'))
496 return (c - 'a') + 10;
497 debug_printf(5, "non-hex character: '%c'/'%c'\n", c, lc);
502 * Take a string like "0ab1" and make it
503 * a series of bytes: { 0x0a, 0xb1 }
505 * Destroys the original string.
507 char *convert_ascii_to_hex(char *ascii, int len)
511 fprintf(stderr, "%s() must be even number of bytes: %d\n",
515 for (i=0; i < len; i+=2) {
516 u8 high = atoh(ascii[i]);
517 u8 low = atoh(ascii[i+1]);
518 u8 byte = (high<<4 | low);
519 debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte);
522 for (i=len/2; i < len; i++)
527 #define PASSPHRASE_PROG "wpa_passphrase"
529 struct wpa_key *make_wpa_key(char *essid, char *pass)
531 char program[] = PASSPHRASE_PROG;
532 // 7 for 2 spaces, 4 quotes and a \0
533 char redirect[] = " 2> /dev/null";
534 char *cmdbuf = malloc(strlen(essid) + strlen(pass) + strlen(program) + 7 +
540 sprintf(cmdbuf, "%s '%s' '%s' %s", program, essid, pass, redirect);
541 FILE *pipe = popen(cmdbuf, "r");
543 perror("\nunable to execute " PASSPHRASE_PROG);
547 int key_chars = WPA_KEY_BYTES*2;
548 char hex_key_in_ascii[key_chars+1];
551 while (fgets(&line[0], 1023, pipe)) {
552 debug_printf(4, "read from %s: '%s'\n", PASSPHRASE_PROG, line);
553 read = sscanf(&line[0], " psk=%64s", &hex_key_in_ascii[0]);
558 int exit_code = pclose(pipe);
559 if (!read || exit_code) {
560 fprintf(stderr, "\nunable to read wpa key from %s\n", PASSPHRASE_PROG);
561 fprintf(stderr, "Is wpa_supplicant installed?\n");
564 debug_printf(4, "ascii key: '%s'\n", hex_key_in_ascii);
565 char *hex_key = convert_ascii_to_hex(hex_key_in_ascii, key_chars);
566 struct wpa_key *key = malloc(sizeof(*key));
567 memcpy(&key->key[0], hex_key, WPA_KEY_BYTES);
572 void card_info_cmd(enum card_info_subcommand cmd)
574 struct card_info_req cir;
576 cir.subcommand = cmd;
578 write_struct(REQM, &cir);
582 u32 fetch_log_length(void)
584 card_info_cmd(LOG_LEN);
585 struct card_info_log_len *loglen = buf;
586 return be32_to_u32(loglen->val);
589 void print_log_len(void)
591 u32 len = fetch_log_length();
592 printf("log len: %08lx\n", len);
595 void print_card_mac(void)
597 debug_printf(2, "%s()\n", __func__);
598 card_info_cmd(MAC_ADDRESS);
599 struct mac_address *mac = buf;
600 assert(mac->length == MAC_BYTES);
601 printf("card mac address: ");
605 void print_card_key(void)
607 debug_printf(2, "%s()\n", __func__);
608 card_info_cmd(CARD_KEY);
609 struct card_info_rsp_key *foo = buf;
610 printf("card key (len: %d): '", foo->key.length);
611 print_pascal_string(&foo->key);
615 struct noarg_request {
619 void issue_noarg_command(u8 cmd)
621 struct noarg_request req;
623 write_struct(REQM, &req);
627 void scan_print_nets(void)
631 debug_printf(2, "%s()\n", __func__);
632 issue_noarg_command('g');
633 struct scanned_net_list *scanned = buf;
634 if (scanned->nr == 0) {
635 printf("unable to detect any wireless networks\n");
638 printf("Scanned wireless networks:\n");
639 for (i=0; i < scanned->nr; i++) {
640 struct scanned_net *net = &scanned->nets[i];
641 printf("'%s' type(%d): %s, strength: %d\n", net->essid,
643 net_type_name(net->type),
648 void print_configured_nets(void)
651 struct configured_net_list *configured;
653 debug_printf(2, "%s()\n", __func__);
654 issue_noarg_command('l');
656 if (configured->nr == 0) {
657 printf("No wireless networks configured on card\n");
660 printf("configured wireless networks:\n");
661 for (i=0; i < configured->nr; i++) {
662 struct configured_net *net = &configured->nets[i];
663 printf("'%s'\n", net->essid);
667 void reboot_card(void)
669 debug_printf(2, "%s()\n", __func__);
670 issue_noarg_command('b');
673 void copy_wep_key(struct wep_key *dst, struct wep_key *src)
675 memcpy(&dst->key, &src->key, sizeof(*dst));
678 void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src)
680 memcpy(&dst->key, &src->key, sizeof(*dst));
683 void network_action(char cmd, char *essid, char *wpa_ascii)
685 struct net_request nr;
686 memset(&nr, 0, sizeof(nr));
689 strcpy(&nr.essid[0], essid);
690 nr.essid_len = strlen(essid);
691 struct wpa_key *wpakey;
693 wpakey = make_wpa_key(essid, wpa_ascii);
694 nr.key.len = sizeof(*wpakey);
695 copy_wpa_key(&nr.key.wpa, wpakey);
697 write_struct(REQM, &nr);
701 void add_network(char *essid, char *wpa_ascii)
703 debug_printf(2, "%s()\n", __func__);
704 network_action('a', essid, wpa_ascii);
707 void remove_network(char *essid)
709 debug_printf(2, "%s()\n", __func__);
710 network_action('d', essid, NULL);
713 int try_connection_to(char *essid, char *wpa_ascii)
718 char *type = net_type_name(WPA);
720 type = net_type_name(UNSECURED);
721 printf("trying to connect to %s network: '%s'", type, essid);
723 printf(" with passphrase: '%s'", wpa_ascii);
727 network_action('t', essid, wpa_ascii);
731 for (i=0; i < 200; i++) {
732 struct byte_response *r;
733 issue_noarg_command('s');
736 char *state = net_test_state_name(rsp);
737 if (rsp == last_rsp) {
742 printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state);
746 if (!strcmp("success", state)) {
750 if (!strcmp("not scanning", state))
752 if (!strcmp("unknown", state))
757 printf("Succeeded connecting to: '%s'\n", essid);
759 printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid,
760 rsp, net_test_state_name(rsp));
765 struct fetch_log_cmd {
768 } __attribute__((packed));
771 * When you ask for the log at offset 0x0, you
772 * get back 8 bytes of offsets into the rest of
775 struct first_log_response {
778 u8 data[EYEFI_BUF_SIZE-8];
779 } __attribute__((packed));
781 struct rest_log_response {
782 u8 data[EYEFI_BUF_SIZE];
783 } __attribute__((packed));
785 unsigned char *get_log_at_offset(u32 offset)
787 struct fetch_log_cmd cmd;
789 cmd.offset = u32_to_be32(offset);
791 debug_printf(2, "getting log at offset: %08lx\n", offset);
792 write_struct(REQM, &cmd);
803 u32 log_size = fetch_log_length();
804 char *resbuf = malloc(log_size);
806 int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE;
807 for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) {
808 debug_printf(1, "fetching EyeFi card log part %d/%d...",
809 i+1, nr_bufs_per_log);
811 get_log_at_offset(EYEFI_BUF_SIZE*i);
812 debug_printf(1, "done\n");
816 struct first_log_response *log = buf;
817 log_end = be32_to_u32(log->log_end);
818 log_start = be32_to_u32(log->log_start);
819 debug_printf(2, "log end: 0x%04lx\n", log_end);
820 debug_printf(2, "log start: 0x%04lx\n", log_start);
821 log_data = &log->data[0];
822 log_size = ARRAY_SIZE(log->data);
824 struct rest_log_response *log = buf;
825 log_data = &log->data[0];
826 log_size = ARRAY_SIZE(log->data);
828 debug_printf(3, "writing %ld bytes to resbuf[%d]\n",
829 log_size, total_bytes);
830 memcpy(&resbuf[total_bytes], log_data, log_size);
831 total_bytes += log_size;
833 // The last byte *should* be a null, and the
834 // official software does not print it.
835 for (i = 0; i < total_bytes-1; i++) {
836 int offset = (log_start+i)%total_bytes;
837 char c = resbuf[offset];
838 // the official software converts UNIX to DOS-style
839 // line breaks, so we'll do the same
845 // just some simple sanity checking to make sure what
846 // we are fetching looks valid
847 int null_bytes_left = 20;
848 if (resbuf[log_end] != 0) {
849 debug_printf(2, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n",
850 log_end, log_end, resbuf[log_end]);
851 for (i=0; i<log_size; i++) {
854 if (null_bytes_left <= 0)
857 debug_printf(2, "null byte %d\n", i);
866 if ((o >= '0') && (o <= '7'))
871 int octal_esc_to_chr(char *input) {
874 int len = strlen(input);
876 //intf("%s('%s')\n", __func__, input);
877 if (input[0] != '\\')
882 for (i=1; i < len ; i++) {
885 int tmp = atoo(input[i]);
886 //intf("tmp: %d\n", tmp);
895 char *replace_escapes(char *str)
899 debug_printf(4, "%s(%s)\n", __func__, str);
900 for (i=0; i < strlen(str); i++) {
901 int esc = octal_esc_to_chr(&str[i]);
907 str[output++] = str[i];
910 debug_printf(4, "'%s' %d\n", str, output);
914 #define LINEBUFSZ 1024
915 void locate_eyefi_mount(void)
917 char line[LINEBUFSZ];
918 FILE *mounts = fopen("/proc/mounts", "r");
926 while (fgets(&line[0], 1023, mounts)) {
928 read = sscanf(&line[0], "%s %s %s %s %d %d",
929 &dev[0], &mnt[0], &fs[0], &opt[0],
931 // only look at fat filesystems:
932 if (strcmp(fs, "msdos") && strcmp(fs, "vfat")) {
933 debug_printf(2, "fs at '%s' is not fat, skipping...\n", mnt);
936 // Linux's /proc/mounts has spaces like this \040
937 replace_escapes(&mnt[0]);
938 strcpy(&eyefi_mount[0], &mnt[0]);
939 char *file = eyefi_file(REQM);
940 debug_printf(2, "looking for EyeFi file here: '%s'\n", file);
944 statret = stat(file, &statbuf);
948 debug_printf(1, "located EyeFi card at: %s\n", eyefi_mount);
957 printf(" eyefitest [OPTIONS]\n");
958 printf(" -a ESSID add network (implies test unless --force)\n");
959 printf(" -t ESSID test network\n");
960 printf(" -p KEY set WPA key for add/test\n");
961 printf(" -r ESSID remove network\n");
962 printf(" -s scan for networks\n");
963 printf(" -c list configured networks\n");
964 printf(" -b reboot card\n");
965 printf(" -d level set debugging level (default: 1)\n");
966 printf(" -k print card unique key\n");
967 printf(" -l dump card log\n");
968 printf(" -m print card mac\n");
972 int main(int argc, char **argv)
977 debug_printf(3, "%s starting...\n", argv[0]);
979 locate_eyefi_mount();
981 //static int passed_wep = 0;
982 //static int passed_wpa = 0;
983 static int force = 0;
984 static struct option long_options[] = {
985 //{"wep", 'x', &passed_wep, 1},
986 //{"wpa", 'y', &passed_wpa, 1},
987 {"force", 0, &force, 1},
988 {"help", 'h', NULL, 1},
995 char network_action = 0;
996 debug_printf(3, "about to parse arguments\n");
997 while ((c = getopt_long_only(argc, argv, "a:bcd:klmp:r:st:",
998 &long_options[0], &option_index)) != -1) {
999 debug_printf(3, "argument: '%c' %d optarg: '%s'\n", c, c, optarg);
1002 // was a long argument
1014 print_configured_nets();
1017 debug_level = atoi(optarg);
1040 debug_printf(3, "after arguments essid: '%s' passwd: '%s'\n", essid, passwd);
1041 if (network_action && essid) {
1043 switch (network_action) {
1045 ret = try_connection_to(essid, passwd);
1049 ret = try_connection_to(essid, passwd);
1051 debug_printf(1, "forced: skipping network test\n");
1054 printf("Error connecting to network '%s', not adding.\n", essid);
1055 printf("use --force to override\n");
1058 add_network(essid, passwd);
1061 remove_network(essid);