From: Matthew Dillon Date: Fri, 30 Jul 2004 00:24:24 +0000 (+0000) Subject: Add the ndiscvt utility from FreeBSD-5, which is used to compile windows X-Git-Url: https://gitweb.dragonflybsd.org/~polachok/dragonfly.git/commitdiff_plain/799e5dd91550de4a773a1dc2d20fd0945ad4cd3e Add the ndiscvt utility from FreeBSD-5, which is used to compile windows device drivers for NDIS. --- diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 4e30c55160..095fbda1e3 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,6 +1,6 @@ # From: @(#)Makefile 5.20 (Berkeley) 6/12/93 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $ -# $DragonFly: src/usr.sbin/Makefile,v 1.11 2004/07/05 00:22:39 dillon Exp $ +# $DragonFly: src/usr.sbin/Makefile,v 1.12 2004/07/30 00:24:22 dillon Exp $ # XXX MISSING: mkproto SUBDIR= IPXrouted \ @@ -54,6 +54,7 @@ SUBDIR= IPXrouted \ mrouted \ mtest \ mtree \ + ndiscvt \ ndp \ newsyslog \ ngctl \ diff --git a/usr.sbin/ndiscvt/Makefile b/usr.sbin/ndiscvt/Makefile new file mode 100644 index 0000000000..b372a3d627 --- /dev/null +++ b/usr.sbin/ndiscvt/Makefile @@ -0,0 +1,24 @@ +# $FreeBSD: src/usr.sbin/ndiscvt/Makefile,v 1.5 2004/02/23 20:21:21 johan Exp $ +# $DragonFly: src/usr.sbin/ndiscvt/Makefile,v 1.1 2004/07/30 00:24:24 dillon Exp $ + +.PATH: ${.CURDIR}/../../sys/emulation/ndis + +PROG= ndiscvt +SRCS= ndiscvt.c +SRCS+= subr_pe.c +SRCS+= inf.c inf-token.l inf-parse.y y.tab.h + +MAN8= ndiscvt.8 + +WARNS?= 4 + +DPADD= ${LIBL} +LDADD= -ll + +YFLAGS+=-v + +CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys + +CLEANFILES= y.output + +.include diff --git a/usr.sbin/ndiscvt/inf-parse.y b/usr.sbin/ndiscvt/inf-parse.y new file mode 100644 index 0000000000..5baedbae62 --- /dev/null +++ b/usr.sbin/ndiscvt/inf-parse.y @@ -0,0 +1,110 @@ +%{ +/* + * 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. + * + * $DragonFly: src/usr.sbin/ndiscvt/inf-parse.y,v 1.1 2004/07/30 00:24:24 dillon Exp $ + */ + +#include +#include +#include + +#include "inf.h" + +extern int yyparse (void); +extern int yylex (void); +extern void yyerror(const char *); +%} + +%token EQUALS COMMA EOL +%token SECTION +%token STRING +%token WORD + +%union { + char *str; +} + +%% + +inf_file + : inf_list + | + ; + +inf_list + : inf + | inf_list inf + ; + +inf + : SECTION EOL + { section_add($1); } + | WORD EQUALS assign EOL + { assign_add($1); } + | WORD COMMA regkey EOL + { regkey_add($1); } + | WORD EOL + { define_add($1); } + | EOL + ; + +assign + : WORD + { push_word($1); } + | STRING + { push_word($1); } + | WORD COMMA assign + { push_word($1); } + | STRING COMMA assign + { push_word($1); } + | COMMA assign + { push_word(NULL); } + | COMMA + { push_word(NULL); } + | + ; + +regkey + : WORD + { push_word($1); } + | STRING + { push_word($1); } + | WORD COMMA regkey + { push_word($1); } + | STRING COMMA regkey + { push_word($1); } + | COMMA regkey + { push_word(NULL); } + | COMMA + { push_word(NULL); } + ; +%% diff --git a/usr.sbin/ndiscvt/inf-token.l b/usr.sbin/ndiscvt/inf-token.l new file mode 100644 index 0000000000..e244b2e026 --- /dev/null +++ b/usr.sbin/ndiscvt/inf-token.l @@ -0,0 +1,129 @@ +%{ +/* + * 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. + * + * $DragonFly: src/usr.sbin/ndiscvt/inf-token.l,v 1.1 2004/07/30 00:24:24 dillon Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "y.tab.h" + +int lineno = 1; +#define YY_NO_UNPUT + +int yylex(void); +void yyerror(const char *); + +static void +update_lineno(const char *cp) +{ + while (*cp) + if (*cp++ == '\n') + lineno++; +} + +%} + +%% + +[ \t]+ ; +\n { lineno++; return EOL; } +\r ; +;.*$ ; +\/\/.*$ ; += { return EQUALS; } +, { return COMMA; } +\"(\\\"|[^"]|\"\")*\" { + int len = strlen(yytext) - 2; + int blen = len + 1; + char *walker; + int i; + update_lineno(yytext); + yylval.str = (char *)malloc(blen); + if (yylval.str == NULL) + goto out; + walker = yylval.str; + for (i = 1; i <= len; i++) { + if (yytext[i] == '\"') { + switch (yytext[i + 1]) { + case '\"': + i++; + break; + default: + break; + } + } + if (yytext[i] == '\\') { + switch (yytext[i + 1]) { + case '\n': + i += 2; + while(isspace(yytext[i])) + i++; + break; + case '\"': + i++; + break; + case '(': + i++; + break; + default: + break; + } + } + *walker++ = yytext[i]; + } + *walker++ = '\0'; + out:; + return STRING; + } +\[[a-zA-Z0-9%&\{\}\-\.\/_\\\*\ ]+\] { + int len = strlen(yytext); + yytext[len-1] = '\0'; + yylval.str = strdup(yytext+1); + return SECTION; + } +[a-zA-Z0-9%&\{\}\-\.\/_\\\*]+ { + yylval.str = strdup(yytext); + return WORD; + } +%% + +void +yyerror(const char *s) +{ + errx(1, "line %d: %s%s %s.", lineno, yytext, yytext?":":"", s); +} diff --git a/usr.sbin/ndiscvt/inf.c b/usr.sbin/ndiscvt/inf.c new file mode 100644 index 0000000000..b9ed8e67e2 --- /dev/null +++ b/usr.sbin/ndiscvt/inf.c @@ -0,0 +1,724 @@ +/* + * 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. + * + * $DragonFly: src/usr.sbin/ndiscvt/inf.c,v 1.1 2004/07/30 00:24:24 dillon Exp $ + */ + +#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 section + *find_section (const char *); +static void dump_deviceids_pci (void); +static void dump_deviceids_pcmcia (void); +static void dump_pci_id (const char *); +static void dump_pcmcia_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(); + 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 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_deviceids_pci() +{ + struct assign *manf, *dev; + struct section *sec; + struct assign *assign; + char xpsec[256]; + int found = 0; + + /* Find manufacturer name */ + manf = find_assign("Manufacturer", NULL); + + /* 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)) { + /* 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) + return; + + found = 0; + + /* Emit start of PCI device table */ + fprintf (ofp, "#define NDIS_PCI_DEV_TABLE"); + +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; + } + + /* Emit end of table */ + + fprintf(ofp, "\n\n"); + +} + +static void +dump_deviceids_pcmcia() +{ + struct assign *manf, *dev; + struct section *sec; + struct assign *assign; + char xpsec[256]; + int found = 0; + + /* Find manufacturer name */ + manf = find_assign("Manufacturer", NULL); + + /* 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)) { + /* 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) + return; + + found = 0; + + /* Emit start of PCMCIA device table */ + fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE"); + +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; + } + + /* Emit end of table */ + + fprintf(ofp, "\n\n"); + +} + +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); + break; + } + 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++; + + /* Find manufacturer name */ + manf = find_assign("Manufacturer", NULL); + + /* 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)) { + 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]); + + /* Emit start of block */ + fprintf (ofp, "ndis_cfg ndis_regvals[] = {"); + +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) + 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; + } + + 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 (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; +} diff --git a/usr.sbin/ndiscvt/inf.h b/usr.sbin/ndiscvt/inf.h new file mode 100644 index 0000000000..33f78699d8 --- /dev/null +++ b/usr.sbin/ndiscvt/inf.h @@ -0,0 +1,62 @@ +/* + * $Id: inf.h,v 1.3 2003/11/30 21:58:16 winter Exp $ + * + * $FreeBSD: src/usr.sbin/ndiscvt/inf.h,v 1.1 2003/12/11 22:38:14 wpaul Exp $ + * $DragonFly: src/usr.sbin/ndiscvt/inf.h,v 1.1 2004/07/30 00:24:24 dillon Exp $ + */ + +#define W_MAX 16 + +struct section { + const char * name; + + TAILQ_ENTRY(section) link; +}; +TAILQ_HEAD(section_head, section); + +struct assign { + struct section *section; + + const char * key; + const char * vals[W_MAX]; + + TAILQ_ENTRY(assign) link; +}; +TAILQ_HEAD(assign_head, assign); + +struct reg { + struct section *section; + + const char * root; + const char * subkey; + const char * key; + u_int flags; + const char * value; + + TAILQ_ENTRY(reg) link; +}; +TAILQ_HEAD(reg_head, reg); + +#define FLG_ADDREG_TYPE_SZ 0x00000000 +#define FLG_ADDREG_BINVALUETYPE 0x00000001 +#define FLG_ADDREG_NOCLOBBER 0x00000002 +#define FLG_ADDREG_DELVAL 0x00000004 +#define FLG_ADDREG_APPEND 0x00000008 +#define FLG_ADDREG_KEYONLY 0x00000010 +#define FLG_ADDREG_OVERWRITEONLY 0x00000020 +#define FLG_ADDREG_64BITKEY 0x00001000 +#define FLG_ADDREG_KEYONLY_COMMON 0x00002000 +#define FLG_ADDREG_32BITKEY 0x00004000 +#define FLG_ADDREG_TYPE_MULTI_SZ 0x00010000 +#define FLG_ADDREG_TYPE_EXPAND_SZ 0x00020000 +#define FLG_ADDREG_TYPE_DWORD 0x00010001 +#define FLG_ADDREG_TYPE_NONE 0x00020001 + +extern void section_add (const char *); +extern void assign_add (const char *); +extern void define_add (const char *); +extern void regkey_add (const char *); + +extern void push_word (const char *); +extern void clear_words (void); +extern int inf_parse (FILE *, FILE *); diff --git a/usr.sbin/ndiscvt/ndiscvt.8 b/usr.sbin/ndiscvt/ndiscvt.8 new file mode 100644 index 0000000000..ff5854121b --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.8 @@ -0,0 +1,169 @@ +.\" 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. +.\" +.\" $FreeBSD: src/usr.sbin/ndiscvt/ndiscvt.8,v 1.4 2004/06/13 18:03:42 ru Exp $ +.\" $DragonFly: src/usr.sbin/ndiscvt/ndiscvt.8,v 1.1 2004/07/30 00:24:24 dillon Exp $ +.\" +.Dd December 10, 2003 +.Dt NDISCVT 8 +.Os +.Sh NAME +.Nm ndiscvt +.Nd convert +.Tn Windows\[rg] +NDIS drivers for use with +.Fx +.Sh SYNOPSIS +.Nm +.Op Fl i Ar inffile +.Fl s Ar sysfile +.Op Fl n Ar devname +.Op Fl o Ar outfile +.Sh DESCRIPTION +The +.Nm +utility transforms a +.Tn Windows\[rg] +NDIS driver into a data file which +is used to build an +.Xr ndis 4 +compatibility driver module. +.Tn Windows\[rg] +drivers consist of two main parts: a +.Pa .SYS +file, which contains the actual driver executable code, +and an +.Pa .INF +file, which provides the +.Tn Windows\[rg] +installer with device +identifier information and a list of driver-specific registry keys. +The +.Nm +utility can convert these files into a header file that is compiled +into +.Pa if_ndis.c +to create an object code module that can be linked into +the +.Fx +kernel. +.Pp +The +.Pa .INF +file is typically required since only it contains device +identification data such as PCI vendor and device IDs or PCMCIA +indentifier strings. +The +.Pa .INF +file may be optionally omitted however, +in which case the +.Nm +utility will only perform the conversion of the +.Pa .SYS +file. +This is useful for debugging purposes only. +.Sh OPTIONS +The options are as follows: +.Bl -tag -width indent +.It Fl i Ar inffile +Open and parse the specified +.Pa .INF +file when performing conversion. +The +.Nm +utility will parse this file and emit a device identification +structure and registry key configuration structures which will be +used by the +.Xr ndis 4 +driver and +.Xr ndisapi 9 +kernel subsystem. +If this is omitted, +.Nm +will emit a dummy configuration structure only. +.It Fl s Ar sysfile +Open and parse the specified +.Pa .SYS +file. +This file must contain a +.Tn Windows\[rg] +driver image. +The +.Nm +utility will perform some manipulation of the sections within the +executable file to make runtime linking within the kernel a little +easier and then convert the image into a data array. +.It Fl n Ar devname +Specify an alternate name for the network device/interface which will +be created when the driver is instantiated. +If you need to load more +than one NDIS driver into your system (i.e., if you have two different +network cards in your system which require NDIS driver support), each +module you create must have a unique name. +Device can not be larger than +.Dv IFNAMSIZ . +If no name is specified, the driver will use the +default a default name +.Pq Dq Li ndis . +.It Fl o Ar outfile +Specify the output file in which to place the resulting data. +This can be any file pathname. +If +.Ar outfile +is a single dash +.Pq Sq Fl , +the data will be written to the standard output. +The +.Pa if_ndis.c +module expects to find the driver data in a file called +.Pa ndis_driver_data.h , +so it is recommended that this name be used. +.El +.Sh SEE ALSO +.Xr ndis 4 , +.Xr ndisapi 9 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.3 . +.Sh AUTHORS +.An -nosplit +The +.Nm +utility was written by +.An Bill Paul Aq wpaul@windriver.com . +The +.Xr lex 1 +and +.Xr yacc 1 +.Pa INF +file parser was written by +.An Matthew Dodd Aq mdodd@FreeBSD.org . diff --git a/usr.sbin/ndiscvt/ndiscvt.c b/usr.sbin/ndiscvt/ndiscvt.c new file mode 100644 index 0000000000..8599e761c7 --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.c @@ -0,0 +1,290 @@ +/* + * 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. + * + * $DragonFly: src/usr.sbin/ndiscvt/ndiscvt.c,v 1.1 2004/07/30 00:24:24 dillon Exp $ + */ + +#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 in object code files can be sparse. That is, the + * section may occupy more space in memory that it does when + * stored in a disk file. In Windows PE files, each section header + * has a 'virtual size' and 'raw data size' field. The latter + * specifies the amount of section data actually stored in the + * disk file, and the former describes how much space the section + * should actually occupy in memory. If the vsize is larger than + * the rsize, we need to allocate some extra storage and fill + * it with zeros. (Think BSS.) + * + * The typical method of loading an executable file involves + * reading each segment into memory using the vaddr/vsize from + * each section header. We try to make a small optimization however + * and only pad/move segments when it's absolutely necessary, i.e. + * if the vsize is larger than the rsize. This conserves a little + * bit of memory, at the cost of having to fixup some of the values + * in the section headers. + */ + +#define ROUND_UP(x, y) \ + (((x) + (y)) - ((x) % (y))) + +#define SET_HDRS(x) \ + dos_hdr = (image_dos_header *)x; \ + nt_hdr = (image_nt_header *)(x + dos_hdr->idh_lfanew); \ + sect_hdr = (image_section_header *)((vm_offset_t)nt_hdr + \ + sizeof(image_nt_header)); + +static +int insert_padding(imgbase, imglen) + 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, diff, 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++) { + /* + * If we have accumulated any padding offset, + * add it to the raw data address of this segment. + */ + oldraddr = sect_hdr->ish_rawdataaddr; + oldrlen = sect_hdr->ish_rawdatasize; + if (offaccum) + sect_hdr->ish_rawdataaddr += offaccum; + if (sect_hdr->ish_misc.ish_vsize > + sect_hdr->ish_rawdatasize) { + diff = ROUND_UP(sect_hdr->ish_misc.ish_vsize - + sect_hdr->ish_rawdatasize, + opt_hdr.ioh_filealign); + offaccum += ROUND_UP(diff - + (sect_hdr->ish_misc.ish_vsize - + sect_hdr->ish_rawdatasize), + opt_hdr.ioh_filealign); + sect_hdr->ish_rawdatasize = + 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 [-i ] -s " + "[-n devname] [-o outfile]\n", __progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + FILE *fp, *outfp; + void *img; + int n, fsize, cnt; + unsigned char *ptr; + int i; + char *inffile = NULL, *sysfile = NULL, *outfile = NULL; + char *dname = NULL; + int ch; + + while((ch = getopt(argc, argv, "i:s:o:n:")) != -1) { + switch(ch) { + case 'i': + inffile = optarg; + break; + case 's': + sysfile = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'n': + dname = optarg; + break; + default: + usage(); + break; + } + } + + 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); + + 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); + fclose(fp); + } + + fprintf(outfp, "\n#ifdef NDIS_IMAGE\n"); + fprintf(outfp, "\nextern unsigned char drv_data[];\n\n"); + + fprintf(outfp, "__asm__(\".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); +}