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