1 /* $NetBSD: eehandlers.c,v 1.19 2019/10/05 23:30:22 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <ctype.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <util.h>
43 #include <sys/inttypes.h>
44
45 #include <machine/eeprom.h>
46
47 #include "defs.h"
48
49 extern char *path_eeprom;
50 extern int eval;
51 extern int update_checksums;
52 extern int ignore_checksum;
53 extern int fix_checksum;
54 extern int cksumfail;
55 extern u_short writecount;
56
57 static char err_str[BUFSIZE];
58
59 static void badval(const struct keytabent *, char *);
60 static int doio(const struct keytabent *, u_char *, ssize_t, int);
61
62 static u_char ee_checksum(u_char *, size_t);
63 static void ee_hwupdate(const struct keytabent *, char *);
64 static void ee_num8(const struct keytabent *, char *);
65 static void ee_num16(const struct keytabent *, char *);
66 static void ee_screensize(const struct keytabent *, char *);
67 static void ee_truefalse(const struct keytabent *, char *);
68 static void ee_bootdev(const struct keytabent *, char *);
69 static void ee_kbdtype(const struct keytabent *, char *);
70 static void ee_constype(const struct keytabent *, char *);
71 static void ee_diagpath(const struct keytabent *, char *);
72 static void ee_banner(const struct keytabent *, char *);
73 static void ee_notsupp(const struct keytabent *, char *);
74
75 static const struct keytabent eekeytab[] = {
76 { "hwupdate", 0x10, ee_hwupdate },
77 { "memsize", 0x14, ee_num8 },
78 { "memtest", 0x15, ee_num8 },
79 { "scrsize", 0x16, ee_screensize },
80 { "watchdog_reboot", 0x17, ee_truefalse },
81 { "default_boot", 0x18, ee_truefalse },
82 { "bootdev", 0x19, ee_bootdev },
83 { "kbdtype", 0x1e, ee_kbdtype },
84 { "console", 0x1f, ee_constype },
85 { "keyclick", 0x21, ee_truefalse },
86 { "diagdev", 0x22, ee_bootdev },
87 { "diagpath", 0x28, ee_diagpath },
88 { "columns", 0x50, ee_num8 },
89 { "rows", 0x51, ee_num8 },
90 { "ttya_use_baud", 0x58, ee_truefalse },
91 { "ttya_baud", 0x59, ee_num16 },
92 { "ttya_no_rtsdtr", 0x5b, ee_truefalse },
93 { "ttyb_use_baud", 0x60, ee_truefalse },
94 { "ttyb_baud", 0x61, ee_num16 },
95 { "ttyb_no_rtsdtr", 0x63, ee_truefalse },
96 { "banner", 0x68, ee_banner },
97 { "secure", 0, ee_notsupp },
98 { "bad_login", 0, ee_notsupp },
99 { "password", 0, ee_notsupp },
100 { NULL, 0, ee_notsupp },
101 };
102
103 #define BARF(kt) { \
104 badval((kt), arg); \
105 ++eval; \
106 return; \
107 }
108
109 #define FAILEDREAD(kt) { \
110 warnx("%s", err_str); \
111 warnx("failed to read field `%s'", (kt)->kt_keyword); \
112 ++eval; \
113 return; \
114 }
115
116 #define FAILEDWRITE(kt) { \
117 warnx("%s", err_str); \
118 warnx("failed to update field `%s'", (kt)->kt_keyword); \
119 ++eval; \
120 return; \
121 }
122
123 void
ee_action(char * keyword,char * arg)124 ee_action(char *keyword, char *arg)
125 {
126 const struct keytabent *ktent;
127
128 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent) {
129 if (strcmp(ktent->kt_keyword, keyword) == 0) {
130 (*ktent->kt_handler)(ktent, arg);
131 return;
132 }
133 }
134
135 warnx("unknown keyword %s", keyword);
136 ++eval;
137 }
138
139 void
ee_dump(void)140 ee_dump(void)
141 {
142 const struct keytabent *ktent;
143
144 for (ktent = eekeytab; ktent->kt_keyword != NULL; ++ktent)
145 (*ktent->kt_handler)(ktent, NULL);
146 }
147
148 static void
ee_hwupdate(const struct keytabent * ktent,char * arg)149 ee_hwupdate(const struct keytabent *ktent, char *arg)
150 {
151 uint32_t hwtime;
152 time_t t;
153 char *cp, *cp2;
154
155 if (arg) {
156 if ((strcmp(arg, "now") == 0) ||
157 (strcmp(arg, "today") == 0)) {
158 if ((t = time(NULL)) == (time_t)(-1)) {
159 warnx("can't get current time");
160 ++eval;
161 return;
162 }
163 } else
164 if ((t = parsedate(arg, NULL, NULL)) == (time_t)(-1))
165 BARF(ktent);
166 hwtime = (uint32_t)t; /* XXX 32 bit time_t on hardware */
167 if (hwtime != t)
168 warnx("time overflow");
169
170 if (doio(ktent, (u_char *)&hwtime, sizeof(hwtime), IO_WRITE))
171 FAILEDWRITE(ktent);
172 } else {
173 if (doio(ktent, (u_char *)&hwtime, sizeof(hwtime), IO_READ))
174 FAILEDREAD(ktent);
175 t = (time_t)hwtime; /* XXX 32 bit time_t on hardware */
176 }
177
178 cp = ctime(&t);
179 if (cp != NULL && (cp2 = strrchr(cp, '\n')) != NULL)
180 *cp2 = '\0';
181
182 printf("%s=%" PRId64, ktent->kt_keyword, (int64_t)t);
183 if (cp != NULL)
184 printf(" (%s)", cp);
185 printf("\n");
186 }
187
188 static void
ee_num8(const struct keytabent * ktent,char * arg)189 ee_num8(const struct keytabent *ktent, char *arg)
190 {
191 u_char num8 = 0;
192 u_int num32;
193 int i;
194
195 if (arg) {
196 for (i = 0; i < (int)strlen(arg) - 1; ++i)
197 if (!isdigit((unsigned char)arg[i]))
198 BARF(ktent);
199 num32 = atoi(arg);
200 if (num32 > 0xff)
201 BARF(ktent);
202 num8 += num32;
203 if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
204 FAILEDWRITE(ktent);
205 } else
206 if (doio(ktent, &num8, sizeof(num8), IO_READ))
207 FAILEDREAD(ktent);
208
209 printf("%s=%d\n", ktent->kt_keyword, num8);
210 }
211
212 static void
ee_num16(const struct keytabent * ktent,char * arg)213 ee_num16(const struct keytabent *ktent, char *arg)
214 {
215 u_int16_t num16 = 0;
216 u_int num32;
217 int i;
218
219 if (arg) {
220 for (i = 0; i < (int)strlen(arg) - 1; ++i)
221 if (!isdigit((unsigned char)arg[i]))
222 BARF(ktent);
223 num32 = atoi(arg);
224 if (num32 > 0xffff)
225 BARF(ktent);
226 num16 += num32;
227 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
228 FAILEDWRITE(ktent);
229 } else
230 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
231 FAILEDREAD(ktent);
232
233 printf("%s=%d\n", ktent->kt_keyword, num16);
234 }
235
236 static const struct strvaltabent scrsizetab[] = {
237 { "1152x900", EE_SCR_1152X900 },
238 { "1024x1024", EE_SCR_1024X1024 },
239 { "1600x1280", EE_SCR_1600X1280 },
240 { "1440x1440", EE_SCR_1440X1440 },
241 { NULL, 0 },
242 };
243
244 static void
ee_screensize(const struct keytabent * ktent,char * arg)245 ee_screensize(const struct keytabent *ktent, char *arg)
246 {
247 const struct strvaltabent *svp;
248 u_char scsize;
249
250 if (arg) {
251 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
252 if (strcmp(svp->sv_str, arg) == 0)
253 break;
254 if (svp->sv_str == NULL)
255 BARF(ktent);
256
257 scsize = svp->sv_val;
258 if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
259 FAILEDWRITE(ktent);
260 } else {
261 if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
262 FAILEDREAD(ktent);
263
264 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
265 if (svp->sv_val == scsize)
266 break;
267 if (svp->sv_str == NULL) {
268 warnx("unknown %s value %d", ktent->kt_keyword,
269 scsize);
270 return;
271 }
272 }
273 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
274 }
275
276 static const struct strvaltabent truthtab[] = {
277 { "true", EE_TRUE },
278 { "false", EE_FALSE },
279 { NULL, 0 },
280 };
281
282 static void
ee_truefalse(const struct keytabent * ktent,char * arg)283 ee_truefalse(const struct keytabent *ktent, char *arg)
284 {
285 const struct strvaltabent *svp;
286 u_char truth;
287
288 if (arg) {
289 for (svp = truthtab; svp->sv_str != NULL; ++svp)
290 if (strcmp(svp->sv_str, arg) == 0)
291 break;
292 if (svp->sv_str == NULL)
293 BARF(ktent);
294
295 truth = svp->sv_val;
296 if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
297 FAILEDWRITE(ktent);
298 } else {
299 if (doio(ktent, &truth, sizeof(truth), IO_READ))
300 FAILEDREAD(ktent);
301
302 for (svp = truthtab; svp->sv_str != NULL; ++svp)
303 if (svp->sv_val == truth)
304 break;
305 if (svp->sv_str == NULL) {
306 warnx("unknown truth value 0x%x for %s", truth,
307 ktent->kt_keyword);
308 return;
309 }
310 }
311 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
312 }
313
314 static void
ee_bootdev(const struct keytabent * ktent,char * arg)315 ee_bootdev(const struct keytabent *ktent, char *arg)
316 {
317 u_char dev[5];
318 int i;
319 size_t arglen;
320 char *cp;
321
322 if (arg) {
323 /*
324 * The format of the string we accept is the following:
325 * cc(n,n,n)
326 * where:
327 * c -- an alphabetical character [a-z]
328 * n -- a number in hexadecimal, between 0 and ff,
329 * with no leading `0x'.
330 */
331 arglen = strlen(arg);
332 if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
333 arg[arglen - 1] != ')')
334 BARF(ktent);
335
336 /* Handle the first 2 letters. */
337 for (i = 0; i < 2; ++i) {
338 if (arg[i] < 'a' || arg[i] > 'z')
339 BARF(ktent);
340 dev[i] = (u_char)arg[i];
341 }
342
343 /* Handle the 3 `0x'-less hex values. */
344 cp = &arg[3];
345 for (i = 2; i < 5; ++i) {
346 if (*cp == '\0')
347 BARF(ktent);
348
349 if (*cp >= '0' && *cp <= '9')
350 dev[i] = *cp++ - '0';
351 else if (*cp >= 'a' && *cp <= 'f')
352 dev[i] = 10 + (*cp++ - 'a');
353 else
354 BARF(ktent);
355
356 /* Deal with a second digit. */
357 if (*cp >= '0' && *cp <= '9') {
358 dev[i] <<= 4;
359 dev[i] &= 0xf0;
360 dev[i] += *cp++ - '0';
361 } else if (*cp >= 'a' && *cp <= 'f') {
362 dev[i] <<= 4;
363 dev[i] &= 0xf0;
364 dev[i] += 10 + (*cp++ - 'a');
365 }
366
367 /* Ensure we have the correct delimiter. */
368 if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
369 ++cp;
370 continue;
371 } else
372 BARF(ktent);
373 }
374 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
375 FAILEDWRITE(ktent);
376 } else
377 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
378 FAILEDREAD(ktent);
379
380 printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
381 dev[1], dev[2], dev[3], dev[4]);
382 }
383
384 static void
ee_kbdtype(const struct keytabent * ktent,char * arg)385 ee_kbdtype(const struct keytabent *ktent, char *arg)
386 {
387 u_char kbd = 0;
388 u_int kbd2;
389 int i;
390
391 if (arg) {
392 for (i = 0; i < (int)strlen(arg) - 1; ++i)
393 if (!isdigit((unsigned char)arg[i]))
394 BARF(ktent);
395 kbd2 = atoi(arg);
396 if (kbd2 > 0xff)
397 BARF(ktent);
398 kbd += kbd2;
399 if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
400 FAILEDWRITE(ktent);
401 } else
402 if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
403 FAILEDREAD(ktent);
404
405 printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
406 }
407
408 static const struct strvaltabent constab[] = {
409 { "b&w", EE_CONS_BW },
410 { "ttya", EE_CONS_TTYA },
411 { "ttyb", EE_CONS_TTYB },
412 { "color", EE_CONS_COLOR },
413 { "p4opt", EE_CONS_P4OPT },
414 { NULL, 0 },
415 };
416
417 static void
ee_constype(const struct keytabent * ktent,char * arg)418 ee_constype(const struct keytabent *ktent, char *arg)
419 {
420 const struct strvaltabent *svp;
421 u_char cons;
422
423 if (arg) {
424 for (svp = constab; svp->sv_str != NULL; ++svp)
425 if (strcmp(svp->sv_str, arg) == 0)
426 break;
427 if (svp->sv_str == NULL)
428 BARF(ktent);
429
430 cons = svp->sv_val;
431 if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
432 FAILEDWRITE(ktent);
433 } else {
434 if (doio(ktent, &cons, sizeof(cons), IO_READ))
435 FAILEDREAD(ktent);
436
437 for (svp = constab; svp->sv_str != NULL; ++svp)
438 if (svp->sv_val == cons)
439 break;
440 if (svp->sv_str == NULL) {
441 warnx("unknown type 0x%x for %s", cons,
442 ktent->kt_keyword);
443 return;
444 }
445 }
446 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
447
448 }
449
450 static void
ee_diagpath(const struct keytabent * ktent,char * arg)451 ee_diagpath(const struct keytabent *ktent, char *arg)
452 {
453 char path[40];
454
455 memset(path, 0, sizeof(path));
456 if (arg) {
457 if (strlen(arg) > sizeof(path))
458 BARF(ktent);
459 memcpy(path, arg, sizeof path);
460 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
461 FAILEDWRITE(ktent);
462 } else
463 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
464 FAILEDREAD(ktent);
465
466 printf("%s=%s\n", ktent->kt_keyword, path);
467 }
468
469 static void
ee_banner(const struct keytabent * ktent,char * arg)470 ee_banner(const struct keytabent *ktent, char *arg)
471 {
472 char string[80];
473 u_char enable;
474 struct keytabent kt;
475
476 kt.kt_keyword = "enable_banner";
477 kt.kt_offset = EE_BANNER_ENABLE_LOC;
478 kt.kt_handler = ee_notsupp;
479
480 memset(string, '\0', sizeof(string));
481 if (arg) {
482 if (strlen(arg) > sizeof(string))
483 BARF(ktent);
484 if (*arg != '\0') {
485 enable = EE_TRUE;
486 memcpy(string, arg, sizeof string);
487 if (doio(ktent, (u_char *)string,
488 sizeof(string), IO_WRITE))
489 FAILEDWRITE(ktent);
490 } else {
491 enable = EE_FALSE;
492 if (doio(ktent, (u_char *)string,
493 sizeof(string), IO_READ))
494 FAILEDREAD(ktent);
495 }
496
497 if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
498 FAILEDWRITE(&kt);
499 } else {
500 if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
501 FAILEDREAD(ktent);
502 if (doio(&kt, &enable, sizeof(enable), IO_READ))
503 FAILEDREAD(&kt);
504 }
505 printf("%s=%s (%s)\n", ktent->kt_keyword, string,
506 enable == EE_TRUE ? "enabled" : "disabled");
507 }
508
509 /* ARGSUSED */
510 static void
ee_notsupp(const struct keytabent * ktent,char * arg)511 ee_notsupp(const struct keytabent *ktent, char *arg)
512 {
513
514 warnx("field `%s' not yet supported", ktent->kt_keyword);
515 }
516
517 static void
badval(const struct keytabent * ktent,char * arg)518 badval(const struct keytabent *ktent, char *arg)
519 {
520
521 warnx("inappropriate value `%s' for field `%s'", arg,
522 ktent->kt_keyword);
523 }
524
525 static int
doio(const struct keytabent * ktent,u_char * buf,ssize_t len,int wr)526 doio(const struct keytabent *ktent, u_char *buf, ssize_t len, int wr)
527 {
528 int fd, rval = 0;
529 u_char *buf2;
530
531 buf2 = (u_char *)calloc(1, len);
532 if (buf2 == NULL) {
533 strncpy(err_str, "memory allocation failed", sizeof err_str);
534 return (1);
535 }
536
537 fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
538 if (fd < 0) {
539 (void)snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
540 strerror(errno));
541 free(buf2);
542 return (1);
543 }
544
545 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
546 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
547 path_eeprom, strerror(errno));
548 rval = 1;
549 goto done;
550 }
551
552 if (read(fd, buf2, len) != len) {
553 (void)snprintf(err_str, sizeof err_str, "read: %s: %s",
554 path_eeprom, strerror(errno));
555 return (1);
556 }
557
558 if (wr == IO_WRITE) {
559 if (memcmp(buf, buf2, len) == 0)
560 goto done;
561
562 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
563 (void)snprintf(err_str, sizeof err_str, "lseek: %s: %s",
564 path_eeprom, strerror(errno));
565 rval = 1;
566 goto done;
567 }
568
569 ++update_checksums;
570 if (write(fd, buf, len) < 0) {
571 (void)snprintf(err_str, sizeof err_str, "write: %s: %s",
572 path_eeprom, strerror(errno));
573 rval = 1;
574 goto done;
575 }
576 } else
577 memmove(buf, buf2, len);
578
579 done:
580 free(buf2);
581 (void)close(fd);
582 return (rval);
583 }
584
585 /*
586 * Read from eeLastHwUpdate to just before eeReserved. Calculate
587 * a checksum, and deposit 3 copies of it sequentially starting at
588 * eeChecksum[0]. Increment the write count, and deposit 3 copies
589 * of it sequentially starting at eeWriteCount[0].
590 */
591 void
ee_updatechecksums(void)592 ee_updatechecksums(void)
593 {
594 struct keytabent kt;
595 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
596 u_char checksum;
597 int i;
598
599 kt.kt_keyword = "eeprom contents";
600 kt.kt_offset = EE_HWUPDATE_LOC;
601 kt.kt_handler = ee_notsupp;
602
603 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
604 cksumfail = 1;
605 FAILEDREAD(&kt);
606 }
607
608 checksum = ee_checksum(checkme, sizeof(checkme));
609
610 kt.kt_keyword = "eeprom checksum";
611 for (i = 0; i < 4; ++i) {
612 kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
613 if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
614 cksumfail = 1;
615 FAILEDWRITE(&kt);
616 }
617 }
618
619 kt.kt_keyword = "eeprom writecount";
620 for (i = 0; i < 4; ++i) {
621 kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
622 if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
623 IO_WRITE)) {
624 cksumfail = 1;
625 FAILEDWRITE(&kt);
626 }
627 }
628 }
629
630 void
ee_verifychecksums(void)631 ee_verifychecksums(void)
632 {
633 struct keytabent kt;
634 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
635 u_char checksum, ochecksum[3];
636 u_short owritecount[3];
637
638 /*
639 * Verify that the EEPROM's write counts match, and update the
640 * global copy for use later.
641 */
642 kt.kt_keyword = "eeprom writecount";
643 kt.kt_offset = EE_WC_LOC;
644 kt.kt_handler = ee_notsupp;
645
646 if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
647 cksumfail = 1;
648 FAILEDREAD(&kt);
649 }
650
651 if (owritecount[0] != owritecount[1] ||
652 owritecount[0] != owritecount[2]) {
653 warnx("eeprom writecount mismatch %s",
654 ignore_checksum ? "(ignoring)" :
655 (fix_checksum ? "(fixing)" : ""));
656
657 if (!ignore_checksum && !fix_checksum) {
658 cksumfail = 1;
659 return;
660 }
661
662 writecount = MAXIMUM(owritecount[0], owritecount[1]);
663 writecount = MAXIMUM(writecount, owritecount[2]);
664 } else
665 writecount = owritecount[0];
666
667 /*
668 * Verify that the EEPROM's checksums match and are correct.
669 */
670 kt.kt_keyword = "eeprom checksum";
671 kt.kt_offset = EE_CKSUM_LOC;
672
673 if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
674 cksumfail = 1;
675 FAILEDREAD(&kt);
676 }
677
678 if (ochecksum[0] != ochecksum[1] ||
679 ochecksum[0] != ochecksum[2]) {
680 warnx("eeprom checksum mismatch %s",
681 ignore_checksum ? "(ignoring)" :
682 (fix_checksum ? "(fixing)" : ""));
683
684 if (!ignore_checksum && !fix_checksum) {
685 cksumfail = 1;
686 return;
687 }
688 }
689
690 kt.kt_keyword = "eeprom contents";
691 kt.kt_offset = EE_HWUPDATE_LOC;
692
693 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
694 cksumfail = 1;
695 FAILEDREAD(&kt);
696 }
697
698 checksum = ee_checksum(checkme, sizeof(checkme));
699
700 if (ochecksum[0] != checksum) {
701 warnx("eeprom checksum incorrect %s",
702 ignore_checksum ? "(ignoring)" :
703 (fix_checksum ? "(fixing)" : ""));
704
705 if (!ignore_checksum && !fix_checksum) {
706 cksumfail = 1;
707 return;
708 }
709 }
710
711 if (fix_checksum)
712 ee_updatechecksums();
713 }
714
715 static u_char
ee_checksum(u_char * area,size_t len)716 ee_checksum(u_char *area, size_t len)
717 {
718 u_char sum = 0;
719
720 while (len--)
721 sum += *area++;
722
723 return (0x100 - sum);
724 }
725