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