From 2421aeed20d0dafc00dfe4baaf6d8581291eb010 Mon Sep 17 00:00:00 2001 From: dave Date: Mon, 10 Mar 2008 19:54:41 -0700 Subject: [PATCH] initial commit --- COPYING | 340 ++++++++++++++++++ Makefile | 10 + README | 57 +++ eyefi-config.c | 944 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1351 insertions(+) create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100755 eyefi-config.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f331d76 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +CC=gcc +CFLAGS=-g -Wall + +eyefi-config: eyefi-config.c + $(CC) $(CFLAGS) $< -o $@ + +clean: + rm eyefi-config + + diff --git a/README b/README new file mode 100644 index 0000000..f0d69a3 --- /dev/null +++ b/README @@ -0,0 +1,57 @@ +Just: + + make + +Then: + +To scan for networks: + +$ ./eyefi-config -s +Scanned wireless networks: +'MYESSID' type(2): WPA, strength: 33 +'VEXD2' type(1): WEP, strength: -1 + +Fetch the log: + +$ ./eyefi-config -l +fetching EyeFi card log part 1/4...done +fetching EyeFi card log part 2/4...done +fetching EyeFi card log part 3/4...done +fetching EyeFi card log part 4/4...done +56:48] Done scanning for new photos. Uploads not pending. +[56:48] Done scanning for all photos. Uploads not pending. +[802:37] EAPOL-Key type=2 +[802:37] WPA: RX message 1 of 4-Way Handshake from 00:11:95:aa:bb:cc (ver=2) +[802:37] WPA: Sending EAPOL-Key 2/4 +... + +Test a network (without adding to the card: + +# ./eyefitest -t ESSID -p password +trying to connect to WPA network: 'MYESSID' with passphrase: 'password' +Testing connecion to 'MYESSID' (1): locating network +Testing connecion to 'MYESSID' (2): verifying network key..... +Testing connecion to 'MYESSID' (3): waiting for DHCP.................. +Testing connecion to 'MYESSID' (4): testing connection to Eye-Fi server..... +Testing connecion to 'MYESSID' (5): success +Succeeded connecting to: 'MYESSID' + +Add a network: + +$ ./eyefi-config -a MYESSID -p password +trying to connect to WPA network: 'MYESSID' with passphrase: 'password' +Testing connecion to 'MYESSID' (1): locating network +Testing connecion to 'MYESSID' (2): verifying network key..... +Testing connecion to 'MYESSID' (3): waiting for DHCP.................. +Testing connecion to 'MYESSID' (4): testing connection to Eye-Fi server..... +Testing connecion to 'MYESSID' (5): success +Succeeded connecting to: 'MYESSID' + +List the networks configured on the card: + +$ ./eyefi-config -c +configured wireless networks: +'bcdefghijkl' +'MYESSID' + + diff --git a/eyefi-config.c b/eyefi-config.c new file mode 100755 index 0000000..825f7f9 --- /dev/null +++ b/eyefi-config.c @@ -0,0 +1,944 @@ +/* + * eyefitest.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define O_DIRECT 00040000 /* direct disk access hint */ + +#define MOUNT "/media/EYE-FI/" +#define PATH MOUNT "eyefi/" +#define REQC PATH "REQC" +#define REQM PATH "REQM" +#define RSPC PATH "RSPC" +#define RSPM PATH "RSPM" + +#define BUFSZ 16384 +#define EYEFI_BUF_SIZE 16384 +char unaligned_buf[BUFSZ*10]; +void *buf; + + +int debug_level = 1; +#define debug_printf(level, args...) do { \ + if ((level) <= debug_level) \ + fprintf(stderr, ## args); \ + } while(0) + +/* + * Do some kernel-style types to make + * definitions shorter. + */ +typedef unsigned long u32; +typedef unsigned char u8; + +static inline u32 swap_bytes(u32 src) +{ + unsigned int dest = 0; + dest |= (src & 0xff000000) >> 24; + dest |= (src & 0x00ff0000) >> 8; + dest |= (src & 0x0000ff00) << 8; + dest |= (src & 0x000000ff) << 24; + return dest; +} + +/* + * Just a few functions so that I can't easily forget about + * endinness. + */ +struct __be32 { + u32 val; +} __attribute__((packed)); +typedef struct __be32 be32; + +/* + * 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) +{ + be32 ret; + ret.val = swap_bytes(src); + return ret; +} + +void dumpbuf(const char *buffer, int bytesToWrite) +{ + int i; + static char linebuf[500]; + + for (i=0; i < bytesToWrite; i += 16) { + char *tmpbuf = &linebuf[0]; + unsigned long sum = 0; + int j; +#define lprintf(args...) do { \ + tmpbuf += sprintf(tmpbuf, ## args);\ +} while (0) + + lprintf("[%03d]: ", i); + for (j=0; j < 16; j++) { + u8 c = ((unsigned char *)buffer)[i+j]; + lprintf("%02x ", (unsigned int)c); + sum += c; + } + lprintf(" |"); + for (j=0; j < 16; j++) { + u8 c = ((unsigned char *)buffer)[i+j]; + if (c >= 'a' && c <= 'z') + lprintf("%c", c); + else if (c >= 'A' && c <= 'Z') + lprintf("%c", c); + else if (c >= '0' && c <= '9') + lprintf("%c", c); + else if (c >= 0x20 && c <= 127) + lprintf("%c", c); + else + lprintf("."); + } + lprintf("|\n"); + if (sum == 0) + continue; + printf("%s", linebuf); + //if (i > 200) + // break; + } +} + +struct card_seq_num { + u32 seq; +} __attribute__((packed)); + +void read_from(char *file); +void write_to(char *file, void *stuff, int len); +struct card_seq_num read_seq_from(char *file) +{ + struct card_seq_num *ret; + read_from(file); + ret = buf; + return *ret; +} + +/* + * For O_DIRECT writes to files, we need + * to be 512 byte aligned on Linux, I think. + * So, just align this to something big + * and be done with it. FIXME :) + */ +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); + 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); + + read_from(REQM); + read_from(REQC); + read_from(RSPM); + read_from(RSPC); +} + +void init_card() +{ + if (buf != NULL) + return; + + align_buf(); + zero_card_files(); + seq = read_seq_from(RSPC); + if (seq.seq == 0) + seq.seq = 0x1234; +} + +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", MOUNT); + fprintf(stderr, "Do you have write permissions to it?\n"); + if (debug_level > 1) + perror("bad open"); + exit(1); +} + +void read_from(char *file) +{ + u8 c; + int i; + int ret, retcntl; + int fd; + int zeros = 0; + + init_card(); + + fd = open(file, O_RDONLY); + if (fd < 0) + open_error(file); + retcntl = fcntl(fd, F_SETFL, O_DIRECT); + if (retcntl < 0) { + perror("bad fcntl"); + exit(1); + } + ret = read(fd, buf, BUFSZ); + if (debug_level > 3) + dumpbuf(buf, 128); + if (ret < 0) { + perror("bad read"); + exit(1); + } + debug_printf(3, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl); + for (i=0; i < BUFSZ; i++) { + c = ((char *)buf)[i]; + if (c == '\0') { + zeros++; + continue; + } + } + //if (zeros) + // printf(" zeros: %d", zeros); + //fsync(fd); + close(fd); +} + +void write_to(char *file, void *stuff, int len) +{ + //printf("not writing to '%s'\n", file); + //return; + int ret; + int fd; + init_card(); + if (len == -1) + len = strlen(stuff); + + if (debug_level > 3) + 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); + if (fd < 0) + open_error(file); + if (debug_level > 3) + dumpbuf(buf, 128); + ret = write(fd, buf, BUFSZ); + //fsync(fd); + close(fd); + debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len); + if (ret < 0) + exit(ret); +} + +/* + * 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; +}; + +#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) +{ + //u32 tmpseq = be32_to_u32(seq.seq); + //seq.seq = u32_to_be32(tmpseq+1); + seq.seq++; + write_struct(REQC, &seq); +} + +u32 current_seq(void) +{ + return seq.seq; +} + +void wait_for_response(void) +{ + int i; + debug_printf(3, "waiting for response...\n"); + inc_seq(); + for (i = 0; i < 50; 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(), + cardseq.seq); + if (rsp == current_seq()) + break; + usleep(300000); + } + debug_printf(3, "got good seq, reading RSPM...\n"); + read_from(RSPM); + debug_printf(3, "done reading RSPM\n"); +} +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", +}; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +char *net_test_state_name(u8 state) +{ + int size = ARRAY_SIZE(net_test_states); + if (state >= size) + return "unknown"; + return net_test_states[state]; +} + +char *net_types[] = { + "No security", + "WEP", + "WPA", + "unknown1", + "WPA2", +}; + +char *net_type_name(u8 type) +{ + int size = ARRAY_SIZE(net_types); + if (type >= size) + return "unknown"; + 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)); + +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(0, "non-hex character: '%c'/'%c'\n", c, lc); + return 0; +} + +/* + * Take a string like "0ab1" and make it + * a series of bytes: { 0x0a, 0xb1 } + * + * Destroys the original string. + */ +char *convert_ascii_to_hex(char *ascii, int len) +{ + int i; + if (len%2) { + fprintf(stderr, "%s() must be even number of bytes: %d\n", + __func__, len); + exit(2); + } + for (i=0; i < len; i+=2) { + u8 high = atoh(ascii[i]); + u8 low = atoh(ascii[i+1]); + u8 byte = (high<<4 | low); + debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte); + ascii[i/2] = byte; + } + for (i=len/2; i < len; i++) + ascii[i] = '\0'; + return &ascii[0]; +} + +#define PASSPHRASE_PROG "wpa_passphrase" + +struct wpa_key *make_wpa_key(char *essid, char *pass) +{ + char program[] = PASSPHRASE_PROG; + // 7 for 2 spaces, 4 quotes and a \0 + char redirect[] = " 2> /dev/null"; + char *cmdbuf = malloc(strlen(essid) + strlen(pass) + strlen(program) + 7 + + strlen(redirect)); + + if (!cmdbuf) + return NULL; + + sprintf(cmdbuf, "%s '%s' '%s' %s", program, essid, pass, redirect); + FILE *pipe = popen(cmdbuf, "r"); + if (!pipe) { + perror("\nunable to execute " PASSPHRASE_PROG); + return NULL; + } + + int key_chars = WPA_KEY_BYTES*2; + char hex_key_in_ascii[key_chars+1]; + char line[1024]; + int read = 0; + while (fgets(&line[0], 1023, pipe)) { + debug_printf(4, "read from %s: '%s'\n", PASSPHRASE_PROG, line); + read = sscanf(&line[0], " psk=%64s", &hex_key_in_ascii[0]); + if (read == 0) + continue; + break; + } + int exit_code = pclose(pipe); + if (!read || exit_code) { + fprintf(stderr, "\nunable to read wpa key from %s\n", PASSPHRASE_PROG); + fprintf(stderr, "Is wpa_supplicant installed?\n"); + exit(4); + } + debug_printf(4, "ascii key: '%s'\n", hex_key_in_ascii); + char *hex_key = convert_ascii_to_hex(hex_key_in_ascii, key_chars); + struct wpa_key *key = malloc(sizeof(*key)); + memcpy(&key->key[0], hex_key, WPA_KEY_BYTES); + free(cmdbuf); + return key; +} + +void card_info_cmd(enum card_info_subcommand cmd) +{ + struct card_info_req cir; + cir.o = 'o'; + cir.subcommand = cmd; + + write_struct(REQM, &cir); + wait_for_response(); +} + +u32 fetch_log_length(void) +{ + card_info_cmd(LOG_LEN); + struct card_info_log_len *loglen = 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) +{ + 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); +} + +void print_card_key(void) +{ + 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"); +} + +struct noarg_request { + u8 req; +}; + +void issue_noarg_command(u8 cmd) +{ + struct noarg_request req; + req.req = cmd; + write_struct(REQM, &req); + wait_for_response(); +} + +void scan_print_nets(void) +{ + int i; + + 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); + } +} + +void print_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); + } +} + +void reboot_card(void) +{ + debug_printf(2, "%s()\n", __func__); + issue_noarg_command('b'); +} + +void copy_wep_key(struct wep_key *dst, struct wep_key *src) +{ + memcpy(&dst->key, &src->key, sizeof(*dst)); +} + +void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src) +{ + memcpy(&dst->key, &src->key, sizeof(*dst)); +} + +void network_action(char cmd, char *essid, char *wpa_ascii) +{ + struct net_request nr; + memset(&nr, 0, sizeof(nr)); + + nr.req = cmd; + strcpy(&nr.essid[0], essid); + nr.essid_len = strlen(essid); + struct wpa_key *wpakey; + if (wpa_ascii) { + wpakey = make_wpa_key(essid, wpa_ascii); + nr.key.len = sizeof(*wpakey); + copy_wpa_key(&nr.key.wpa, wpakey); + } + write_struct(REQM, &nr); + wait_for_response(); +} + +void add_network(char *essid, char *wpa_ascii) +{ + debug_printf(2, "%s()\n", __func__); + network_action('a', essid, wpa_ascii); +} + +void remove_network(char *essid) +{ + debug_printf(2, "%s()\n", __func__); + network_action('d', essid, NULL); +} + +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); + 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) +{ + 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); + wait_for_response(); + return buf; +} + +int get_log(void) +{ + int total_bytes = 0; + int i; + u32 log_start; + u32 log_end; + u32 log_size = fetch_log_length(); + char *resbuf = malloc(log_size); + + int nr_bufs_per_log = log_size/EYEFI_BUF_SIZE; + for (i = 0; i < log_size/EYEFI_BUF_SIZE; i++) { + debug_printf(1, "fetching EyeFi card log part %d/%d...", + i+1, nr_bufs_per_log); + fflush(NULL); + get_log_at_offset(EYEFI_BUF_SIZE*i); + debug_printf(1, "done\n"); + u32 log_size; + u8 *log_data; + 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); + 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); + } else { + struct rest_log_response *log = buf; + log_data = &log->data[0]; + log_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); + } + 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) { + fprintf(stderr, "error: unexpected last byte (%ld/0x%lx) of log: %02x\n", + log_end, log_end, resbuf[log_end]); + for (i=0; i