Index: head/usr.sbin/ndiscvt/inf.c =================================================================== --- head/usr.sbin/ndiscvt/inf.c (revision 343575) +++ head/usr.sbin/ndiscvt/inf.c (revision 343576) @@ -1,918 +1,920 @@ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2003 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "inf.h" extern FILE *yyin; int yyparse (void); const char *words[W_MAX]; /* More than we'll need. */ int idx; static struct section_head sh; static struct reg_head rh; static struct assign_head ah; static char *sstrdup (const char *); static struct assign *find_assign (const char *, const char *); static struct assign *find_next_assign (struct assign *); static struct section *find_section (const char *); -static void dump_deviceids_pci (void); -static void dump_deviceids_pcmcia (void); -static void dump_deviceids_usb (void); +static int dump_deviceids_pci (void); +static int dump_deviceids_pcmcia (void); +static int dump_deviceids_usb (void); static void dump_pci_id (const char *); static void dump_pcmcia_id (const char *); static void dump_usb_id (const char *); static void dump_regvals (void); static void dump_paramreg (const struct section *, const struct reg *, int); static FILE *ofp; int inf_parse (FILE *fp, FILE *outfp) { TAILQ_INIT(&sh); TAILQ_INIT(&rh); TAILQ_INIT(&ah); ofp = outfp; yyin = fp; yyparse(); - dump_deviceids_pci(); - dump_deviceids_pcmcia(); - dump_deviceids_usb(); + if (dump_deviceids_pci() == 0 && + dump_deviceids_pcmcia() == 0 && + dump_deviceids_usb() == 0) + return (-1); + fprintf(outfp, "#ifdef NDIS_REGVALS\n"); dump_regvals(); fprintf(outfp, "#endif /* NDIS_REGVALS */\n"); return (0); } void section_add (const char *s) { struct section *sec; sec = malloc(sizeof(struct section)); bzero(sec, sizeof(struct section)); sec->name = s; TAILQ_INSERT_TAIL(&sh, sec, link); return; } static struct assign * find_assign (const char *s, const char *k) { struct assign *assign; char newkey[256]; /* Deal with string section lookups. */ if (k != NULL && k[0] == '%') { bzero(newkey, sizeof(newkey)); strncpy(newkey, k + 1, strlen(k) - 2); k = newkey; } TAILQ_FOREACH(assign, &ah, link) { if (strcasecmp(assign->section->name, s) == 0) { if (k == NULL) return(assign); else if (strcasecmp(assign->key, k) == 0) return(assign); } } return(NULL); } static struct assign * find_next_assign (struct assign *a) { struct assign *assign; TAILQ_FOREACH(assign, &ah, link) { if (assign == a) break; } assign = assign->link.tqe_next; if (assign == NULL || assign->section != a->section) return(NULL); return (assign); } static const char * stringcvt(const char *s) { struct assign *manf; manf = find_assign("strings", s); if (manf == NULL) return(s); return(manf->vals[0]); } struct section * find_section (const char *s) { struct section *section; TAILQ_FOREACH(section, &sh, link) { if (strcasecmp(section->name, s) == 0) return(section); } return(NULL); } static void dump_pcmcia_id(const char *s) { char *manstr, *devstr; char *p0, *p; p0 = __DECONST(char *, s); p = strchr(p0, '\\'); if (p == NULL) return; p0 = p + 1; p = strchr(p0, '-'); if (p == NULL) return; *p = '\0'; manstr = p0; /* Convert any underscores to spaces. */ while (*p0 != '\0') { if (*p0 == '_') *p0 = ' '; p0++; } p0 = p + 1; p = strchr(p0, '-'); if (p == NULL) return; *p = '\0'; devstr = p0; /* Convert any underscores to spaces. */ while (*p0 != '\0') { if (*p0 == '_') *p0 = ' '; p0++; } fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr); return; } static void dump_pci_id(const char *s) { char *p; char vidstr[7], didstr[7], subsysstr[14]; p = strcasestr(s, "VEN_"); if (p == NULL) return; p += 4; strcpy(vidstr, "0x"); strncat(vidstr, p, 4); p = strcasestr(s, "DEV_"); if (p == NULL) return; p += 4; strcpy(didstr, "0x"); strncat(didstr, p, 4); if (p == NULL) return; p = strcasestr(s, "SUBSYS_"); if (p == NULL) strcpy(subsysstr, "0x00000000"); else { p += 7; strcpy(subsysstr, "0x"); strncat(subsysstr, p, 8); } fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr); return; } static void dump_usb_id(const char *s) { char *p; char vidstr[7], pidstr[7]; p = strcasestr(s, "VID_"); if (p == NULL) return; p += 4; strcpy(vidstr, "0x"); strncat(vidstr, p, 4); p = strcasestr(s, "PID_"); if (p == NULL) return; p += 4; strcpy(pidstr, "0x"); strncat(pidstr, p, 4); if (p == NULL) return; fprintf(ofp, "\t\\\n\t{ %s, %s, ", vidstr, pidstr); } -static void +static int dump_deviceids_pci() { struct assign *manf, *dev; struct section *sec; struct assign *assign; char xpsec[256]; int first = 1, found = 0; /* Find manufacturer name */ manf = find_assign("Manufacturer", NULL); nextmanf: /* Find manufacturer section */ if (manf->vals[1] != NULL && (strcasecmp(manf->vals[1], "NT.5.1") == 0 || strcasecmp(manf->vals[1], "NTx86") == 0 || strcasecmp(manf->vals[1], "NTx86.5.1") == 0 || strcasecmp(manf->vals[1], "NTamd64") == 0)) { /* Handle Windows XP INF files. */ snprintf(xpsec, sizeof(xpsec), "%s.%s", manf->vals[0], manf->vals[1]); sec = find_section(xpsec); } else sec = find_section(manf->vals[0]); /* See if there are any PCI device definitions. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); if (strcasestr(assign->vals[1], "PCI") != NULL) { found++; break; } } } if (found == 0) goto done; found = 0; if (first == 1) { /* Emit start of PCI device table */ fprintf (ofp, "#define NDIS_PCI_DEV_TABLE"); first = 0; } retry: /* * Now run through all the device names listed * in the manufacturer section and dump out the * device descriptions and vendor/device IDs. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); /* Emit device IDs. */ if (strcasestr(assign->vals[1], "PCI") != NULL) dump_pci_id(assign->vals[1]); else continue; /* Emit device description */ fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]); found++; } } /* Someone tried to fool us. Shame on them. */ if (!found) { found++; sec = find_section(manf->vals[0]); goto retry; } /* Handle Manufacturer sections with multiple entries. */ manf = find_next_assign(manf); if (manf != NULL) goto nextmanf; done: /* Emit end of table */ fprintf(ofp, "\n\n"); - return; + return (found); } -static void +static int dump_deviceids_pcmcia() { struct assign *manf, *dev; struct section *sec; struct assign *assign; char xpsec[256]; int first = 1, found = 0; /* Find manufacturer name */ manf = find_assign("Manufacturer", NULL); nextmanf: /* Find manufacturer section */ if (manf->vals[1] != NULL && (strcasecmp(manf->vals[1], "NT.5.1") == 0 || strcasecmp(manf->vals[1], "NTx86") == 0 || strcasecmp(manf->vals[1], "NTx86.5.1") == 0 || strcasecmp(manf->vals[1], "NTamd64") == 0)) { /* Handle Windows XP INF files. */ snprintf(xpsec, sizeof(xpsec), "%s.%s", manf->vals[0], manf->vals[1]); sec = find_section(xpsec); } else sec = find_section(manf->vals[0]); /* See if there are any PCMCIA device definitions. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); if (strcasestr(assign->vals[1], "PCMCIA") != NULL) { found++; break; } } } if (found == 0) goto done; found = 0; if (first == 1) { /* Emit start of PCMCIA device table */ fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE"); first = 0; } retry: /* * Now run through all the device names listed * in the manufacturer section and dump out the * device descriptions and vendor/device IDs. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); /* Emit device IDs. */ if (strcasestr(assign->vals[1], "PCMCIA") != NULL) dump_pcmcia_id(assign->vals[1]); else continue; /* Emit device description */ fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]); found++; } } /* Someone tried to fool us. Shame on them. */ if (!found) { found++; sec = find_section(manf->vals[0]); goto retry; } /* Handle Manufacturer sections with multiple entries. */ manf = find_next_assign(manf); if (manf != NULL) goto nextmanf; done: /* Emit end of table */ fprintf(ofp, "\n\n"); - return; + return (found); } -static void +static int dump_deviceids_usb() { struct assign *manf, *dev; struct section *sec; struct assign *assign; char xpsec[256]; int first = 1, found = 0; /* Find manufacturer name */ manf = find_assign("Manufacturer", NULL); nextmanf: /* Find manufacturer section */ if (manf->vals[1] != NULL && (strcasecmp(manf->vals[1], "NT.5.1") == 0 || strcasecmp(manf->vals[1], "NTx86") == 0 || strcasecmp(manf->vals[1], "NTx86.5.1") == 0 || strcasecmp(manf->vals[1], "NTamd64") == 0)) { /* Handle Windows XP INF files. */ snprintf(xpsec, sizeof(xpsec), "%s.%s", manf->vals[0], manf->vals[1]); sec = find_section(xpsec); } else sec = find_section(manf->vals[0]); /* See if there are any USB device definitions. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); if (strcasestr(assign->vals[1], "USB") != NULL) { found++; break; } } } if (found == 0) goto done; found = 0; if (first == 1) { /* Emit start of USB device table */ fprintf (ofp, "#define NDIS_USB_DEV_TABLE"); first = 0; } retry: /* * Now run through all the device names listed * in the manufacturer section and dump out the * device descriptions and vendor/device IDs. */ TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { dev = find_assign("strings", assign->key); /* Emit device IDs. */ if (strcasestr(assign->vals[1], "USB") != NULL) dump_usb_id(assign->vals[1]); else continue; /* Emit device description */ fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]); found++; } } /* Someone tried to fool us. Shame on them. */ if (!found) { found++; sec = find_section(manf->vals[0]); goto retry; } /* Handle Manufacturer sections with multiple entries. */ manf = find_next_assign(manf); if (manf != NULL) goto nextmanf; done: /* Emit end of table */ fprintf(ofp, "\n\n"); - return; + return (found); } static void dump_addreg(const char *s, int devidx) { struct section *sec; struct reg *reg; /* Find the addreg section */ sec = find_section(s); /* Dump all the keys defined in it. */ TAILQ_FOREACH(reg, &rh, link) { /* * Keys with an empty subkey are very easy to parse, * so just deal with them here. If a parameter key * of the same name also exists, prefer that one and * skip this one. */ if (reg->section == sec) { if (reg->subkey == NULL) { fprintf(ofp, "\n\t{ \"%s\",", reg->key); fprintf(ofp,"\n\t\"%s \",", reg->key); fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" : stringcvt(reg->value), devidx); } else if (strncasecmp(reg->subkey, "Ndi\\params", strlen("Ndi\\params")-1) == 0 && (reg->key != NULL && strcasecmp(reg->key, "ParamDesc") == 0)) dump_paramreg(sec, reg, devidx); } } return; } static void dump_enumreg(const struct section *s, const struct reg *r) { struct reg *reg; char enumkey[256]; sprintf(enumkey, "%s\\enum", r->subkey); TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey)) continue; fprintf(ofp, " [%s=%s]", reg->key, stringcvt(reg->value)); } return; } static void dump_editreg(const struct section *s, const struct reg *r) { struct reg *reg; TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) continue; if (reg->key == NULL) continue; if (strcasecmp(reg->key, "LimitText") == 0) fprintf(ofp, " [maxchars=%s]", reg->value); if (strcasecmp(reg->key, "Optional") == 0 && strcmp(reg->value, "1") == 0) fprintf(ofp, " [optional]"); } return; } /* Use this for int too */ static void dump_dwordreg(const struct section *s, const struct reg *r) { struct reg *reg; TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) continue; if (reg->key == NULL) continue; if (strcasecmp(reg->key, "min") == 0) fprintf(ofp, " [min=%s]", reg->value); if (strcasecmp(reg->key, "max") == 0) fprintf(ofp, " [max=%s]", reg->value); } return; } static void dump_defaultinfo(const struct section *s, const struct reg *r, int devidx) { struct reg *reg; TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) continue; if (reg->key == NULL || strcasecmp(reg->key, "Default")) continue; fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" : stringcvt(reg->value), devidx); return; } /* Default registry entry missing */ fprintf(ofp, "\n\t{ \"\" }, %d },", devidx); return; } static void dump_paramdesc(const struct section *s, const struct reg *r) { struct reg *reg; TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) continue; if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc")) continue; fprintf(ofp, "\n\t\"%s", stringcvt(r->value)); break; } return; } static void dump_typeinfo(const struct section *s, const struct reg *r) { struct reg *reg; TAILQ_FOREACH(reg, &rh, link) { if (reg->section != s) continue; if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) continue; if (reg->key == NULL) continue; if (strcasecmp(reg->key, "type")) continue; if (strcasecmp(reg->value, "dword") == 0 || strcasecmp(reg->value, "int") == 0) dump_dwordreg(s, r); if (strcasecmp(reg->value, "enum") == 0) dump_enumreg(s, r); if (strcasecmp(reg->value, "edit") == 0) dump_editreg(s, r); } return; } static void dump_paramreg(const struct section *s, const struct reg *r, int devidx) { const char *keyname; keyname = r->subkey + strlen("Ndi\\params\\"); fprintf(ofp, "\n\t{ \"%s\",", keyname); dump_paramdesc(s, r); dump_typeinfo(s, r); fprintf(ofp, "\","); dump_defaultinfo(s, r, devidx); return; } static void dump_regvals(void) { struct assign *manf, *dev; struct section *sec; struct assign *assign; char sname[256]; int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0; /* Find signature to check for special case of WinNT. */ assign = find_assign("version", "signature"); if (strcasecmp(assign->vals[0], "$windows nt$") == 0) is_winnt++; /* Emit start of block */ fprintf (ofp, "ndis_cfg ndis_regvals[] = {"); /* Find manufacturer name */ manf = find_assign("Manufacturer", NULL); nextmanf: /* Find manufacturer section */ if (manf->vals[1] != NULL && (strcasecmp(manf->vals[1], "NT.5.1") == 0 || strcasecmp(manf->vals[1], "NTx86") == 0 || strcasecmp(manf->vals[1], "NTx86.5.1") == 0 || strcasecmp(manf->vals[1], "NTamd64") == 0)) { is_winxp++; /* Handle Windows XP INF files. */ snprintf(sname, sizeof(sname), "%s.%s", manf->vals[0], manf->vals[1]); sec = find_section(sname); } else sec = find_section(manf->vals[0]); retry: TAILQ_FOREACH(assign, &ah, link) { if (assign->section == sec) { found++; /* * Find all the AddReg sections. * Look for section names with .NT, unless * this is a WinXP .INF file. */ if (is_winxp) { sprintf(sname, "%s.NTx86", assign->vals[0]); dev = find_assign(sname, "AddReg"); if (dev == NULL) { sprintf(sname, "%s.NT", assign->vals[0]); dev = find_assign(sname, "AddReg"); } if (dev == NULL) dev = find_assign(assign->vals[0], "AddReg"); } else { sprintf(sname, "%s.NT", assign->vals[0]); dev = find_assign(sname, "AddReg"); if (dev == NULL && is_winnt) dev = find_assign(assign->vals[0], "AddReg"); } /* Section not found. */ if (dev == NULL) continue; for (i = 0; i < W_MAX; i++) { if (dev->vals[i] != NULL) dump_addreg(dev->vals[i], devidx); } devidx++; } } if (!found) { sec = find_section(manf->vals[0]); is_winxp = 0; found++; goto retry; } manf = find_next_assign(manf); if (manf != NULL) goto nextmanf; fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n"); return; } void assign_add (const char *a) { struct assign *assign; int i; assign = malloc(sizeof(struct assign)); bzero(assign, sizeof(struct assign)); assign->section = TAILQ_LAST(&sh, section_head); assign->key = sstrdup(a); for (i = 0; i < idx; i++) assign->vals[(idx - 1) - i] = sstrdup(words[i]); TAILQ_INSERT_TAIL(&ah, assign, link); clear_words(); return; } void define_add (const char *d __unused) { #ifdef notdef fprintf(stderr, "define \"%s\"\n", d); #endif return; } static char * sstrdup(const char *str) { if (str != NULL && strlen(str)) return (strdup(str)); return (NULL); } static int satoi (const char *nptr) { if (nptr != NULL && strlen(nptr)) return (atoi(nptr)); return (0); } void regkey_add (const char *r) { struct reg *reg; reg = malloc(sizeof(struct reg)); bzero(reg, sizeof(struct reg)); reg->section = TAILQ_LAST(&sh, section_head); reg->root = sstrdup(r); reg->subkey = sstrdup(words[3]); reg->key = sstrdup(words[2]); reg->flags = satoi(words[1]); reg->value = sstrdup(words[0]); TAILQ_INSERT_TAIL(&rh, reg, link); free(__DECONST(char *, r)); clear_words(); return; } void push_word (const char *w) { if (idx == W_MAX) { fprintf(stderr, "too many words; try bumping W_MAX in inf.h\n"); exit(1); } if (w && strlen(w)) words[idx++] = w; else words[idx++] = NULL; return; } void clear_words (void) { int i; for (i = 0; i < idx; i++) { if (words[i]) { free(__DECONST(char *, words[i])); } } idx = 0; bzero(words, sizeof(words)); return; } Index: head/usr.sbin/ndiscvt/ndiscvt.c =================================================================== --- head/usr.sbin/ndiscvt/ndiscvt.c (revision 343575) +++ head/usr.sbin/ndiscvt/ndiscvt.c (revision 343576) @@ -1,435 +1,436 @@ /* * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2003 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "inf.h" static int insert_padding(void **, int *); extern const char *__progname; /* * Sections within Windows PE files are defined using virtual * and physical address offsets and virtual and physical sizes. * The physical values define how the section data is stored in * the executable file while the virtual values describe how the * sections will look once loaded into memory. It happens that * the linker in the Microsoft(r) DDK will tend to generate * binaries where the virtual and physical values are identical, * which means in most cases we can just transfer the file * directly to memory without any fixups. This is not always * the case though, so we have to be prepared to handle files * where the in-memory section layout differs from the disk file * section layout. * * There are two kinds of variations that can occur: the relative * virtual address of the section might be different from the * physical file offset, and the virtual section size might be * different from the physical size (for example, the physical * size of the .data section might be 1024 bytes, but the virtual * size might be 1384 bytes, indicating that the data section should * actually use up 1384 bytes in RAM and be padded with zeros). What we * do is read the original file into memory and then make an in-memory * copy with all of the sections relocated, re-sized and zero padded * according to the virtual values specified in the section headers. * We then emit the fixed up image file for use by the if_ndis driver. * This way, we don't have to do the fixups inside the kernel. */ #define ROUND_DOWN(n, align) (((uintptr_t)n) & ~((align) - 1l)) #define ROUND_UP(n, align) ROUND_DOWN(((uintptr_t)n) + (align) - 1l, \ (align)) #define SET_HDRS(x) \ dos_hdr = (image_dos_header *)x; \ nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \ sect_hdr = IMAGE_FIRST_SECTION(nt_hdr); static int insert_padding(void **imgbase, int *imglen) { image_section_header *sect_hdr; image_dos_header *dos_hdr; image_nt_header *nt_hdr; image_optional_header opt_hdr; int i = 0, sections, curlen = 0; int offaccum = 0, oldraddr, oldrlen; uint8_t *newimg, *tmp; newimg = malloc(*imglen); if (newimg == NULL) return(ENOMEM); bcopy(*imgbase, newimg, *imglen); curlen = *imglen; if (pe_get_optional_header((vm_offset_t)newimg, &opt_hdr)) return(0); sections = pe_numsections((vm_offset_t)newimg); SET_HDRS(newimg); for (i = 0; i < sections; i++) { oldraddr = sect_hdr->ish_rawdataaddr; oldrlen = sect_hdr->ish_rawdatasize; sect_hdr->ish_rawdataaddr = sect_hdr->ish_vaddr; offaccum += ROUND_UP(sect_hdr->ish_vaddr - oldraddr, opt_hdr.ioh_filealign); offaccum += ROUND_UP(sect_hdr->ish_misc.ish_vsize, opt_hdr.ioh_filealign) - ROUND_UP(sect_hdr->ish_rawdatasize, opt_hdr.ioh_filealign); tmp = realloc(newimg, *imglen + offaccum); if (tmp == NULL) { free(newimg); return(ENOMEM); } newimg = tmp; SET_HDRS(newimg); sect_hdr += i; bzero(newimg + sect_hdr->ish_rawdataaddr, ROUND_UP(sect_hdr->ish_misc.ish_vsize, opt_hdr.ioh_filealign)); bcopy((uint8_t *)(*imgbase) + oldraddr, newimg + sect_hdr->ish_rawdataaddr, oldrlen); sect_hdr++; } free(*imgbase); *imgbase = newimg; *imglen += offaccum; return(0); } static void usage(void) { fprintf(stderr, "Usage: %s [-O] [-i ] -s " "[-n devname] [-o outfile]\n", __progname); fprintf(stderr, " %s -f \n", __progname); exit(1); } static void bincvt(char *sysfile, char *outfile, void *img, int fsize) { char *ptr; char tname[] = "/tmp/ndiscvt.XXXXXX"; char sysbuf[1024]; FILE *binfp; mkstemp(tname); binfp = fopen(tname, "a+"); if (binfp == NULL) err(1, "opening %s failed", tname); if (fwrite(img, fsize, 1, binfp) != 1) err(1, "failed to output binary image"); fclose(binfp); outfile = strdup(basename(outfile)); if (strchr(outfile, '.')) *strchr(outfile, '.') = '\0'; snprintf(sysbuf, sizeof(sysbuf), #ifdef __i386__ "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", #endif #ifdef __amd64__ "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n", #endif tname, outfile); printf("%s", sysbuf); system(sysbuf); unlink(tname); ptr = tname; while (*ptr) { if (*ptr == '/' || *ptr == '.') *ptr = '_'; ptr++; } snprintf(sysbuf, sizeof(sysbuf), "objcopy --redefine-sym _binary_%s_start=ndis_%s_drv_data_start " "--strip-symbol _binary_%s_size " "--redefine-sym _binary_%s_end=ndis_%s_drv_data_end %s.o %s.o\n", tname, sysfile, tname, tname, sysfile, outfile, outfile); printf("%s", sysbuf); system(sysbuf); free(outfile); return; } static void firmcvt(char *firmfile) { char *basefile, *outfile, *ptr; char sysbuf[1024]; outfile = strdup(basename(firmfile)); basefile = strdup(outfile); snprintf(sysbuf, sizeof(sysbuf), #ifdef __i386__ "objcopy -I binary -O elf32-i386-freebsd -B i386 %s %s.o\n", #endif #ifdef __amd64__ "objcopy -I binary -O elf64-x86-64-freebsd -B i386 %s %s.o\n", #endif firmfile, outfile); printf("%s", sysbuf); system(sysbuf); ptr = firmfile; while (*ptr) { if (*ptr == '/' || *ptr == '.') *ptr = '_'; ptr++; } ptr = basefile; while (*ptr) { if (*ptr == '/' || *ptr == '.') *ptr = '_'; else *ptr = tolower(*ptr); ptr++; } snprintf(sysbuf, sizeof(sysbuf), "objcopy --redefine-sym _binary_%s_start=%s_start " "--strip-symbol _binary_%s_size " "--redefine-sym _binary_%s_end=%s_end %s.o %s.o\n", firmfile, basefile, firmfile, firmfile, basefile, outfile, outfile); ptr = sysbuf; printf("%s", sysbuf); system(sysbuf); snprintf(sysbuf, sizeof(sysbuf), "ld -Bshareable -d -warn-common -o %s.ko %s.o\n", outfile, outfile); printf("%s", sysbuf); system(sysbuf); free(basefile); exit(0); } int main(int argc, char *argv[]) { FILE *fp, *outfp; int i, bin = 0; void *img; int n, fsize, cnt; unsigned char *ptr; char *inffile = NULL, *sysfile = NULL; char *outfile = NULL, *firmfile = NULL; char *dname = NULL; int ch; while((ch = getopt(argc, argv, "i:s:o:n:f:O")) != -1) { switch(ch) { case 'f': firmfile = optarg; break; case 'i': inffile = optarg; break; case 's': sysfile = optarg; break; case 'o': outfile = optarg; break; case 'n': dname = optarg; break; case 'O': bin = 1; break; default: usage(); break; } } if (firmfile != NULL) firmcvt(firmfile); if (sysfile == NULL) usage(); /* Open the .SYS file and load it into memory */ fp = fopen(sysfile, "r"); if (fp == NULL) err(1, "opening .SYS file '%s' failed", sysfile); fseek (fp, 0L, SEEK_END); fsize = ftell (fp); rewind (fp); img = calloc(fsize, 1); n = fread (img, fsize, 1, fp); if (n == 0) err(1, "reading .SYS file '%s' failed", sysfile); fclose(fp); if (insert_padding(&img, &fsize)) { fprintf(stderr, "section relocation failed\n"); exit(1); } if (outfile == NULL || strcmp(outfile, "-") == 0) outfp = stdout; else { outfp = fopen(outfile, "w"); if (outfp == NULL) err(1, "opening output file '%s' failed", outfile); } fprintf(outfp, "\n/*\n"); fprintf(outfp, " * Generated from %s and %s (%d bytes)\n", inffile == NULL ? "" : inffile, sysfile, fsize); fprintf(outfp, " */\n\n"); if (dname != NULL) { if (strlen(dname) > IFNAMSIZ) err(1, "selected device name '%s' is " "too long (max chars: %d)", dname, IFNAMSIZ); fprintf (outfp, "#define NDIS_DEVNAME \"%s\"\n", dname); fprintf (outfp, "#define NDIS_MODNAME %s\n\n", dname); } if (inffile == NULL) { fprintf (outfp, "#ifdef NDIS_REGVALS\n"); fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n"); fprintf (outfp, "\t{ NULL, NULL, { 0 }, 0 }\n"); fprintf (outfp, "#endif /* NDIS_REGVALS */\n"); fprintf (outfp, "};\n\n"); } else { fp = fopen(inffile, "r"); if (fp == NULL) err(1, "opening .INF file '%s' failed", inffile); - inf_parse(fp, outfp); + if (inf_parse(fp, outfp) != 0) + errx(1, "creating .INF file - no entries created, are you using the correct files?"); fclose(fp); } fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); if (bin) { sysfile = strdup(basename(sysfile)); ptr = (unsigned char *)sysfile; while (*ptr) { if (*ptr == '.') *ptr = '_'; ptr++; } fprintf(outfp, "\nextern unsigned char ndis_%s_drv_data_start[];\n", sysfile); fprintf(outfp, "static unsigned char *drv_data = " "ndis_%s_drv_data_start;\n\n", sysfile); bincvt(sysfile, outfile, img, fsize); goto done; } fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); fprintf(outfp, "__asm__(\".data\");\n"); fprintf(outfp, "__asm__(\".globl drv_data\");\n"); fprintf(outfp, "__asm__(\".type drv_data, @object\");\n"); fprintf(outfp, "__asm__(\".size drv_data, %d\");\n", fsize); fprintf(outfp, "__asm__(\"drv_data:\");\n"); ptr = img; cnt = 0; while(cnt < fsize) { fprintf (outfp, "__asm__(\".byte "); for (i = 0; i < 10; i++) { cnt++; if (cnt == fsize) { fprintf(outfp, "0x%.2X\");\n", ptr[i]); goto done; } else { if (i == 9) fprintf(outfp, "0x%.2X\");\n", ptr[i]); else fprintf(outfp, "0x%.2X, ", ptr[i]); } } ptr += 10; } done: fprintf(outfp, "#endif /* NDIS_IMAGE */\n"); if (fp != NULL) fclose(fp); fclose(outfp); free(img); exit(0); }