From 0e17d59461350cd04d90619bbac31ed6eee4e356 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Sat, 12 Jul 2008 12:49:26 -0700 Subject: [PATCH] Add support for other operating systems: chdk OS X --- eyefi-chdk.c | 25 ++ eyefi-config.c | 918 +++++++++++++------------------------------------ eyefi-linux.c | 125 +++++++ eyefi-osx.c | 8 + eyefi-unix.c | 333 ++++++++++++++++++ 5 files changed, 726 insertions(+), 683 deletions(-) create mode 100644 eyefi-chdk.c create mode 100644 eyefi-linux.c create mode 100644 eyefi-osx.c create mode 100755 eyefi-unix.c diff --git a/eyefi-chdk.c b/eyefi-chdk.c new file mode 100644 index 0000000..626ce7f --- /dev/null +++ b/eyefi-chdk.c @@ -0,0 +1,25 @@ +/* + * eyefi-chdk.c + * + * Copyright (C) 2008 Dave Hansen + * + * This software may be redistributed and/or modified under the terms of + * the GNU General Public License ("GPL") version 2 as published by the + * Free Software Foundation. + */ + +#include "eyefi-config.h" + +int eyefi_printf(const char *fmt, ...) +{ + va_list args; + int r; + + va_start(args, fmt); + r = printf(fmt, args); + va_end(args); + + return r; +} + + diff --git a/eyefi-config.c b/eyefi-config.c index 2fc7933..41c2c3e 100755 --- a/eyefi-config.c +++ b/eyefi-config.c @@ -1,5 +1,5 @@ /* - * eyefitest.c + * eyefi-config.c * * Copyright (C) 2008 Dave Hansen * @@ -8,36 +8,22 @@ * Free Software Foundation. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "eyefi-config.h" -int debug_level = 1; -#define debug_printf(level, args...) do { \ - if ((level) <= debug_level) \ - fprintf(stderr, ## args); \ - } while(0) +int eyefi_debug_level = 0; + +int eyefi_printf(const char *fmt, ...) +{ + va_list args; + int r; -#define O_DIRECT 00040000 /* direct disk access hint */ + va_start(args, fmt); + r = printf(fmt, args); + va_end(args); -enum eyefi_file { - REQC, - REQM, - RSPC, - RSPM -}; + return r; +} -#define PATHNAME_MAX 4096 -char eyefi_mount[PATHNAME_MAX]; // PATH_MAX anyone? static char *eyefi_file_name(enum eyefi_file file) { switch (file) { @@ -50,7 +36,7 @@ static char *eyefi_file_name(enum eyefi_file file) return NULL; } -static char *eyefi_file_on(enum eyefi_file file, char *mnt) +char *eyefi_file_on(enum eyefi_file file, char *mnt) { char *filename = eyefi_file_name(file); char *full = malloc(PATHNAME_MAX); @@ -60,34 +46,18 @@ static char *eyefi_file_on(enum eyefi_file file, char *mnt) return full; } - -#define BUFSZ 16384 -#define EYEFI_BUF_SIZE 16384 -char unaligned_buf[BUFSZ*2]; -void *buf; - /* - * Just a few functions so that I can't easily forget about - * endinness. + * This lets us get away with a static allocation + * for the buffer. We make it size*2 so that we're + * guaranteed to be able to get a "size" buffer + * aligned inside of the larger one. */ -struct __be32 { - u32 val; -} __attribute__((packed)); -typedef struct __be32 be32; +static char unaligned_buf[EYEFI_BUF_SIZE*2]; +static void *eyefi_buf; -/* - * These two obviously need to get fixed for - * big endian machines. - */ -u32 be32_to_u32(be32 src) -{ - return swap_bytes(src.val); -} -be32 u32_to_be32(u32 src) +void *eyefi_response(void) { - be32 ret; - ret.val = swap_bytes(src); - return ret; + return eyefi_buf; } void dumpbuf(const char *buffer, int bytesToWrite) @@ -132,17 +102,15 @@ void dumpbuf(const char *buffer, int bytesToWrite) } } -struct card_seq_num { - u32 seq; -} __attribute__((packed)); - void read_from(enum eyefi_file); void write_to(enum eyefi_file, void *, int); + +struct card_seq_num eyefi_seq; struct card_seq_num read_seq_from(enum eyefi_file file) { struct card_seq_num *ret; read_from(file); - ret = buf; + ret = eyefi_buf; return *ret; } @@ -151,28 +119,30 @@ struct card_seq_num read_seq_from(enum eyefi_file file) * to be 512 byte aligned on Linux, I think. * So, just align this to something big * and be done with it. FIXME :) + * + * This probably isn't necessary on chdk, + * since I don't think it buffers I/O at + * all. */ void align_buf(void) { - unsigned long addr = (unsigned long)&unaligned_buf[BUFSZ]; - addr &= ~(BUFSZ-1); - buf = (void *)addr; - debug_printf(4, "buf: %p\n", buf); + unsigned long addr = (unsigned long)&unaligned_buf[EYEFI_BUF_SIZE]; + addr &= ~(EYEFI_BUF_SIZE-1); + eyefi_buf = (void *)addr; + debug_printf(4, "buf: %p\n", eyefi_buf); debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]); } -struct card_seq_num seq; - /* * The real manager does this so we might * as well, too. */ void zero_card_files(void) { - //write_to(REQM, buf, BUFSZ); - write_to(REQC, buf, BUFSZ); - write_to(RSPM, buf, BUFSZ); - write_to(RSPC, buf, BUFSZ); + //write_to(REQM, eyefi_buf, EYEFI_BUF_SIZE); + write_to(REQC, eyefi_buf, EYEFI_BUF_SIZE); + write_to(RSPM, eyefi_buf, EYEFI_BUF_SIZE); + write_to(RSPC, eyefi_buf, EYEFI_BUF_SIZE); read_from(REQM); read_from(REQC); @@ -180,237 +150,109 @@ void zero_card_files(void) read_from(RSPC); } -char lower(char c) -{ - if ((c >= 'A') && (c <= 'Z')) - c += ('a' - 'A'); - return c; -} - -int atoh(char c) -{ - char lc = lower(c); - if ((c >= '0') && (c <= '9')) - return c - '0'; - else if ((c >= 'a') && (c <= 'z')) - return (c - 'a') + 10; - debug_printf(5, "non-hex character: '%c'/'%c'\n", c, lc); - return -1; -} - -int atoo(char o) -{ - if ((o >= '0') && (o <= '7')) - return atoh(o); - return -1; -} - -int octal_esc_to_chr(char *input) { - int i=0; - int ret = 0; - int len = strlen(input); - - //intf("%s('%s')\n", __func__, input); - if (input[0] != '\\') - return -1; - if (len < 4) - return -1; - - for (i=1; i < len ; i++) { - if (i > 3) - break; - int tmp = atoo(input[i]); - //intf("tmp: %d\n", tmp); - if (tmp < 0) - return tmp; - ret <<= 3; - ret += tmp; - } - return ret; -} - -char *replace_escapes(char *str) -{ - int i; - int output = 0; - debug_printf(4, "%s(%s)\n", __func__, str); - for (i=0; i < strlen(str); i++) { - int esc = octal_esc_to_chr(&str[i]); - if (esc >= 0) { - str[output++] = esc; - i += 3; - continue; - } - str[output++] = str[i]; - } - str[output] = '\0'; - debug_printf(4, "replaced escapes in: '%s' bytes of output: %d\n", str, output); - return str; -} - -#define LINEBUFSZ 1024 -char *locate_eyefi_mount(void) -{ - char line[LINEBUFSZ]; - FILE *mounts = fopen("/proc/mounts", "r"); - - char dev[LINEBUFSZ]; - char mnt[LINEBUFSZ]; - char fs[LINEBUFSZ]; - char opt[LINEBUFSZ]; - int foo; - int bar; - - if (strlen(eyefi_mount)) - return &eyefi_mount[0]; - - while (fgets(&line[0], 1023, mounts)) { - int read; - read = sscanf(&line[0], "%s %s %s %s %d %d", - &dev[0], &mnt[0], &fs[0], &opt[0], - &foo, &bar); - // only look at fat filesystems: - if (strcmp(fs, "msdos") && strcmp(fs, "vfat")) { - debug_printf(2, "fs at '%s' is not fat, skipping...\n", mnt); - continue; - } - // Linux's /proc/mounts has spaces like this \040 - replace_escapes(&mnt[0]); - char *file = eyefi_file_on(REQM, &mnt[0]); - debug_printf(2, "looking for EyeFi file here: '%s'\n", file); - - struct stat statbuf; - int statret; - statret = stat(file, &statbuf); - free(file); - if (statret) { - debug_printf(2, "fs at: %s is not an Eye-Fi card, skipping...\n", - eyefi_mount); - continue; - } - strcpy(&eyefi_mount[0], &mnt[0]); - debug_printf(1, "located EyeFi card at: '%s'\n", eyefi_mount); - break; - } - fclose(mounts); - if (strlen(eyefi_mount)) - return &eyefi_mount[0]; - return NULL; -} - void init_card() { char *mnt; - if (buf != NULL) + if (eyefi_buf != NULL) return; debug_printf(2, "Initializing card...\n"); mnt = locate_eyefi_mount(); - if (mnt == NULL) { - debug_printf(1, "unable to locate Eye-Fi card\n"); - if (debug_level < 5) - debug_printf(0, "please run with '-d5' option and report the output\n"); - else { - debug_printf(0, "----------------------------------------------\n"); - debug_printf(0, "Debug information:\n"); - system("cat /proc/mounts >&2"); - } - exit(1); - } + if (mnt == NULL) + return; align_buf(); zero_card_files(); - seq = read_seq_from(RSPC); - if (seq.seq == 0) - seq.seq = 0x1234; + eyefi_seq = read_seq_from(RSPC); + if (eyefi_seq.seq == 0) + eyefi_seq.seq = 0x1234; + eyefi_seq.seq++; debug_printf(2, "Done initializing card...\n"); + debug_printf(2, "seq was: %04lx\n", eyefi_seq.seq); } static char *eyefi_file(enum eyefi_file file) { init_card(); - return eyefi_file_on(file, &eyefi_mount[0]); -} - -void open_error(char *file) -{ - fprintf(stderr, "unable to open '%s'\n", file); - fprintf(stderr, "Is the Eye-Fi card inserted and mounted at: %s ?\n", eyefi_mount); - fprintf(stderr, "Do you have write permissions to it?\n"); - fprintf(stderr, "debug information:\n"); - if (debug_level > 0) - system("cat /proc/mounts >&2"); - if (debug_level > 1) - perror("bad open"); - exit(1); + return eyefi_file_on(file, locate_eyefi_mount()); } void read_from(enum eyefi_file __file) { - u8 c; - int i; int ret, retcntl; int fd; - int zeros = 0; char *file = eyefi_file(__file); init_card(); +retry: fd = open(file, O_RDONLY); if (fd < 0) - open_error(file); - retcntl = fcntl(fd, F_SETFL, O_DIRECT); + open_error(file, fd); + retcntl = fd_dont_cache(fd); if (retcntl < 0) { perror("bad fcntl"); exit(1); } - ret = read(fd, buf, BUFSZ); - if (debug_level > 3) - dumpbuf(buf, 128); + ret = read(fd, eyefi_buf, EYEFI_BUF_SIZE); + if (eyefi_debug_level > 3) + dumpbuf(eyefi_buf, 128); if (ret < 0) { - perror("bad read"); + close(fd); + perror("bad read, retrying..."); + goto retry; exit(1); } debug_printf(4, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl); - for (i=0; i < BUFSZ; i++) { - c = ((char *)buf)[i]; + /* + * There was a time when I was carefully recording how each response + * looked, and I counted the zeros in each response. I don't care + * any more. + u8 c; + int zeros = 0; + int i; + for (i=0; i < EYEFI_BUF_SIZE; i++) { + c = ((char *)eyefi_buf)[i]; if (c == '\0') { zeros++; continue; } } - //if (zeros) - // printf(" zeros: %d", zeros); - //fsync(fd); + */ free(file); close(fd); } +int fake_write = 0; void write_to(enum eyefi_file __file, void *stuff, int len) { int ret; int fd; char *file; + if (fake_write) + return; + init_card(); file = eyefi_file(__file); if (len == -1) len = strlen(stuff); - if (debug_level > 3) { + if (eyefi_debug_level > 3) { debug_printf(3, "%s('%s', ..., %d)\n", __func__, file, len); dumpbuf(stuff, len); } - memset(buf, 0, BUFSZ); - memcpy(buf, stuff, len); - fd = open(file, O_RDWR|O_DIRECT|O_CREAT, 0600); - //ret = lseek(fd, 0, SEEK_SET); + memset(eyefi_buf, 0, EYEFI_BUF_SIZE); + memcpy(eyefi_buf, stuff, len); + fd = open(file, O_RDWR|O_CREAT, 0600); if (fd < 0) - open_error(file); - if (debug_level > 3) - dumpbuf(buf, 128); - ret = write(fd, buf, BUFSZ); - //fsync(fd); + open_error(file, fd); + ret = fd_dont_cache(fd); + if (ret < 0) + open_error(file, ret); + if (eyefi_debug_level > 3) + dumpbuf(eyefi_buf, 128); + ret = write(fd, eyefi_buf, EYEFI_BUF_SIZE); close(fd); debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len); if (ret < 0) { @@ -421,154 +263,66 @@ void write_to(enum eyefi_file __file, void *stuff, int len) free(file); } -/* - * Most of the eyefi strings are pascal-style with - * a length byte preceeding content. (Did pascal - * have just a byte for length or more??) - */ -struct pascal_string { - u8 length; - u8 value[32]; -} __attribute__((packed)); - -void print_pascal_string(struct pascal_string *str) -{ - int i; - for (i = 0; i < str->length; i++) - printf("%c", str->value[i]); -} - -/* - * The 'o' command has several sub-commands: - */ -enum card_info_subcommand { - MAC_ADDRESS = 1, - FIRMWARE_INFO = 2, - CARD_KEY = 3, - API_URL = 4, - UNKNOWN1 = 5, // Chris says these are - UNKNOWN2 = 6, // checksums - LOG_LEN = 7, -}; - -struct card_info_req { - u8 o; - u8 subcommand; -} __attribute__((packed)); - -struct card_info_rsp_key { - struct pascal_string key; -}; - -struct card_firmware_info { - struct pascal_string info; -}; - -#define MAC_BYTES 6 -struct mac_address { - u8 length; - u8 mac[MAC_BYTES]; -} __attribute__((packed)); - -struct card_info_api_url { - struct pascal_string key; -}; - -struct card_info_log_len { - u8 len; - be32 val; -} __attribute__((packed)); - #define write_struct(file, s) write_to((file), s, sizeof(*(s))) -void print_mac(struct mac_address *mac) -{ - int i; - for (i=0; i < MAC_BYTES-1; i++) { - printf("%02x:", mac->mac[i]); - } - printf("%02x\n", mac->mac[i]); -} - void inc_seq(void) { + /* + * Oddly enough, the sequence number appears + * to be of normal endianness. + */ //u32 tmpseq = be32_to_u32(seq.seq); //seq.seq = u32_to_be32(tmpseq+1); - seq.seq++; - write_struct(REQC, &seq); + eyefi_seq.seq++; + write_struct(REQC, &eyefi_seq); } -u32 current_seq(void) +u32 eyefi_current_seq(void) { - return seq.seq; + return eyefi_seq.seq; } int wait_for_response(void) { + int good_rsp = 0; + u32 rsp; int i; debug_printf(3, "waiting for response...\n"); inc_seq(); - for (i = 0; i < 50; i++) { + for (i = 0; i < 10; i++) { struct card_seq_num cardseq = read_seq_from(RSPC); - u32 rsp = cardseq.seq; - debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, current_seq(), + debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, eyefi_current_seq(), cardseq.seq); - if (rsp == current_seq()) + rsp = cardseq.seq; + if (rsp == eyefi_current_seq()) { + good_rsp = 1; break; + } + if (eyefi_debug_level > 4) { + read_from(REQM); + debug_printf(1, "command issued was: '%c'\n", ((char *)eyefi_buf)[0]); + } usleep(300000); } - if (i == 50) { + if (!good_rsp) { debug_printf(1, "never saw card seq response\n"); return -1; } - debug_printf(3, "got good seq, reading RSPM...\n"); + debug_printf(3, "got good seq (%ld), reading RSPM...\n", rsp); read_from(RSPM); debug_printf(3, "done reading RSPM\n"); return 0; } -struct byte_response { - u8 response; -}; - -enum net_type { - UNSECURED, - WEP, - WPA, - WPA2 -}; - -#define ESSID_LEN 32 -struct scanned_net { - char essid[ESSID_LEN]; - signed char strength; - u8 type; -} __attribute__((packed)); - -struct scanned_net_list { - u8 nr; - struct scanned_net nets[100]; -} __attribute__((packed)); - -struct configured_net { - char essid[ESSID_LEN]; -} __attribute__((packed)); - -struct configured_net_list { - u8 nr; - struct configured_net nets[100]; -} __attribute__((packed)); char *net_test_states[] = { - "not scanning", - "locating network", - "verifying network key", - "waiting for DHCP", - "testing connection to Eye-Fi server", - "success", + "not scanning", + "locating network", + "verifying network key", + "waiting for DHCP", + "testing connection to Eye-Fi server", + "success", }; -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - char *net_test_state_name(u8 state) { int size = ARRAY_SIZE(net_test_states); @@ -593,31 +347,23 @@ char *net_type_name(u8 type) return net_types[type]; } -#define WPA_KEY_BYTES 32 -struct wpa_key { - u8 key[WPA_KEY_BYTES]; -} __attribute((packed)); - -#define WEP_KEY_BYTES 32 -struct wep_key { - u8 key[WEP_KEY_BYTES]; -} __attribute((packed)); - -struct network_key { - u8 len; - union { - struct wpa_key wpa; - struct wep_key wep; - }; -} __attribute((packed)); - -#define KEY_LEN 32 -struct net_request { - char req; - u8 essid_len; - char essid[ESSID_LEN]; - struct network_key key; -} __attribute((packed)); +static char lower(char c) +{ + if ((c >= 'A') && (c <= 'Z')) + c += ('a' - 'A'); + return c; +} + +int atoh(char c) +{ + char lc = lower(c); + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'a') && (c <= 'z')) + return (c - 'a') + 10; + debug_printf(5, "non-hex character: '%c'/'%c'\n", c, lc); + return -1; +} /* * Take a string like "0ab1" and make it @@ -649,8 +395,6 @@ char *convert_ascii_to_hex(char *ascii, int len) return &ascii[0]; } -#define PASSPHRASE_PROG "wpa_passphrase" - struct wpa_key *make_wpa_key(char *essid, char *pass) { struct wpa_key *key = malloc(sizeof(*key)); @@ -682,97 +426,106 @@ int card_info_cmd(enum card_info_subcommand cmd) u32 fetch_log_length(void) { + debug_printf(3, "%s()\n", __func__); card_info_cmd(LOG_LEN); - struct card_info_log_len *loglen = buf; + struct card_info_log_len *loglen = eyefi_buf; return be32_to_u32(loglen->val); } -void print_log_len(void) -{ - u32 len = fetch_log_length(); - printf("log len: %08lx\n", len); -} - -void print_card_mac(void) +struct card_firmware_info *fetch_card_firmware_info(void) { debug_printf(2, "%s()\n", __func__); - card_info_cmd(MAC_ADDRESS); - struct mac_address *mac = buf; - assert(mac->length == MAC_BYTES); - printf("card mac address: "); - print_mac(mac); + card_info_cmd(FIRMWARE_INFO); + return (struct card_firmware_info *)eyefi_buf; + return NULL; } -void print_card_firmware_info(void) +struct testbuf { + char cmd; + u8 l1; + char name[100]; +}; + +struct z { + char zeros[100]; +} z; + +void testit0(void) { - debug_printf(2, "%s()\n", __func__); - card_info_cmd(FIRMWARE_INFO); - struct card_firmware_info *info = buf; - printf("card firmware (len: %d): '", info->info.length); - print_pascal_string(&info->info); - printf("'\n"); + char c; + struct testbuf tb; + int i; + + strcpy(tb.name, "www.sr71.net/"); + tb.l1 = strlen(tb.name); + for (i = 0; i < 10; i++) { + tb.cmd = 'O'; + tb.l1 = i; + write_struct(RSPM, &z); + write_struct(REQM, &tb); + wait_for_response(); + printf("buffer after O %d:\n", i); + dumpbuf(eyefi_buf, 64); + printf("----------------\n"); + write_struct(REQM, &tb); + card_info_cmd(i); + printf("card info(%d):\n", i); + dumpbuf(eyefi_buf, 64); + printf("-----------\n"); + } + return; + + strcpy(tb.name, "/public/eyefi/servname"); + strcpy(tb.name, "/config/networks.xml"); + //tb.len = strlen(tb.name); + tb.l1 = 0; + for (c = 'O'; c <= 'O'; c++) { + tb.cmd = c; + write_struct(REQM, &tb); + wait_for_response(); + printf("dumping buffer:\n"); + dumpbuf(eyefi_buf, 64); + printf("buffer dump done\n"); + } } -void print_card_key(void) +struct card_info_rsp_key *fetch_card_key(void) { + struct card_info_rsp_key *key; + debug_printf(2, "%s()\n", __func__); card_info_cmd(CARD_KEY); - struct card_info_rsp_key *foo = buf; - printf("card key (len: %d): '", foo->key.length); - print_pascal_string(&foo->key); - printf("'\n"); + key = eyefi_buf; + return key; } -struct noarg_request { - u8 req; -}; - int issue_noarg_command(u8 cmd) { struct noarg_request req; + printf("%s() cmd: %d\n", __func__, cmd); req.req = cmd; write_struct(REQM, &req); return wait_for_response(); } -void scan_print_nets(void) +struct scanned_net_list *scan_nets(void) { - int i; + struct scanned_net_list *scanned; debug_printf(2, "%s()\n", __func__); issue_noarg_command('g'); - struct scanned_net_list *scanned = buf; - if (scanned->nr == 0) { - printf("unable to detect any wireless networks\n"); - return; - } - printf("Scanned wireless networks:\n"); - for (i=0; i < scanned->nr; i++) { - struct scanned_net *net = &scanned->nets[i]; - printf("'%s' type(%d): %s, strength: %d\n", net->essid, - net->type, - net_type_name(net->type), - net->strength); - } + scanned = eyefi_response(); + return scanned; } -void print_configured_nets(void) +struct configured_net_list *fetch_configured_nets(void) { - int i; struct configured_net_list *configured; debug_printf(2, "%s()\n", __func__); issue_noarg_command('l'); - configured = buf; - if (configured->nr == 0) { - printf("No wireless networks configured on card\n"); - return; - } - printf("configured wireless networks:\n"); - for (i=0; i < configured->nr; i++) { - struct configured_net *net = &configured->nets[i]; - printf("'%s'\n", net->essid); - } + configured = eyefi_buf; + return configured; } void reboot_card(void) @@ -821,276 +574,75 @@ void remove_network(char *essid) network_action('d', essid, NULL); } -int try_connection_to(char *essid, char *wpa_ascii) +int get_log_at_offset(u32 offset) { - int i; - int ret = -1; - - char *type = net_type_name(WPA); - if (!wpa_ascii) - type = net_type_name(UNSECURED); - printf("trying to connect to %s network: '%s'", type, essid); - if (wpa_ascii) - printf(" with passphrase: '%s'", wpa_ascii); - fflush(NULL); - - // test network - network_action('t', essid, wpa_ascii); - u8 last_rsp = -1; - - char rsp = '\0'; - for (i=0; i < 200; i++) { - struct byte_response *r; - issue_noarg_command('s'); - r = buf; - rsp = r->response; - char *state = net_test_state_name(rsp); - if (rsp == last_rsp) { - printf("."); - fflush(NULL);; - } else { - if (rsp) - printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state); - last_rsp = rsp; - } - - if (!strcmp("success", state)) { - ret = 0; - break; - } - if (!strcmp("not scanning", state)) - break; - if (!strcmp("unknown", state)) - break; - } - printf("\n"); - if (!ret) { - printf("Succeeded connecting to: '%s'\n", essid); - } else { - printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid, - rsp, net_test_state_name(rsp)); - } - return ret; -} - -struct fetch_log_cmd { - char m; - be32 offset; -} __attribute__((packed)); - -/* - * When you ask for the log at offset 0x0, you - * get back 8 bytes of offsets into the rest of - * the data - */ -struct first_log_response { - be32 log_end; - be32 log_start; - u8 data[EYEFI_BUF_SIZE-8]; -} __attribute__((packed)); - -struct rest_log_response { - u8 data[EYEFI_BUF_SIZE]; -} __attribute__((packed)); - -unsigned char *get_log_at_offset(u32 offset) -{ - int ret; struct fetch_log_cmd cmd; cmd.m = 'm'; cmd.offset = u32_to_be32(offset); debug_printf(2, "getting log at offset: %08lx\n", offset); write_struct(REQM, &cmd); - ret = wait_for_response(); - if (!ret) - return buf; - return NULL; + return wait_for_response(); } -int get_log(void) +void add_log_piece(u8 *log, int log_len, u8 *piece, int piece_pos, int piece_size) +{ + debug_printf(0, "%s(%p, %d, %p, %d, %d)\n", __func__, log, log_len, piece, piece_pos, piece_size); + if (piece_pos + piece_size > log_len) { + int overflow_by = (piece_pos + piece_size) - log_len; + int piece_overrun_pos = piece_size - overflow_by; + piece_size -= overflow_by; + memcpy(&log[0], &piece[piece_overrun_pos], overflow_by); + debug_printf(0, "writing %d bytes to logbuf[0] from piece[%d]\n", + overflow_by, piece_overrun_pos); + } + debug_printf(0, "writing %d bytes to logbuf[%d]\n", piece_size, piece_pos); + memcpy(&log[piece_pos], piece, piece_size); +} + +int get_log_into(u8 *resbuf) { int total_bytes = 0; + int ret; int i; u32 log_start; u32 log_end; - u32 log_size = fetch_log_length(); - char *resbuf = malloc(log_size); + u32 __log_size = fetch_log_length(); + int log_pieces = __log_size/EYEFI_BUF_SIZE; - int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE; - for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) { + if (__log_size <= 0) + return __log_size; + + /* There are 8 bytes of header in the first log entry + * to specify where the log starts and ends */ + u32 log_size = __log_size - 8; + + for (i = 0; i < log_pieces; i++) { debug_printf(1, "fetching EyeFi card log part %d/%d...", - i+1, nr_bufs_per_log); + i+1, log_pieces); fflush(NULL); - get_log_at_offset(EYEFI_BUF_SIZE*i); + ret = get_log_at_offset(EYEFI_BUF_SIZE*i); debug_printf(1, "done\n"); - u32 log_size; - u8 *log_data; + u8 *log_piece; + u32 log_piece_size; if (i == 0) { - struct first_log_response *log = buf; - log_end = be32_to_u32(log->log_end); - log_start = be32_to_u32(log->log_start); + struct first_log_response *log = eyefi_buf; + log_end = log_size - be32_to_u32(log->log_end); + log_start = log_size - be32_to_u32(log->log_start); debug_printf(2, "log end: 0x%04lx\n", log_end); debug_printf(2, "log start: 0x%04lx\n", log_start); - log_data = &log->data[0]; - log_size = ARRAY_SIZE(log->data); + log_piece = &log->data[0]; + log_piece_size = ARRAY_SIZE(log->data); } else { - struct rest_log_response *log = buf; - log_data = &log->data[0]; - log_size = ARRAY_SIZE(log->data); + struct rest_log_response *log = eyefi_buf; + log_piece = &log->data[0]; + log_piece_size = ARRAY_SIZE(log->data); } - debug_printf(3, "writing %ld bytes to resbuf[%d]\n", - log_size, total_bytes); - memcpy(&resbuf[total_bytes], log_data, log_size); - total_bytes += log_size; - } - // The last byte *should* be a null, and the - // official software does not print it. - for (i = 0; i < total_bytes-1; i++) { - int offset = (log_start+i)%total_bytes; - char c = resbuf[offset]; - // the official software converts UNIX to DOS-style - // line breaks, so we'll do the same - if (c == '\n') - printf("%c", '\r'); - printf("%c", c); + add_log_piece(resbuf, log_size, log_piece, log_start, log_piece_size); + total_bytes += log_piece_size; + log_start += log_piece_size; + log_start = log_start % log_size; } - printf("\n"); - // just some simple sanity checking to make sure what - // we are fetching looks valid - int null_bytes_left = 20; - if (resbuf[log_end] != 0) { - debug_printf(2, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n", - log_end, log_end, resbuf[log_end]); - for (i=0; i= '0') && (o <= '7')) + return atoh(o); + return -1; +} + +static int octal_esc_to_chr(char *input) +{ + int i=0; + int ret = 0; + int len = strlen(input); + + //intf("%s('%s')\n", __func__, input); + if (input[0] != '\\') + return -1; + if (len < 4) + return -1; + + for (i=1; i < len ; i++) { + if (i > 3) + break; + int tmp = atoo(input[i]); + //intf("tmp: %d\n", tmp); + if (tmp < 0) + return tmp; + ret <<= 3; + ret += tmp; + } + return ret; +} + +static char *replace_escapes(char *str) +{ + int i; + int output = 0; + debug_printf(4, "%s(%s)\n", __func__, str); + for (i=0; i < strlen(str); i++) { + int esc = octal_esc_to_chr(&str[i]); + if (esc >= 0) { + str[output++] = esc; + i += 3; + continue; + } + str[output++] = str[i]; + } + str[output] = '\0'; + debug_printf(4, "replaced escapes in: '%s' bytes of output: %d\n", str, output); + return str; +} + +int fd_dont_cache(int fd) +{ + return fcntl(fd, F_SETFL, O_DIRECT); +} + + +#define LINEBUFSZ 1024 +char *locate_eyefi_mount(void) +{ + static char eyefi_mount[PATHNAME_MAX]; // PATH_MAX anyone? + char line[LINEBUFSZ]; + FILE *mounts = fopen("/proc/mounts", "r"); + + char dev[LINEBUFSZ]; + char mnt[LINEBUFSZ]; + char fs[LINEBUFSZ]; + char opt[LINEBUFSZ]; + int foo; + int bar; + + if (strlen(eyefi_mount)) + return &eyefi_mount[0]; + + while (fgets(&line[0], 1023, mounts)) { + int read; + read = sscanf(&line[0], "%s %s %s %s %d %d", + &dev[0], &mnt[0], &fs[0], &opt[0], + &foo, &bar); + // only look at fat filesystems: + if (strcmp(fs, "msdos") && strcmp(fs, "vfat")) { + debug_printf(2, "fs at '%s' is not fat, skipping...\n", mnt); + continue; + } + // Linux's /proc/mounts has spaces like this \040 + replace_escapes(&mnt[0]); + char *file = eyefi_file_on(REQM, &mnt[0]); + debug_printf(2, "looking for EyeFi file here: '%s'\n", file); + + struct stat statbuf; + int statret; + statret = stat(file, &statbuf); + free(file); + if (statret) { + debug_printf(2, "fs at: %s is not an Eye-Fi card, skipping...\n", + eyefi_mount); + continue; + } + strcpy(&eyefi_mount[0], &mnt[0]); + debug_printf(1, "located EyeFi card at: '%s'\n", eyefi_mount); + break; + } + fclose(mounts); + + if (strlen(eyefi_mount)) + return &eyefi_mount[0]; + + debug_printf(0, "unable to locate Eye-Fi card\n"); + if (eyefi_debug_level < 5) + debug_printf(0, "please run with '-d5' option and report the output\n"); + else { + debug_printf(0, "----------------------------------------------\n"); + debug_printf(0, "Debug information:\n"); + system("cat /proc/mounts >&2"); + } + exit(1); + return NULL; +} + + + diff --git a/eyefi-osx.c b/eyefi-osx.c new file mode 100644 index 0000000..c1b3b10 --- /dev/null +++ b/eyefi-osx.c @@ -0,0 +1,8 @@ + +int fd_set_no_cache(int fd) +{ + //fcntl(fd, F_SETFL, O_DIRECT); + return fcntl(fd, F_NOCACHE, 1); +} + + diff --git a/eyefi-unix.c b/eyefi-unix.c new file mode 100755 index 0000000..c4785db --- /dev/null +++ b/eyefi-unix.c @@ -0,0 +1,333 @@ +/* + * eyefi-unix.c + * + * Copyright (C) 2008 Dave Hansen + * + * This software may be redistributed and/or modified under the terms of + * the GNU General Public License ("GPL") version 2 as published by the + * Free Software Foundation. + */ + +#include "eyefi-config.h" + +void print_pascal_string(struct pascal_string *str) +{ + int i; + for (i = 0; i < str->length; i++) + printf("%c", str->value[i]); +} + +void print_mac(struct mac_address *mac) +{ + int i; + for (i=0; i < MAC_BYTES-1; i++) { + printf("%02x:", mac->mac[i]); + } + printf("%02x\n", mac->mac[i]); +} + + +void print_card_mac(void) +{ + debug_printf(2, "%s()\n", __func__); + struct mac_address *mac; + + card_info_cmd(MAC_ADDRESS); + mac = eyefi_response(); + assert(mac->length == MAC_BYTES); + printf("card mac address: "); + print_mac(mac); +} + +void print_card_firmware_info(void) +{ + struct card_firmware_info *info = fetch_card_firmware_info(); + printf("card firmware (len: %d): '", info->info.length); + print_pascal_string(&info->info); + printf("'\n"); +} + +void print_card_key(void) +{ + debug_printf(2, "%s()\n", __func__); + struct card_info_rsp_key *foo = fetch_card_key(); + printf("card key (len: %d): '", foo->key.length); + print_pascal_string(&foo->key); + printf("'\n"); +} + +void scan_print_nets(void) +{ + int i; + + debug_printf(2, "%s()\n", __func__); + struct scanned_net_list *scanned = scan_nets(); + if (scanned->nr == 0) { + printf("unable to detect any wireless networks\n"); + return; + } + printf("Scanned wireless networks:\n"); + for (i=0; i < scanned->nr; i++) { + struct scanned_net *net = &scanned->nets[i]; + printf("'%s' type(%d): %s, strength: %d\n", net->essid, + net->type, + net_type_name(net->type), + net->strength); + } +} + +void print_configured_nets(void) +{ + int ret; + int i; + struct configured_net_list *configured = fetch_configured_nets(); + + debug_printf(2, "%s()\n", __func__); + ret = issue_noarg_command('l'); + if (ret) { + printf("error issuing print networks command: %d\n", ret); + return; + } + configured = eyefi_response(); + if (configured->nr == 0) { + printf("No wireless networks configured on card\n"); + return; + } + printf("configured wireless networks:\n"); + for (i=0; i < configured->nr; i++) { + struct configured_net *net = &configured->nets[i]; + printf("'%s'\n", net->essid); + } +} + +int try_connection_to(char *essid, char *wpa_ascii) +{ + int i; + int ret = -1; + + char *type = net_type_name(WPA); + if (!wpa_ascii) + type = net_type_name(UNSECURED); + eyefi_printf("trying to connect to %s network: '%s'", type, essid); + if (wpa_ascii) + eyefi_printf(" with passphrase: '%s'", wpa_ascii); + fflush(NULL); + + // test network + network_action('t', essid, wpa_ascii); + u8 last_rsp = -1; + + char rsp = '\0'; + for (i=0; i < 200; i++) { + struct byte_response *r; + issue_noarg_command('s'); + r = eyefi_response(); + rsp = r->response; + char *state = net_test_state_name(rsp); + if (rsp == last_rsp) { + eyefi_printf("."); + fflush(NULL);; + } else { + if (rsp) + eyefi_printf("\nTesting connecion to '%s' (%d): %s", essid, rsp, state); + last_rsp = rsp; + } + + if (!strcmp("success", state)) { + ret = 0; + break; + } + if (!strcmp("not scanning", state)) + break; + if (!strcmp("unknown", state)) + break; + } + eyefi_printf("\n"); + if (!ret) { + eyefi_printf("Succeeded connecting to: '%s'\n", essid); + } else { + eyefi_printf("Unable to connect to: '%s' (final state: %d/'%s')\n", essid, + rsp, net_test_state_name(rsp)); + } + return ret; +} + +int print_log(void) +{ + int i; + char *resbuf = malloc(EYEFI_BUF_SIZE*4); + int total_bytes; + + total_bytes = get_log_into(resbuf); + if (total_bytes < 0) { + debug_printf(1, "%s() error: %d\n", __func__, total_bytes); + return total_bytes; + } + // The last byte *should* be a null, and the + // official software does not print it. + for (i = 0; i < total_bytes-1; i++) { + char c = resbuf[i]; + // the official software converts UNIX to DOS-style + // line breaks, so we'll do the same + if (c == '\n') + printf("%c", '\r'); + printf("%c", c); + } + printf("\n"); + // just some simple sanity checking to make sure what + // we are fetching looks valid + /* needs to be rethought for the new aligned logs + int null_bytes_left = 20; + if (resbuf[log_end] != 0) { + debug_printf(2, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n", + log_end, log_end, resbuf[log_end]); + for (i=0; i 0) + system("cat /proc/mounts >&2"); + if (eyefi_debug_level > 1) + perror("bad open"); + exit(1); +} + +void usage(void) +{ + printf("Usage:\n"); + printf(" eyefitest [OPTIONS]\n"); + printf(" -a ESSID add network (implies test unless --force)\n"); + printf(" -t ESSID test network\n"); + printf(" -p KEY set WPA key for add/test\n"); + printf(" -r ESSID remove network\n"); + printf(" -s scan for networks\n"); + printf(" -c list configured networks\n"); + printf(" -b reboot card\n"); + printf(" -f print information about card firmware\n"); + printf(" -d level set debugging level (default: 1)\n"); + printf(" -k print card unique key\n"); + printf(" -l dump card log\n"); + printf(" -m print card mac\n"); + exit(4); +} + +int main(int argc, char **argv) +{ + if (argc == 1) + usage(); + + debug_printf(3, "%s starting...\n", argv[0]); + + //static int passed_wep = 0; + //static int passed_wpa = 0; + static int force = 0; + static struct option long_options[] = { + //{"wep", 'x', &passed_wep, 1}, + //{"wpa", 'y', &passed_wpa, 1}, + {"force", 0, &force, 1}, + {"help", 'h', NULL, 1}, + }; + + int option_index; + char c; + char *essid = NULL; + char *passwd = NULL; + char network_action = 0; + debug_printf(3, "about to parse arguments\n"); + while ((c = getopt_long_only(argc, argv, "a:bcd:kflmp:r:st:z", + &long_options[0], &option_index)) != -1) { + debug_printf(3, "argument: '%c' %d optarg: '%s'\n", c, c, optarg); + switch (c) { + case 0: + // was a long argument + break; + case 'a': + case 't': + case 'r': + essid = optarg; + network_action = c; + break; + case 'b': + reboot_card(); + break; + case 'c': + print_configured_nets(); + break; + case 'd': + eyefi_debug_level = atoi(optarg); + fprintf(stderr, "set debug level to: %d\n", eyefi_debug_level); + break; + case 'f': + print_card_firmware_info(); + break; + case 'k': + print_card_key(); + break; + case 'l': + print_log(); + break; + case 'm': + print_card_mac(); + break; + case 'p': + passwd = optarg; + break; + case 's': + scan_print_nets(); + break; + case 'z': { + extern void testit0(void); + testit0(); + } + break; + case 'h': + default: + usage(); + break; + } + } + debug_printf(3, "after arguments essid: '%s' passwd: '%s'\n", essid, passwd); + if (network_action && essid) { + int ret = 0; + init_card(); + switch (network_action) { + case 't': + ret = try_connection_to(essid, passwd); + break; + case 'a': + if (!force) { + ret = try_connection_to(essid, passwd); + } else { + debug_printf(1, "forced: skipping network test\n"); + } + if (ret) { + printf("Error connecting to network '%s', not adding.\n", essid); + printf("use --force to override\n"); + break; + } + add_network(essid, passwd); + break; + case 'r': + remove_network(essid); + break; + } + } + return 0; +} + + -- 2.45.0