]> CyberLeo.Net >> Repos - SourceForge/eyefi-config.git/blob - eyefi-config.c
Add support for other operating systems:
[SourceForge/eyefi-config.git] / eyefi-config.c
1 /*
2  * eyefi-config.c
3  *
4  * Copyright (C) 2008 Dave Hansen <dave@sr71.net>
5  *
6  * This software may be redistributed and/or modified under the terms of
7  * the GNU General Public License ("GPL") version 2 as published by the
8  * Free Software Foundation.
9  */
10
11 #include "eyefi-config.h"
12
13 int eyefi_debug_level = 0;
14
15 int eyefi_printf(const char *fmt, ...)
16 {
17         va_list args;
18         int r;
19
20         va_start(args, fmt);
21         r = printf(fmt, args);
22         va_end(args);
23
24         return r;
25 }
26  
27 static char *eyefi_file_name(enum eyefi_file file)
28 {
29         switch (file) {
30         case REQC: return "reqc";
31         case REQM: return "reqm";
32         case RSPC: return "rspc";
33         case RSPM: return "rspm";
34         }
35
36         return NULL;
37 }
38
39 char *eyefi_file_on(enum eyefi_file file, char *mnt)
40 {
41         char *filename = eyefi_file_name(file);
42         char *full = malloc(PATHNAME_MAX);
43
44         sprintf(&full[0], "%s/EyeFi/%s", mnt, filename);
45         debug_printf(4, "eyefile nr: %d on '%s' is: '%s'\n", file, mnt, &full[0]);
46         return full;
47 }
48
49 /*
50  * This lets us get away with a static allocation
51  * for the buffer.  We make it size*2 so that we're
52  * guaranteed to be able to get a "size" buffer
53  * aligned inside of the larger one.
54  */
55 static char unaligned_buf[EYEFI_BUF_SIZE*2];
56 static void *eyefi_buf;
57
58 void *eyefi_response(void)
59 {
60         return eyefi_buf;
61 }
62
63 void dumpbuf(const char *buffer, int bytesToWrite)
64 {
65     int i;
66     static char linebuf[500];
67
68     for (i=0; i < bytesToWrite; i += 16) {
69         char *tmpbuf = &linebuf[0];
70         unsigned long sum = 0;
71         int j;
72 #define lprintf(args...)        do {            \
73         tmpbuf += sprintf(tmpbuf, ## args);\
74 } while (0)
75
76         lprintf("[%03d]: ", i);
77         for (j=0; j < 16; j++) {
78                 u8 c = ((unsigned char *)buffer)[i+j];
79                 lprintf("%02x ", (unsigned int)c);
80                 sum += c;
81         }
82         lprintf(" |");
83         for (j=0; j < 16; j++) {
84                 u8 c = ((unsigned char *)buffer)[i+j];
85                 if (c >= 'a' && c <= 'z')
86                         lprintf("%c", c);
87                 else if (c >= 'A' && c <= 'Z')
88                         lprintf("%c", c);
89                 else if (c >= '0' && c <= '9')
90                         lprintf("%c", c);
91                 else if (c >= 0x20 && c <= 127)
92                         lprintf("%c", c);
93                 else
94                         lprintf(".");
95         }
96         lprintf("|\n");
97         if (sum == 0)
98                 continue;
99         printf("%s", linebuf);
100         //if (i > 200)
101         //      break;
102     }
103 }
104
105 void read_from(enum eyefi_file);
106 void write_to(enum eyefi_file, void *, int);
107
108 struct card_seq_num eyefi_seq;
109 struct card_seq_num read_seq_from(enum eyefi_file file)
110 {
111         struct card_seq_num *ret;
112         read_from(file);
113         ret = eyefi_buf;
114         return *ret;
115 }
116
117 /*
118  * For O_DIRECT writes to files, we need
119  * to be 512 byte aligned on Linux, I think.
120  * So, just align this to something big
121  * and be done with it.  FIXME :)
122  *
123  * This probably isn't necessary on chdk,
124  * since I don't think it buffers I/O at
125  * all.
126  */
127 void align_buf(void)
128 {
129         unsigned long addr = (unsigned long)&unaligned_buf[EYEFI_BUF_SIZE];
130         addr &= ~(EYEFI_BUF_SIZE-1);
131         eyefi_buf = (void *)addr;
132         debug_printf(4, "buf: %p\n", eyefi_buf);
133         debug_printf(4, "unaligned: %p\n", &unaligned_buf[0]);
134 }
135
136 /*
137  * The real manager does this so we might
138  * as well, too.
139  */
140 void zero_card_files(void)
141 {
142         //write_to(REQM, eyefi_buf, EYEFI_BUF_SIZE);
143         write_to(REQC, eyefi_buf, EYEFI_BUF_SIZE);
144         write_to(RSPM, eyefi_buf, EYEFI_BUF_SIZE);
145         write_to(RSPC, eyefi_buf, EYEFI_BUF_SIZE);
146
147         read_from(REQM);
148         read_from(REQC);
149         read_from(RSPM);
150         read_from(RSPC);
151 }
152
153 void init_card()
154 {
155         char *mnt;
156         if (eyefi_buf != NULL)
157                 return;
158
159         debug_printf(2, "Initializing card...\n");
160         mnt = locate_eyefi_mount();
161         if (mnt == NULL)
162                 return;
163
164         align_buf();
165         zero_card_files();
166         eyefi_seq = read_seq_from(RSPC);
167         if (eyefi_seq.seq == 0)
168                 eyefi_seq.seq = 0x1234;
169         eyefi_seq.seq++;
170         debug_printf(2, "Done initializing card...\n");
171         debug_printf(2, "seq was: %04lx\n", eyefi_seq.seq);
172 }
173
174 static char *eyefi_file(enum eyefi_file file)
175 {
176         init_card();
177         return eyefi_file_on(file, locate_eyefi_mount());
178 }
179
180 void read_from(enum eyefi_file __file)
181 {
182         int ret, retcntl;
183         int fd;
184         char *file = eyefi_file(__file);
185         
186         init_card();
187
188 retry:
189         fd = open(file, O_RDONLY);
190         if (fd < 0) 
191                 open_error(file, fd);
192         retcntl = fd_dont_cache(fd);
193         if (retcntl < 0) {
194                 perror("bad fcntl");
195                 exit(1);
196         }
197         ret = read(fd, eyefi_buf, EYEFI_BUF_SIZE);
198         if (eyefi_debug_level > 3)
199                 dumpbuf(eyefi_buf, 128);
200         if (ret < 0) {
201                 close(fd);
202                 perror("bad read, retrying...");
203                 goto retry;
204                 exit(1);
205         }
206         debug_printf(4, "read '%s': bytes: %d fcntl: %d\n", file, ret, retcntl);
207         /*
208          * There was a time when I was carefully recording how each response
209          * looked, and I counted the zeros in each response.  I don't care
210          * any more.
211         u8 c;
212         int zeros = 0;
213         int i;
214         for (i=0; i < EYEFI_BUF_SIZE; i++) {
215                 c = ((char *)eyefi_buf)[i];
216                 if (c == '\0') {
217                         zeros++;
218                         continue;
219                 }
220         }
221         */
222         free(file);
223         close(fd);
224 }
225
226 int fake_write = 0;
227 void write_to(enum eyefi_file __file, void *stuff, int len)
228 {
229         int ret;
230         int fd;
231         char *file;
232
233         if (fake_write)
234                 return;
235
236         init_card();
237         file = eyefi_file(__file);
238         if (len == -1)
239                 len = strlen(stuff);
240
241         if (eyefi_debug_level > 3) {
242                 debug_printf(3, "%s('%s', ..., %d)\n", __func__, file, len);
243                 dumpbuf(stuff, len);
244         }
245         memset(eyefi_buf, 0, EYEFI_BUF_SIZE);
246         memcpy(eyefi_buf, stuff, len);
247         fd = open(file, O_RDWR|O_CREAT, 0600);
248         if (fd < 0)
249                 open_error(file, fd);
250         ret = fd_dont_cache(fd);
251         if (ret < 0)
252                 open_error(file, ret);
253         if (eyefi_debug_level > 3)
254                 dumpbuf(eyefi_buf, 128);
255         ret = write(fd, eyefi_buf, EYEFI_BUF_SIZE);
256         close(fd);
257         debug_printf(3, "wrote %d bytes to '%s' (string was %d bytes)\n", ret, file, len);
258         if (ret < 0) {
259                 fprintf(stderr, "error writing to '%s': ", file);
260                 perror("");
261                 exit(ret);
262         }
263         free(file);
264 }       
265
266 #define write_struct(file, s) write_to((file), s, sizeof(*(s)))
267
268 void inc_seq(void)
269 {
270         /*
271          * Oddly enough, the sequence number appears
272          * to be of normal endianness.
273          */
274         //u32 tmpseq = be32_to_u32(seq.seq);
275         //seq.seq = u32_to_be32(tmpseq+1);
276         eyefi_seq.seq++;
277         write_struct(REQC, &eyefi_seq);
278 }
279
280 u32 eyefi_current_seq(void)
281 {
282         return eyefi_seq.seq;
283 }
284
285 int wait_for_response(void)
286 {
287         int good_rsp = 0;
288         u32 rsp;
289         int i;
290         debug_printf(3, "waiting for response...\n");
291         inc_seq();
292         for (i = 0; i < 10; i++) {
293                 struct card_seq_num cardseq = read_seq_from(RSPC);
294                 debug_printf(3, "read rsp code: %lx, looking for: %lx raw: %lx\n", rsp, eyefi_current_seq(),
295                                 cardseq.seq);
296                 rsp = cardseq.seq;
297                 if (rsp == eyefi_current_seq()) {
298                         good_rsp = 1;
299                         break;
300                 }
301                 if (eyefi_debug_level > 4) {
302                         read_from(REQM);
303                         debug_printf(1, "command issued was: '%c'\n", ((char *)eyefi_buf)[0]);
304                 }
305                 usleep(300000);
306         }
307         if (!good_rsp) {
308                 debug_printf(1, "never saw card seq response\n");
309                 return -1;
310         }
311         debug_printf(3, "got good seq (%ld), reading RSPM...\n", rsp);
312         read_from(RSPM);
313         debug_printf(3, "done reading RSPM\n");
314         return 0;
315 }
316
317 char *net_test_states[] = {
318        "not scanning",
319        "locating network",
320        "verifying network key",
321        "waiting for DHCP",
322        "testing connection to Eye-Fi server",
323        "success",
324 };
325
326 char *net_test_state_name(u8 state)
327 {
328         int size = ARRAY_SIZE(net_test_states);
329         if (state >= size)
330                 return "unknown";
331         return net_test_states[state];
332 }
333
334 char *net_types[] = {
335         "No security",
336         "WEP",
337         "WPA",
338         "unknown1",
339         "WPA2",
340 };
341
342 char *net_type_name(u8 type)
343 {
344         int size = ARRAY_SIZE(net_types);
345         if (type >= size)
346                 return "unknown";
347         return net_types[type];
348 }
349
350 static char lower(char c)
351 {
352         if ((c >= 'A') && (c <= 'Z'))
353                 c += ('a' - 'A');
354         return c;
355 }
356
357 int atoh(char c)
358 {
359         char lc = lower(c);
360         if ((c >= '0') && (c <= '9'))
361                 return c - '0';
362         else if ((c >= 'a') && (c <= 'z'))
363                 return (c - 'a') + 10;
364         debug_printf(5, "non-hex character: '%c'/'%c'\n", c, lc);
365         return -1;
366 }
367
368 /*
369  * Take a string like "0ab1" and make it
370  * a series of bytes: { 0x0a, 0xb1 }
371  *
372  * @len is the strlen() of the ascii
373  *
374  * Destroys the original string.
375  */
376 char *convert_ascii_to_hex(char *ascii, int len)
377 {
378         int i;
379         if (len%2) {
380                 fprintf(stderr, "%s() must be even number of bytes: %d\n",
381                 __func__, len);
382                 exit(2);
383         }
384         for (i=0; i < len; i+=2) {
385                 int high = atoh(ascii[i]);
386                 int low  = atoh(ascii[i+1]);
387                 u8 byte = (high<<4 | low);
388                 if (high < 0 || low < 0)
389                         return NULL;
390                 debug_printf(6, "high: %02x low: %02x, both: %02x\n", high, low, byte);
391                 ascii[i/2] = byte;
392         }
393         for (i=len/2; i < len; i++)
394                 ascii[i] = '\0';
395         return &ascii[0];
396 }
397
398 struct wpa_key *make_wpa_key(char *essid, char *pass)
399 {
400         struct wpa_key *key = malloc(sizeof(*key));
401
402         if (strlen(pass) == WPA_KEY_BYTES*2) {
403                 char *hex_pass;
404                 debug_printf(2, "Interpreting password as hex WPA key\n");
405                 hex_pass = convert_ascii_to_hex(pass, WPA_KEY_BYTES*2);
406                 if (!hex_pass)
407                         return NULL;
408                 memcpy(&key->key[0], pass, WPA_KEY_BYTES);
409         } else {
410                 debug_printf(2, "Interpreting password as ASCII WPA key\n");
411                 pbkdf2_sha1(pass, essid, strlen(essid), 4096,
412                             &key->key[0], WPA_KEY_BYTES);
413         }
414         return key;
415 }
416
417 int card_info_cmd(enum card_info_subcommand cmd)
418 {
419         struct card_info_req cir;
420         cir.o = 'o';
421         cir.subcommand = cmd;
422
423         write_struct(REQM, &cir);
424         return wait_for_response();
425 }
426
427 u32 fetch_log_length(void)
428 {
429         debug_printf(3, "%s()\n", __func__);
430         card_info_cmd(LOG_LEN);
431         struct card_info_log_len *loglen = eyefi_buf;
432         return be32_to_u32(loglen->val);
433 }
434
435 struct card_firmware_info *fetch_card_firmware_info(void)
436 {
437         debug_printf(2, "%s()\n", __func__);
438         card_info_cmd(FIRMWARE_INFO);
439         return (struct card_firmware_info *)eyefi_buf;
440         return NULL;
441 }
442
443 struct testbuf {
444         char cmd;
445         u8 l1;
446         char name[100];
447 };
448
449 struct z {
450         char zeros[100];
451 } z;
452
453 void testit0(void)
454 {
455         char c;
456         struct testbuf tb;
457         int i;
458
459         strcpy(tb.name, "www.sr71.net/");
460         tb.l1 = strlen(tb.name);
461         for (i = 0; i < 10; i++) {
462                 tb.cmd = 'O';
463                 tb.l1 = i;
464                 write_struct(RSPM, &z);
465                 write_struct(REQM, &tb);
466                 wait_for_response();
467                 printf("buffer after O %d:\n", i);
468                 dumpbuf(eyefi_buf, 64);
469                 printf("----------------\n");
470                 write_struct(REQM, &tb);
471                 card_info_cmd(i);
472                 printf("card info(%d):\n", i);
473                 dumpbuf(eyefi_buf, 64);
474                 printf("-----------\n");
475         }
476         return;
477
478         strcpy(tb.name, "/public/eyefi/servname");
479         strcpy(tb.name, "/config/networks.xml");
480         //tb.len = strlen(tb.name);
481         tb.l1 = 0;
482         for (c = 'O'; c <= 'O'; c++) {
483                 tb.cmd = c;
484                 write_struct(REQM, &tb);
485                 wait_for_response();
486                 printf("dumping buffer:\n");
487                 dumpbuf(eyefi_buf, 64);
488                 printf("buffer dump done\n");
489         }
490 }
491
492 struct card_info_rsp_key *fetch_card_key(void)
493 {
494         struct card_info_rsp_key *key;
495
496         debug_printf(2, "%s()\n", __func__);
497         card_info_cmd(CARD_KEY);
498         key = eyefi_buf;
499         return key;
500 }
501
502 int issue_noarg_command(u8 cmd)
503 {
504         struct noarg_request req;
505         printf("%s() cmd: %d\n", __func__, cmd);
506         req.req = cmd;
507         write_struct(REQM, &req);
508         return wait_for_response();
509 }
510
511 struct scanned_net_list *scan_nets(void)
512 {
513         struct scanned_net_list *scanned;
514
515         debug_printf(2, "%s()\n", __func__);
516         issue_noarg_command('g');
517         scanned = eyefi_response();
518         return scanned;
519 }
520
521 struct configured_net_list *fetch_configured_nets(void)
522 {
523         struct configured_net_list *configured;
524
525         debug_printf(2, "%s()\n", __func__);
526         issue_noarg_command('l');
527         configured = eyefi_buf;
528         return configured;
529 }
530
531 void reboot_card(void)
532 {
533         debug_printf(2, "%s()\n", __func__);
534         issue_noarg_command('b');
535 }
536
537 void copy_wep_key(struct wep_key *dst, struct wep_key *src)
538 {
539         memcpy(&dst->key, &src->key, sizeof(*dst));
540 }
541
542 void copy_wpa_key(struct wpa_key *dst, struct wpa_key *src)
543 {
544         memcpy(&dst->key, &src->key, sizeof(*dst));
545 }
546
547 int network_action(char cmd, char *essid, char *wpa_ascii)
548 {
549         struct net_request nr;
550         memset(&nr, 0, sizeof(nr));
551
552         nr.req = cmd;
553         strcpy(&nr.essid[0], essid);
554         nr.essid_len = strlen(essid);
555         struct wpa_key *wpakey;
556         if (wpa_ascii) {
557                 wpakey = make_wpa_key(essid, wpa_ascii);
558                 nr.key.len = sizeof(*wpakey);
559                 copy_wpa_key(&nr.key.wpa, wpakey);
560         }
561         write_struct(REQM, &nr);
562         return wait_for_response();
563 }
564
565 void add_network(char *essid, char *wpa_ascii)
566 {
567         debug_printf(2, "%s()\n", __func__);
568         network_action('a', essid, wpa_ascii);
569 }
570
571 void remove_network(char *essid)
572 {
573         debug_printf(2, "%s()\n", __func__);
574         network_action('d', essid, NULL);
575 }
576
577 int get_log_at_offset(u32 offset)
578 {
579         struct fetch_log_cmd cmd;
580         cmd.m = 'm';
581         cmd.offset = u32_to_be32(offset);
582
583         debug_printf(2, "getting log at offset: %08lx\n", offset);
584         write_struct(REQM, &cmd);
585         return wait_for_response();
586 }
587
588 void add_log_piece(u8 *log, int log_len, u8 *piece, int piece_pos, int piece_size)
589 {
590         debug_printf(0, "%s(%p, %d, %p, %d, %d)\n", __func__, log, log_len, piece, piece_pos, piece_size);
591         if (piece_pos + piece_size > log_len) {
592                 int overflow_by = (piece_pos + piece_size) - log_len;
593                 int piece_overrun_pos = piece_size - overflow_by;
594                 piece_size -= overflow_by;
595                 memcpy(&log[0], &piece[piece_overrun_pos], overflow_by);
596                 debug_printf(0, "writing %d bytes to logbuf[0] from piece[%d]\n",
597                                 overflow_by, piece_overrun_pos);
598         }
599         debug_printf(0, "writing %d bytes to logbuf[%d]\n", piece_size, piece_pos);
600         memcpy(&log[piece_pos], piece, piece_size);
601 }
602
603 int get_log_into(u8 *resbuf)
604 {
605         int total_bytes = 0;
606         int ret;
607         int i;
608         u32 log_start;
609         u32 log_end;
610         u32 __log_size = fetch_log_length();
611         int log_pieces = __log_size/EYEFI_BUF_SIZE;
612
613         if (__log_size <= 0)
614                 return __log_size;
615
616         /* There are 8 bytes of header in the first log entry
617          * to specify where the log starts and ends */
618         u32 log_size = __log_size - 8;
619
620         for (i = 0; i < log_pieces; i++) {
621                 debug_printf(1, "fetching EyeFi card log part %d/%d...",
622                                 i+1, log_pieces);
623                 fflush(NULL);
624                 ret = get_log_at_offset(EYEFI_BUF_SIZE*i);
625                 debug_printf(1, "done\n");
626                 u8 *log_piece;
627                 u32 log_piece_size;
628                 if (i == 0) {
629                         struct first_log_response *log = eyefi_buf;
630                         log_end = log_size - be32_to_u32(log->log_end);
631                         log_start = log_size - be32_to_u32(log->log_start);
632                         debug_printf(2, "log end:   0x%04lx\n", log_end);
633                         debug_printf(2, "log start: 0x%04lx\n", log_start);
634                         log_piece = &log->data[0];
635                         log_piece_size = ARRAY_SIZE(log->data);
636                 } else {
637                         struct rest_log_response *log = eyefi_buf;
638                         log_piece = &log->data[0];
639                         log_piece_size = ARRAY_SIZE(log->data);
640                 }
641                 add_log_piece(resbuf, log_size, log_piece, log_start, log_piece_size);
642                 total_bytes += log_piece_size;
643                 log_start += log_piece_size;
644                 log_start = log_start % log_size;
645         }
646         return total_bytes;
647 }
648