1 /* $NetBSD: iplsum.c,v 1.2 2015/12/13 18:38:23 christos Exp $ */
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__
16 typedef 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
30 uint32_t bootblk[BOOTSIZE / sizeof(uint32_t) + 1];
31
32 #define SUMOFF ((IPLOFF + 4) / sizeof(uint32_t))
33
34 #ifdef __STDC__
35 int main(int, char *[]);
36 #endif
37
38 int
main(int argc,char * argv[])39 main(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 fclose(fp);
58 fprintf(stderr, "%s: too short\n", argv[1]);
59 return 1;
60 } else if (len > BOOTSIZE) {
61 fclose(fp);
62 fprintf(stderr, "%s: too long (%d vs %d)\n", argv[1], len, BOOTSIZE);
63 return 1;
64 }
65 (void) fclose(fp);
66
67 /* sanity check */
68 if ((ntohl(bootblk[0]) & 0xffff0000) != 0x80000000) {
69 fprintf(stderr, "%s: bad LIF magic\n", argv[1]);
70 return 1;
71 }
72 iploff = ntohl(bootblk[0xf0 / sizeof(uint32_t)]);
73 iplsumsize = ntohl(bootblk[0xf4 / sizeof(uint32_t)]);
74 printf("%d bytes free, ipl offset = %d, ipl sum size = %d\n",
75 BOOTSIZE - len, iploff, iplsumsize);
76 if (iploff != IPLOFF || iplsumsize <= 0 || iplsumsize % 2048 ||
77 iploff + iplsumsize > BOOTBLOCKSIZE) {
78 fprintf(stderr, "%s: bad ipl offset / size\n", argv[1]);
79 return 1;
80 }
81
82 /* checksum */
83 sum = 0;
84 for (p = bootblk + IPLOFF / sizeof(uint32_t);
85 p < bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t); p++)
86 sum += ntohl(*p);
87
88 bootblk[SUMOFF] = htonl(ntohl(bootblk[SUMOFF]) - sum);
89
90 /* transfer ipl part 2 */
91 memcpy(bootblk + IPL2ONDISK / sizeof(uint32_t),
92 bootblk + (IPLOFF + IPL1SIZE) / sizeof(uint32_t),
93 IPL2SIZE);
94
95 /* transfer ipl part 3 */
96 memcpy(bootblk + IPL3ONDISK / sizeof(uint32_t),
97 bootblk + (IPLOFF + IPL1SIZE + IPL2SIZE) / sizeof(uint32_t),
98 IPL3SIZE);
99
100 /* write file */
101 if ((fp = fopen(argv[2], "wb")) == NULL) {
102 perror(argv[2]);
103 return 1;
104 }
105 if ((len = fwrite(bootblk, 1, BOOTBLOCKSIZE, fp)) != BOOTBLOCKSIZE) {
106 if (len < 0)
107 perror(argv[2]);
108 else
109 fprintf(stderr, "%s: short write\n", argv[2]);
110 fclose(fp);
111 (void) remove(argv[2]);
112 return 1;
113 }
114 if (fclose(fp)) {
115 perror(argv[2]);
116 (void) remove(argv[2]);
117 return 1;
118 }
119
120 return 0;
121 }
122