xref: /freebsd-13.1/usr.sbin/ndiscvt/ndiscvt.c (revision 602fa832)
1 /*
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2003
5  *	Bill Paul <[email protected]>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/types.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 #include <net/if.h>
42 #include <stdlib.h>
43 #include <stddef.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <errno.h>
47 #include <string.h>
48 #include <libgen.h>
49 #include <err.h>
50 #include <ctype.h>
51 
52 #include <compat/ndis/pe_var.h>
53 
54 #include "inf.h"
55 
56 static int insert_padding(void **, int *);
57 extern const char *__progname;
58 
59 /*
60  * Sections within Windows PE files are defined using virtual
61  * and physical address offsets and virtual and physical sizes.
62  * The physical values define how the section data is stored in
63  * the executable file while the virtual values describe how the
64  * sections will look once loaded into memory. It happens that
65  * the linker in the Microsoft(r) DDK will tend to generate
66  * binaries where the virtual and physical values are identical,
67  * which means in most cases we can just transfer the file
68  * directly to memory without any fixups. This is not always
69  * the case though, so we have to be prepared to handle files
70  * where the in-memory section layout differs from the disk file
71  * section layout.
72  *
73  * There are two kinds of variations that can occur: the relative
74  * virtual address of the section might be different from the
75  * physical file offset, and the virtual section size might be
76  * different from the physical size (for example, the physical
77  * size of the .data section might be 1024 bytes, but the virtual
78  * size might be 1384 bytes, indicating that the data section should
79  * actually use up 1384 bytes in RAM and be padded with zeros). What we
80  * do is read the original file into memory and then make an in-memory
81  * copy with all of the sections relocated, re-sized and zero padded
82  * according to the virtual values specified in the section headers.
83  * We then emit the fixed up image file for use by the if_ndis driver.
84  * This way, we don't have to do the fixups inside the kernel.
85  */
86 
87 #define ROUND_DOWN(n, align)    (((uintptr_t)n) & ~((align) - 1l))
88 #define ROUND_UP(n, align)      ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \
89                                 (align))
90 
91 #define SET_HDRS(x)	\
92 	dos_hdr = (image_dos_header *)x;				\
93 	nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew);		\
94 	sect_hdr = IMAGE_FIRST_SECTION(nt_hdr);
95 
96 static int
insert_padding(void ** imgbase,int * imglen)97 insert_padding(void **imgbase, int *imglen)
98 {
99         image_section_header	*sect_hdr;
100         image_dos_header	*dos_hdr;
101         image_nt_header		*nt_hdr;
102 	image_optional_header	opt_hdr;
103         int			i = 0, sections, curlen = 0;
104 	int			offaccum = 0, oldraddr, oldrlen;
105 	uint8_t			*newimg, *tmp;
106 
107 	newimg = malloc(*imglen);
108 
109 	if (newimg == NULL)
110 		return(ENOMEM);
111 
112 	bcopy(*imgbase, newimg, *imglen);
113 	curlen = *imglen;
114 
115 	if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr))
116 		return(0);
117 
118         sections = pe_numsections((vm_offset_t)newimg);
119 
120 	SET_HDRS(newimg);
121 
122 	for (i = 0; i < sections; i++) {
123 		oldraddr = sect_hdr->ish_rawdataaddr;
124 		oldrlen = sect_hdr->ish_rawdatasize;
125 		sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr;
126 		offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr,
127 		    opt_hdr.ioh_filealign);
128 		offaccum +=
129 		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
130 			     opt_hdr.ioh_filealign) -
131 		    ROUND_UP(sect_hdr->ish_rawdatasize,
132 			     opt_hdr.ioh_filealign);
133 		tmp = realloc(newimg, *imglen + offaccum);
134 		if (tmp == NULL) {
135 			free(newimg);
136 			return(ENOMEM);
137 		}
138 		newimg = tmp;
139 		SET_HDRS(newimg);
140 		sect_hdr += i;
141 		bzero(newimg + sect_hdr->ish_rawdataaddr,
142 		    ROUND_UP(sect_hdr->ish_misc.ish_vsize,
143 		    opt_hdr.ioh_filealign));
144 		bcopy((uint8_t *)(*imgbase) + oldraddr,
145 		    newimg + sect_hdr->ish_rawdataaddr, oldrlen);
146 		sect_hdr++;
147 	}
148 
149 	free(*imgbase);
150 
151 	*imgbase = newimg;
152 	*imglen += offaccum;
153 
154 	return(0);
155 }
156 
157 static void
usage(void)158 usage(void)
159 {
160 	fprintf(stderr, "Usage: %s [-O] [-i <inffile>] -s <sysfile> "
161 	    "[-n devname] [-o outfile]\n", __progname);
162 	fprintf(stderr, "       %s -f <firmfile>\n", __progname);
163 
164 	exit(1);
165 }
166 
167 static void
bincvt(char * sysfile,char * outfile,void * img,int fsize)168 bincvt(char *sysfile, char *outfile, void *img, int fsize)
169 {
170 	char			*ptr;
171 	char			tname[] = "/tmp/ndiscvt.XXXXXX";
172 	char			sysbuf[1024];
173 	FILE			*binfp;
174 
175 	mkstemp(tname);
176 
177 	binfp = fopen(tname, "a+");
178 	if (binfp == NULL)
179 		err(1, "opening %s failed", tname);
180 
181 	if (fwrite(img, fsize, 1, binfp) != 1)
182 		err(1, "failed to output binary image");
183 
184 	fclose(binfp);
185 
186 	outfile = strdup(basename(outfile));
187 	if (strchr(outfile, '.'))
188 		*strchr(outfile, '.') = '\0';
189 
190 	snprintf(sysbuf, sizeof(sysbuf),
191 #ifdef __i386__
192 	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
193 #endif
194 #ifdef __amd64__
195 	    "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
196 #endif
197 	    tname, outfile);
198 	printf("%s", sysbuf);
199 	system(sysbuf);
200 	unlink(tname);
201 
202 	ptr = tname;
203 	while (*ptr) {
204 		if (*ptr == '/' || *ptr == '.')
205 			*ptr = '_';
206 		ptr++;
207 	}
208 
209 	snprintf(sysbuf, sizeof(sysbuf),
210 	    "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start "
211 	    "--strip-symbol _binary_%s_size "
212 	    "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n",
213 	    tname, sysfile, tname, tname, sysfile, outfile, outfile);
214 	printf("%s", sysbuf);
215 	system(sysbuf);
216 	free(outfile);
217 
218 	return;
219 }
220 
221 static void
firmcvt(char * firmfile)222 firmcvt(char *firmfile)
223 {
224 	char			*basefile, *outfile, *ptr;
225 	char			sysbuf[1024];
226 
227 	outfile = strdup(basename(firmfile));
228 	basefile = strdup(outfile);
229 
230 	snprintf(sysbuf, sizeof(sysbuf),
231 #ifdef __i386__
232 	    "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n",
233 #endif
234 #ifdef __amd64__
235 	    "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n",
236 #endif
237 	    firmfile, outfile);
238 	printf("%s", sysbuf);
239 	system(sysbuf);
240 
241 	ptr = firmfile;
242 	while (*ptr) {
243 		if (*ptr == '/' || *ptr == '.')
244 			*ptr = '_';
245 		ptr++;
246 	}
247 	ptr = basefile;
248 	while (*ptr) {
249 		if (*ptr == '/' || *ptr == '.')
250 			*ptr = '_';
251 		else
252 			*ptr = tolower(*ptr);
253 		ptr++;
254 	}
255 
256 	snprintf(sysbuf, sizeof(sysbuf),
257 	    "objcopy --redefine-sym _binary_%s_start=%s_start "
258 	    "--strip-symbol _binary_%s_size "
259 	    "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n",
260 	    firmfile, basefile, firmfile, firmfile,
261 	    basefile, outfile, outfile);
262 	ptr = sysbuf;
263 	printf("%s", sysbuf);
264 	system(sysbuf);
265 
266 	snprintf(sysbuf, sizeof(sysbuf),
267 	    "ld -Bshareable -d -warn-common -o %s.ko %s.o\n",
268 	    outfile, outfile);
269 	printf("%s", sysbuf);
270 	system(sysbuf);
271 
272 	free(basefile);
273 
274 	exit(0);
275 }
276 
277 int
main(int argc,char * argv[])278 main(int argc, char *argv[])
279 {
280 	FILE			*fp, *outfp;
281 	int			i, bin = 0;
282 	void			*img;
283 	int			n, fsize, cnt;
284 	unsigned char		*ptr;
285 	char			*inffile = NULL, *sysfile = NULL;
286 	char			*outfile = NULL, *firmfile = NULL;
287 	char			*dname = NULL;
288 	int			ch;
289 
290 	while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) {
291 		switch(ch) {
292 		case 'f':
293 			firmfile = optarg;
294 			break;
295 		case 'i':
296 			inffile = optarg;
297 			break;
298 		case 's':
299 			sysfile = optarg;
300 			break;
301 		case 'o':
302 			outfile = optarg;
303 			break;
304 		case 'n':
305 			dname = optarg;
306 			break;
307 		case 'O':
308 			bin = 1;
309 			break;
310 		default:
311 			usage();
312 			break;
313 		}
314 	}
315 
316 	if (firmfile != NULL)
317 		firmcvt(firmfile);
318 
319 	if (sysfile == NULL)
320 		usage();
321 
322 	/* Open the .SYS file and load it into memory */
323 	fp = fopen(sysfile, "r");
324 	if (fp == NULL)
325 		err(1, "opening .SYS file '%s' failed", sysfile);
326 	fseek (fp, 0L, SEEK_END);
327 	fsize = ftell (fp);
328 	rewind (fp);
329 	img = calloc(fsize, 1);
330 	n = fread (img, fsize, 1, fp);
331 	if (n == 0)
332 		err(1, "reading .SYS file '%s' failed", sysfile);
333 
334 	fclose(fp);
335 
336 	if (insert_padding(&img, &fsize)) {
337 		fprintf(stderr, "section relocation failed\n");
338 		exit(1);
339 	}
340 
341 	if (outfile == NULL || strcmp(outfile, "-") == 0)
342 		outfp = stdout;
343 	else {
344 		outfp = fopen(outfile, "w");
345 		if (outfp == NULL)
346 			err(1, "opening output file '%s' failed", outfile);
347 	}
348 
349 	fprintf(outfp, "\n/*\n");
350 	fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
351 	    inffile == NULL ? "<notused>" : inffile, sysfile, fsize);
352 	fprintf(outfp, " */\n\n");
353 
354 	if (dname != NULL) {
355 		if (strlen(dname) > IFNAMSIZ)
356 			err(1, "selected device name '%s' is "
357 			    "too long (max chars: %d)", dname, IFNAMSIZ);
358 		fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname);
359 		fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname);
360 	}
361 
362 	if (inffile == NULL) {
363 		fprintf (outfp, "#ifdef NDIS_REGVALS\n");
364 		fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n");
365         	fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n");
366 		fprintf (outfp, "#endif /* NDIS_REGVALS */\n");
367 
368 		fprintf (outfp, "};\n\n");
369 	} else {
370 		fp = fopen(inffile, "r");
371 		if (fp == NULL)
372 			err(1, "opening .INF file '%s' failed", inffile);
373 
374 
375 		if (inf_parse(fp, outfp) != 0)
376 			errx(1, "creating .INF file - no entries created, are you using the correct files?");
377 		fclose(fp);
378 	}
379 
380 	fprintf(outfp, "\n#ifdef NDIS_IMAGE\n");
381 
382 	if (bin) {
383 		sysfile = strdup(basename(sysfile));
384 		ptr = (unsigned char *)sysfile;
385 		while (*ptr) {
386 			if (*ptr == '.')
387 				*ptr = '_';
388 			ptr++;
389 		}
390 		fprintf(outfp,
391 		    "\nextern unsigned char ndis_%s_drv_data_start[];\n",
392 		    sysfile);
393 		fprintf(outfp, "static unsigned char *drv_data = "
394 		    "ndis_%s_drv_data_start;\n\n", sysfile);
395 		bincvt(sysfile, outfile, img, fsize);
396 		goto done;
397 	}
398 
399 
400 	fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
401 
402 	fprintf(outfp, "__asm__(\".data\");\n");
403 	fprintf(outfp, "__asm__(\".globl  drv_data\");\n");
404 	fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
405 	fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
406 	fprintf(outfp, "__asm__(\"drv_data:\");\n");
407 
408 	ptr = img;
409 	cnt = 0;
410 	while(cnt < fsize) {
411 		fprintf (outfp, "__asm__(\".byte ");
412 		for (i = 0; i < 10; i++) {
413 			cnt++;
414 			if (cnt == fsize) {
415 				fprintf(outfp, "0x%.2X\");\n", ptr[i]);
416 				goto done;
417 			} else {
418 				if (i == 9)
419 					fprintf(outfp, "0x%.2X\");\n", ptr[i]);
420 				else
421 					fprintf(outfp, "0x%.2X, ", ptr[i]);
422 			}
423 		}
424 		ptr += 10;
425 	}
426 
427 done:
428 
429 	fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
430 
431 	if (fp != NULL)
432 		fclose(fp);
433 	fclose(outfp);
434 	free(img);
435 	exit(0);
436 }
437