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