1/*	$NetBSD$	*/
2
3/*
4 * Calculate 32bit checksum of IPL and store in a certain location
5 *
6 * Written in 2003 by ITOH Yasufumi.
7 * Public domain
8 */
9
10#include <sys/types.h>
11#include <stdio.h>
12#include <string.h>
13#include <netinet/in.h>
14
15#ifndef __BIT_TYPES_DEFINED__
16typedef unsigned int	uint32_t;
17#endif
18
19/* see README.ipl */
20#define IPLOFF		(4*1024)	/* 4KB */
21#define IPL1SIZE	(4*1024)	/* 4KB */
22#define IPL2SIZE	(1*1024)	/* 1KB */
23#define IPL2ONDISK	0x0400
24#define IPL3SIZE	(3*512)		/* 1.5KB */
25#define IPL3ONDISK	0x0A00
26#define IPLSIZE		(IPL1SIZE + IPL2SIZE + IPL3SIZE)
27#define BOOTSIZE	(IPLOFF + IPLSIZE)
28#define BOOTBLOCKSIZE	8192
29
30uint32_t bootblk[BOOTSIZE / sizeof(uint32_t) + 1];
31
32#define SUMOFF		((IPLOFF + 4) / sizeof(uint32_t))
33
34#ifdef __STDC__
35int main(int, char *[]);
36#endif
37
38int
39main(int argc, char *argv[])
40{
41	FILE *fp;
42	int len;
43	uint32_t sum, *p;
44	int iploff, iplsumsize;
45
46	if (argc != 3) {
47		fprintf(stderr, "usage: %s <input> <output>\n", argv[0]);
48		return 1;
49	}
50
51	/* read file */
52	if ((fp = fopen(argv[1], "rb")) == NULL) {
53		perror(argv[1]);
54		return 1;
55	}
56	if ((len = fread(bootblk, 1, sizeof bootblk, fp)) <= IPLOFF) {
57		fprintf(stderr, "%s: too short\n", argv[1]);
58		return 1;
59	} else if (len > BOOTSIZE) {
60		fprintf(stderr, "%s: too long\n", argv[1]);
61		return 1;
62	}
63	(void) fclose(fp);
64
65	/* sanity check */
66	if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
67		fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
68		return 1;
69	}
70	iploff = ntohl(bootblk[0xf0 / sizeof(uint32_t)]);
71	iplsumsize = ntohl(bootblk[0xf4 / sizeof(uint32_t)]);
72	printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
73	    BOOTSIZE - len, iploff, iplsumsize);
74	if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
75	    iploff + iplsumsize > BOOTBLOCKSIZE) {
76		fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
77		return 1;
78	}
79
80	/* checksum */
81	sum = 0;
82	for (p = bootblk + IPLOFF / sizeof(uint32_t);
83	    p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t); p++)
84		sum += ntohl(*p);
85
86	bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);
87
88	/* transfer ipl part 2 */
89	memcpy(bootblk + IPL2ONDISK / sizeof(uint32_t),
90	    bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t),
91	    IPL2SIZE);
92
93	/* transfer ipl part 3 */
94	memcpy(bootblk + IPL3ONDISK / sizeof(uint32_t),
95	    bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(uint32_t),
96	    IPL3SIZE);
97
98	/* write file */
99	if ((fp = fopen(argv[2], "wb")) == NULL) {
100		perror(argv[2]);
101		return 1;
102	}
103	if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) {
104		if (len < 0)
105			perror(argv[2]);
106		else
107			fprintf(stderr, "%s: short write\n", argv[2]);
108		fclose(fp);
109		(void) remove(argv[2]);
110		return 1;
111	}
112	if (fclose(fp)) {
113		perror(argv[2]);
114		(void) remove(argv[2]);
115		return 1;
116	}
117
118	return 0;
119}
120