diff options
Diffstat (limited to 'usr.sbin/ndiscvt')
-rw-r--r-- | usr.sbin/ndiscvt/Makefile | 29 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/Makefile.depend | 26 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf-parse.y | 110 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf-token.l | 131 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf.c | 916 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf.h | 61 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndiscvt.8 | 283 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndiscvt.c | 432 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndisgen.8 | 86 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndisgen.sh | 559 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/windrv_stub.c | 266 |
11 files changed, 2899 insertions, 0 deletions
diff --git a/usr.sbin/ndiscvt/Makefile b/usr.sbin/ndiscvt/Makefile new file mode 100644 index 0000000..f0facf4 --- /dev/null +++ b/usr.sbin/ndiscvt/Makefile @@ -0,0 +1,29 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../sys/compat/ndis + +PROG= ndiscvt +SRCS= ndiscvt.c +SRCS+= subr_pe.c +SRCS+= inf.c inf-token.l inf-parse.y y.tab.h + +MAN= ndiscvt.8 +MAN+= ndisgen.8 + +WARNS?= 4 +NO_WCAST_ALIGN= + +LIBADD= l + +YFLAGS+=-v + +CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys + +CLEANFILES= y.output + +FILES= windrv_stub.c +FILESDIR= ${SHAREDIR}/misc + +SCRIPTS= ndisgen.sh + +.include <bsd.prog.mk> diff --git a/usr.sbin/ndiscvt/Makefile.depend b/usr.sbin/ndiscvt/Makefile.depend new file mode 100644 index 0000000..f55c806 --- /dev/null +++ b/usr.sbin/ndiscvt/Makefile.depend @@ -0,0 +1,26 @@ +# $FreeBSD$ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + gnu/lib/csu \ + gnu/lib/libgcc \ + include \ + include/xlocale \ + lib/${CSU_DIR} \ + lib/libc \ + lib/libcompiler_rt \ + usr.bin/lex/lib \ + usr.bin/yacc.host \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +inf-parse.o: inf-parse.c +inf-parse.po: inf-parse.c +inf-token.o: inf-token.c +inf-token.o: y.tab.h +inf-token.po: inf-token.c +inf-token.po: y.tab.h +.endif diff --git a/usr.sbin/ndiscvt/inf-parse.y b/usr.sbin/ndiscvt/inf-parse.y new file mode 100644 index 0000000..2a8876d --- /dev/null +++ b/usr.sbin/ndiscvt/inf-parse.y @@ -0,0 +1,110 @@ +%{ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <sys/types.h> +#include <sys/queue.h> + +#include "inf.h" + +extern int yylex (void); +extern void yyerror(const char *); +%} + +%token EQUALS COMMA EOL +%token <str> SECTION +%token <str> STRING +%token <str> 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 0000000..3e2a127 --- /dev/null +++ b/usr.sbin/ndiscvt/inf-token.l @@ -0,0 +1,131 @@ +%{ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <regex.h> +#include <ctype.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "y.tab.h" + +int lineno = 1; + +int yylex(void); +void yyerror(const char *); + +static void +update_lineno(const char *cp) +{ + while (*cp) + if (*cp++ == '\n') + lineno++; +} + +%} + +%option nounput +%option noinput + +%% + +[ \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 0000000..4b30da0 --- /dev/null +++ b/usr.sbin/ndiscvt/inf.c @@ -0,0 +1,916 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <sys/queue.h> + +#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 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(); + 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 +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; +} + +static void +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; +} + +static void +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; +} + +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; +} diff --git a/usr.sbin/ndiscvt/inf.h b/usr.sbin/ndiscvt/inf.h new file mode 100644 index 0000000..ba08d67 --- /dev/null +++ b/usr.sbin/ndiscvt/inf.h @@ -0,0 +1,61 @@ +/* + * $Id: inf.h,v 1.3 2003/11/30 21:58:16 winter Exp $ + * + * $FreeBSD$ + */ + +#define W_MAX 32 + +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 0000000..f497495 --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.8 @@ -0,0 +1,283 @@ +.\" Copyright (c) 2003 +.\" Bill Paul <wpaul@windriver.com> 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$ +.\" +.Dd December 10, 2003 +.Dt NDISCVT 8 +.Os +.Sh NAME +.Nm ndiscvt +.Nd convert +.Tn Windows\[rg] +NDIS drivers for use with FreeBSD +.Sh SYNOPSIS +.Nm +.Op Fl O +.Op Fl i Ar inffile +.Fl s Ar sysfile +.Op Fl n Ar devname +.Op Fl o Ar outfile +.Nm +.Op Fl f Ar firmfile +.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 +identifier 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. +.It Fl O +Generate both an +.Pa ndis_driver_data.h +file and +an +.Pa ndis_driver.data.o +file. +The latter file will contain a copy of the +.Tn Windows\[rg] +.Pa .SYS +driver image encoded as a +.Fx +ELF object file +(created with +.Xr objcopy 1 ) . +Turning the +.Tn Windows\[rg] +driver image directly into an object code file saves disk space +and compilation time. +.It Fl f Ar firmfile +A few NDIS drivers come with additional files that the core +driver module will load during initialization time. +Typically, +these files contain firmware which the driver will transfer to +the device in order to make it fully operational. +In +.Tn Windows\[rg] , +these files are usually just copied into one of the system +directories along with the driver itself. +.Pp +In +.Fx +there are two mechanism for loading these files. +If the driver +is built as a loadable kernel module which is loaded after the +kernel has finished booting +(and after the root file system has +been mounted), +the extra files can simply be copied to the +.Pa /compat/ndis +directory, and they will be loaded into the kernel on demand when the +driver needs them. +.Pp +If however the driver is required to bootstrap the system +(i.e., if +the NDIS-based network interface is to be used for diskless/PXE +booting), +the files need to be pre-loaded by the bootstrap +loader in order to be accessible, since the driver will need them +before the root file system has been mounted. +However, the bootstrap +loader is only able to load files that are shared +.Fx +binary objects. +.Pp +The +.Fl f +flag can be used to convert an arbitrary file +.Ar firmfile +into shared object format +(the actual conversion is done using +the +.Xr objcopy 1 +and +.Xr ld 1 +commands). +The resulting files can then be copied to the +.Pa /boot/kernel +directory, and can be pre-loaded directly from the boot loader +prompt, or automatically by editing the +.Xr loader.conf 5 +file. +If desired, the files can also be loaded into memory +at runtime using the +.Xr kldload 8 +command. +.Pp +When an NDIS driver tries to open an external file, the +.Xr ndisapi 9 +code will first search for a loaded kernel module that matches the +name specified in the open request, and if that fails, it will then +try to open the file from the +.Pa /compat/ndis +directory as well. +Note that during kernel bootstrap, the ability +to open files from +.Pa /compat/ndis +is disabled: only the module search will be performed. +.Pp +When using the +.Fl f +flag, +.Nm +will generate both a relocatable object file +(with a +.Pa .o +extension) +and a shared object file +(with a +.Pa .ko +extension). +The shared object is the one that should be placed in +the +.Pa /boot/kernel +directory. +The relocatable object file is useful if the user wishes +to create a completely static kernel image: the object file can be +linked into the kernel directly along with the driver itself. +Some +editing of the kernel configuration files will be necessary in order +to have the extra object included in the build. +.El +.Sh SEE ALSO +.Xr ld 1 , +.Xr objcopy 1 , +.Xr ndis 4 , +.Xr kldload 8 +.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 Mt wpaul@windriver.com . +The +.Xr lex 1 +and +.Xr yacc 1 +.Pa INF +file parser was written by +.An Matthew Dodd Aq Mt mdodd@FreeBSD.org . diff --git a/usr.sbin/ndiscvt/ndiscvt.c b/usr.sbin/ndiscvt/ndiscvt.c new file mode 100644 index 0000000..7636c4c --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.c @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2003 + * Bill Paul <wpaul@windriver.com>. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <net/if.h> +#include <stdlib.h> +#include <stddef.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <libgen.h> +#include <err.h> +#include <ctype.h> + +#include <compat/ndis/pe_var.h> + +#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 <inffile>] -s <sysfile> " + "[-n devname] [-o outfile]\n", __progname); + fprintf(stderr, " %s -f <firmfile>\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); + + 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 ? "<notused>" : 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"); + + 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); +} diff --git a/usr.sbin/ndiscvt/ndisgen.8 b/usr.sbin/ndiscvt/ndisgen.8 new file mode 100644 index 0000000..2fb4f40 --- /dev/null +++ b/usr.sbin/ndiscvt/ndisgen.8 @@ -0,0 +1,86 @@ +.\" Copyright (c) 2005 +.\" Bill Paul <wpaul@windriver.com> 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$ +.\" +.Dd April 24, 2005 +.Dt NDISGEN 8 +.Os +.Sh NAME +.Nm ndisgen +.Nd generate a FreeBSD driver module from a +.Tn Windows\[rg] +NDIS driver distribution +.Sh SYNOPSIS +.Nm +.Op Ar /path/to/INF /path/to/SYS +.Sh DESCRIPTION +The +.Nm +script uses the +.Xr ndiscvt 8 +utility and other tools to generate a +.Fx +loadable driver module +and a static ELF object module from a +.Tn Windows\[rg] +NDIS driver, for use with the +.Xr ndis 4 +compatibility module. +.Pp +The +.Nm +script is interactive and contains its own help section. +Unless the paths to both files are supplied on the command line, +the script will prompt the user for the +.Pa .INF +and +.Pa .SYS +files needed to generate the +.Fx +driver module. +The script will also prompt for +any firmware or other external files needed. +.Sh SEE ALSO +.Xr ld 1 , +.Xr objcopy 1 , +.Xr ndis 4 , +.Xr kldload 8 , +.Xr ndiscvt 8 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 6.0 . +.Sh AUTHORS +The +.Nm +utility was written by +.An Bill Paul Aq Mt wpaul@windriver.com . diff --git a/usr.sbin/ndiscvt/ndisgen.sh b/usr.sbin/ndiscvt/ndisgen.sh new file mode 100644 index 0000000..97e8364 --- /dev/null +++ b/usr.sbin/ndiscvt/ndisgen.sh @@ -0,0 +1,559 @@ +#!/bin/sh +# +# Copyright (c) 2005 +# Bill Paul <wpaul@windriver.com>. 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$ +# + +header () { +clear +echo " ==================================================================" +echo " ------------------ Windows(r) driver converter -------------------" +echo " ==================================================================" +echo "" +} + +mainmenu() { +header +echo " This script is designed to guide you through the process" +echo " of converting a Windows(r) binary driver module and .INF" +echo " specification file into a FreeBSD ELF kernel module for use" +echo " with the NDIS compatibility system." +echo "" +echo " The following options are available:" +echo "" +echo " 1] Learn about the NDIS compatibility system" +echo " 2] Convert individual firmware files" +echo " 3] Convert driver" +echo " 4] Exit" +echo "" +echo -n " Enter your selection here and press return: " +read KEYPRESS +return +} + + +help1 () { +header +echo " General information" +echo "" +echo " The NDIS compatibility system is designed to let you use Windows(r)" +echo " binary drivers for networking devices with FreeBSD, in cases where" +echo " a native FreeBSD driver is not available due to hardware manufacturer" +echo " oversight or stupidity. NDIS stands for Network Driver Interface" +echo " Standard, and refers to the programming model used to write Windows(r)" +echo " network drivers. (These are often called \"NDIS miniport\" drivers.)" +echo "" +echo " In order to use your network device in NDIS compatibility mode," +echo " you need the Windows(r) driver that goes with it. Also, the driver" +echo " must be compiled for the same architecture as the release of FreeBSD" +echo " you have installed. At this time, the i386 and amd64 architectures" +echo " are both supported. Note that you cannot use a Windows/i386 driver" +echo " with FreeBSD/amd64: you must obtain a Windows/amd64 driver." +echo "" +echo -n " Press return to continue... " +read KEYPRESS +return +} + +help2() { +header +echo " Where to get drivers" +echo "" +echo " If you purchased your network card separately from your computer," +echo " there should have been a driver distribution CD included with the" +echo " card which contains Windows(r) drivers. The NDIS compatibility" +echo " system is designed to emulate the NDIS API of a couple of different" +echo " Windows(r) releases, however it works best with drivers designed" +echo " for NDIS 5.0 or later. Drivers distributed for Windows 2000 should" +echo " work; however, for best results you should use a driver designed" +echo " for Windows XP or Windows Server 2003." +echo "" +echo " If your card was supplied with your computer, or is a built-in device," +echo " drivers may have been included on a special driver bundle CD shipped" +echo " with the computer." +echo "" +echo " If you don't have a driver CD, you should be able to find a driver" +echo " kit on the card or computer vendor's web site." +echo "" +echo -n " Press return to continue... " +read KEYPRESS +return +} + +help3 () { +header +echo " What files do I need?" +echo "" +echo " In most cases, you will need only two files: a .INF file and a .SYS" +echo " file. The .INF file is a text file used by the Windows(r) installer to" +echo " perform the driver installation. It contains information that tells" +echo " the installer what devices the driver supports and what registry keys" +echo " should be created to control driver configuration. The .SYS file" +echo " is the actual driver executable code in Windows(r) Portable Executable" +echo " (PE) format. Note that sometimes the .INF file is supplied in Unicode" +echo " format. Unicode .INF files must be converted to ASCII form with the" +echo " iconv(1) utility before this installer script can use them." +echo " Occasionally, a driver may require firmware or register setup" +echo " files that are external to the main .SYS file. These are provided" +echo " on the same CD with the driver itself, and sometimes have a .BIN" +echo " extension, though they can be named almost anything. You will need" +echo " these additional files to make your device work with the NDIS" +echo " compatibility system as well." +echo "" +echo -n " Press return to continue... " +read KEYPRESS +return +} + +help4 () { +header +echo " How does it all work?" +echo "" +echo " The installer script uses the ndiscvt(1) utility to convert the .INF," +echo " .SYS and optional firmware files into a FreeBSD kernel loadable module" +echo " (.ko) file. This module can be loaded via the kldload(8) utility or" +echo " loaded automatically via the /boot/loader.conf file. The ndiscvt(1)" +echo " utility extracts the device ID information and registry key data" +echo " from the .INF file and converts it into a C header file. It also uses" +echo " the objcopy(1) utility to convert the .SYS file and optional firmware" +echo " files into ELF objects. The header file is compiled into a small C" +echo " stub file which contains a small amount of code to interface with" +echo " the FreeBSD module system. This stub is linked together with the" +echo " converted ELF objects to form a FreeBSD kernel module. A static ELF" +echo " object (.o) file is also created. This file can be linked into a" +echo " static kernel image for those who want/need a fully linked kernel" +echo " image (possibly for embedded bootstrap purposes, or just plain old" +echo " experimentation)." +echo "" +echo -n " Press return to continue... " +read KEYPRESS +return +} + +help5 () { +header +echo " Prerequisites" +echo "" +echo " Converting a driver requires the following utilities:" +echo "" +echo " - The FreeBSD C compiler, cc(1) (part of the base install)." +echo " - The FreeBSD linker, ld(1) (part of the base install)." +echo " - The objcopy(1) utility (part of the base install)." +echo " - The ndiscvt(1) utility (part of the base install)." +echo "" +echo " If you happen to end up with a .INF file that's in Unicode format," +echo " then you'll also need:" +echo "" +echo " - The iconv(1) utility." +echo "" +echo " If you have installed the X Window system or some sort of desktop" +echo " environment, then iconv(1) should already be present. If not, you" +echo " will need to install the libiconv package or port." +echo "" +echo -n " Press return to continue... " +read KEYPRESS +return +} + +infconv () { +header +echo " INF file validation" + +if [ -z "$INFPATH" ]; then + echo "" + echo "" + echo " A .INF file is most often provided as an ASCII file, however" + echo " files with multilanguage support are provided in Unicode format." + echo " Please type in the path to your .INF file now." + echo "" + echo -n " > " + read INFPATH +fi + +if [ ${INFPATH} ] && [ -e ${INFPATH} ]; then + INFTYPE=`${EGREP} -i -c "Signature|.S.i.g.n.a.t.u.r.e" ${INFPATH}` + if [ ${INFTYPE} -le 0 ]; then + echo "" + echo " I don't recognize this file format. It may not be a valid .INF file." + echo "" + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + INFPATH="" + return + fi + + INFTYPE=`${EGREP} -i -c "Class.*=.*Net" ${INFPATH}` + if [ ${INFTYPE} -gt 0 ]; then + echo "" + echo " This .INF file appears to be ASCII." + echo "" + echo -n " Press return to continue... " + read KEYPRESS + return + fi + + INFTYPE=`${EGREP} -i -c ".C.l.a.s.s.*=.*N.e.t" ${INFPATH}` + if [ ${INFTYPE} -gt 0 ]; then + echo "" + echo " This .INF file appears to be Unicode." + if [ -e ${ICONVPATH} ]; then + echo " Trying to convert to ASCII..." + ${ICONVPATH} -f utf-16 -t utf-8 ${INFPATH} > ${INFFILE} + INFPATH=${INFFILE} + echo " Done." + echo "" + echo -n " Press return to continue... " + read KEYPRESS + else + echo " The iconv(1) utility does not appear to be installed." + echo " Please install this utility or convert the .INF file" + echo " to ASCII and run this utility again." + echo "" + exit + fi + return + fi + + echo "" + echo " I don't recognize this file format. It may not be a valid .INF file." + echo "" + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + INFPATH="" +else + echo "" + echo " The file '${INFPATH}' was not found." + echo "" + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + INFPATH="" +fi +return +} + +sysconv() { +header +echo " Driver file validation" + +if [ ! -r "$SYSPATH" ]; then + echo "" + echo "" + echo " Now you need to specify the name of the Windows(r) driver .SYS" + echo " file for your device. Note that if you are running FreeBSD/amd64," + echo " then you must provide a driver that has been compiled for the" + echo " 64-bit Windows(r) platform. If a 64-bit driver is not available" + echo " for your device, you must install FreeBSD/i386 and use the" + echo " 32-bit driver instead." + echo "" + echo " Please type in the path to the Windows(r) driver .SYS file now." + echo "" + echo -n " > " + read SYSPATH +fi + +if [ ${SYSPATH} ] && [ -e ${SYSPATH} ]; then + SYSTYPE=`${FILE} ${SYSPATH}` + + case ${SYSTYPE} in + *Windows*) + echo "" + echo " This .SYS file appears to be in Windows(r) PE format." + echo "" + echo -n " Press return to continue... " + read KEYPRESS + SYSBASE=`${BASENAME} ${SYSPATH} | ${TR} '.' '_'` + ;; + *) + echo "" + echo " I don't recognize this file format. It may not be a valid .SYS file." + echo "" + + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + SYSPATH="" + ;; + esac +else + echo "" + echo " The file '${SYSPATH}' was not found." + echo "" + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + SYSPATH="" +fi +return +} + +ndiscvt() { +header +echo " Driver file conversion" +echo "" +echo " The script will now try to convert the .INF and .SYS files" +echo " using the ndiscvt(1) utility. This utility can handle most" +echo " .INF files; however, occasionally it can fail to parse some files" +echo " due to subtle syntax issues: the .INF syntax is very complex," +echo " and the Windows(r) parser will sometimes allow files with small" +echo " syntax errors to be processed correctly which ndiscvt(1) will" +echo " not. If the conversion fails, you may have to edit the .INF" +echo " file by hand to remove the offending lines." +echo "" +echo -n " Press enter to try converting the files now: " +read KEYPRESS +if ! ${NDISCVT} -i ${INFPATH} -s ${SYSPATH} -O -o ${DNAME}.h > /dev/null; then + echo "CONVERSION FAILED" + exit +else + echo "" + echo " Conversion was successful." + echo "" + echo -n " Press enter to continue... " + read KEYPRESS +fi +return +} + +firmcvt() { + while : ; do +header +echo " Firmware file conversion" +echo "" +echo " If your driver uses additional firmware files, please list them" +echo " below. When you're finished, just press enter to continue. (If your" +echo " driver doesn't need any extra firmware files, just press enter" +echo " to move to the next step.)" +echo "" + echo -n " > " + read FIRMPATH + + if [ ${FIRMPATH} ]; then + if [ ! -e ${FIRMPATH} ]; then + echo "" + echo " The file '${FIRMPATH}' was not found" + echo "" + echo -n " Press enter to try again, or ^C to quit. " + read KEYPRESS + continue + fi + if ! ${NDISCVT} -f ${FIRMPATH} > /dev/null; then + echo "" + echo "CONVERSION FAILED" + else + echo "" + echo " Conversion was successful." + echo "" + FRMBASE=`${BASENAME} ${FIRMPATH}` + FRMBASE="${FRMBASE}.o" + FRMLIST="${FRMLIST} ${FRMBASE}" + fi + echo -n " Press enter to continue... " + read KEYPRESS + else + break + fi + done + +header +echo "" +echo " List of files converted firmware files:" +echo "" +for i in ${FRMLIST} +do + echo " "$i +done +echo "" +echo -n " Press enter to continue... " +read KEYPRESS +return +} + +drvgen () { +header +echo " Kernel module generation" +echo "" +echo "" +echo " The script will now try to generate the kernel driver module." +echo " This is the last step. Once this module is generated, you should" +echo " be able to load it just like any other FreeBSD driver module." +echo "" +echo " Press enter to compile the stub module and generate the driver" +echo -n " module now: " +read KEYPRESS +echo "" +echo -n " Generating Makefile... " +echo ".PATH: ${PWD} ${STUBPATH}" > ${MAKEFILE} +echo "KMOD= ${SYSBASE}" >> ${MAKEFILE} +echo "SRCS+= ${STUBFILE} ${DNAME}.h bus_if.h device_if.h" >> ${MAKEFILE} +echo "OBJS+=${FRMLIST} ${DNAME}.o" >> ${MAKEFILE} +echo "CFLAGS+= \\" >> ${MAKEFILE} +echo " -DDRV_DATA_START=ndis_${SYSBASE}_drv_data_start \\" >> ${MAKEFILE} +echo " -DDRV_NAME=ndis_${SYSBASE} \\" >> ${MAKEFILE} +echo " -DDRV_DATA_END=ndis_${SYSBASE}_drv_data_end" >> ${MAKEFILE} +echo "CLEANFILES+= \\" >> ${MAKEFILE} +echo " ${INFFILE} \\" >> ${MAKEFILE} +echo " ${DNAME}.h \\" >> ${MAKEFILE} +echo " ${DNAME}.o" >> ${MAKEFILE} +echo ".include <bsd.kmod.mk>" >> ${MAKEFILE} +if [ -f ${MAKEFILE} ]; then + echo "done." +else + echo "generating Makefile failed. Exiting." + echo "" + exit +fi +echo -n " Building kernel module... " +echo "" > bus_if.h +echo "" > device_if.h +if ! ${MAKE} -f ${MAKEFILE} depend > /dev/null; then + echo "build failed. Exiting." + echo "" + exit +fi +if ! ${MAKE} -f ${MAKEFILE} all > /dev/null; then + echo "build failed. Exiting." + echo "" + exit +else + if [ -f ${SYSBASE}.ko ]; then + ${MV} ${SYSBASE}.ko ${SYSBASE}.kmod + echo "done." + else + echo "build failed. Exiting." + echo "" + exit + fi +fi +echo -n " Cleaning up... " +if ! ${MAKE} -f ${MAKEFILE} clean cleandepend > /dev/null; then + echo "cleanup failed. Exiting." + echo "" + exit +else + echo "done." +fi +${RM} ${MAKEFILE} +${MV} ${SYSBASE}.kmod ${SYSBASE}.ko +echo "" +echo " The file ${SYSBASE}.ko has been successfully generated." +echo " You can kldload this module to get started." +echo "" +echo -n " Press return to exit. " +read KEYPRESS +echo "" +echo "" +return +} + +convert_driver () { + while : ; do + infconv + if [ ${INFPATH} ]; then + break + fi + done + + while : ; do + sysconv + if [ ${SYSPATH} ]; then + break + fi + done + + ndiscvt + firmcvt + drvgen + return +} + +ICONVPATH=/usr/bin/iconv +NDISCVT=/usr/sbin/ndiscvt +STUBPATH=/usr/share/misc +STUBFILE=windrv_stub.c +DNAME=windrv +CP=/bin/cp +MV=/bin/mv +RM=/bin/rm +TR=/usr/bin/tr +FILE=/usr/bin/file +EGREP=/usr/bin/egrep +MAKE=/usr/bin/make +BASENAME=/usr/bin/basename +TOUCH=/usr/bin/touch +MKTEMP=/usr/bin/mktemp + +MAKEFILE=`${MKTEMP} /tmp/Makefile.XXXXXX` +INFFILE=`${MKTEMP} /tmp/ascii_inf.XXXXXX` + +INFPATH="" +FRMLIST="" +SYSPATH="" +SYSBASE="" +FRMBASE="" + +if [ -r "$1" -a -r "$2" ]; then + # Looks like the user supplied .INF and .SYS files on the command line + INFPATH=$1 + SYSPATH=$2 + convert_driver && exit 0 +fi + +while : ; do + mainmenu + case ${KEYPRESS} in + 1) + help1 + help2 + help3 + help4 + help5 + ;; + 2) + firmcvt + ;; + 3) + convert_driver + ;; + 4) + header + echo "" + echo " Be seeing you!" + echo "" + exit + ;; + *) + header + echo "" + echo -n " Sorry, I didn't understand that. Press enter to try again: " + read KEYPRESS + ;; + esac +done +exit diff --git a/usr.sbin/ndiscvt/windrv_stub.c b/usr.sbin/ndiscvt/windrv_stub.c new file mode 100644 index 0000000..46a0e83 --- /dev/null +++ b/usr.sbin/ndiscvt/windrv_stub.c @@ -0,0 +1,266 @@ +/*- + * Copyright (c) 2005 + * Bill Paul <wpaul@windriver.com>. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#define NDIS_REGVALS + +struct ndis_cfg { + char *nc_cfgkey; + char *nc_cfgdesc; + char nc_val[256]; + int nc_idx; +}; + +typedef struct ndis_cfg ndis_cfg; + +#include "windrv.h" + +struct ndis_pci_type { + uint16_t ndis_vid; + uint16_t ndis_did; + uint32_t ndis_subsys; + char *ndis_name; +}; + +struct ndis_pccard_type { + const char *ndis_vid; + const char *ndis_did; + char *ndis_name; +}; + +struct ndis_usb_type { + uint16_t ndis_vid; + uint16_t ndis_did; + char *ndis_name; +}; + +#ifdef NDIS_PCI_DEV_TABLE +static struct ndis_pci_type ndis_devs_pci[] = { + NDIS_PCI_DEV_TABLE + { 0, 0, 0, NULL } +}; +#endif + +#ifdef NDIS_PCMCIA_DEV_TABLE +static struct ndis_pccard_type ndis_devs_pccard[] = { + NDIS_PCMCIA_DEV_TABLE + { NULL, NULL, NULL } +}; +#endif + +#ifdef NDIS_USB_DEV_TABLE +static struct ndis_usb_type ndis_devs_usb[] = { + NDIS_USB_DEV_TABLE + { 0, 0, NULL } +}; +#endif + +enum interface_type { + InterfaceTypeUndefined = -1, + Internal, + Isa, + Eisa, + MicroChannel, + TurboChannel, + PCIBus, + VMEBus, + NuBus, + PCMCIABus, + CBus, + MPIBus, + MPSABus, + ProcessorInternal, + InternalPowerBus, + PNPISABus, + PNPBus, + MaximumInterfaceType +}; + +typedef enum interface_type interface_type; + +/* + * XXX + * Ordinarily, device_probe_desc is defined in device_if.h, which + * is created from device_if.m. The problem is, the latter file + * is only available if you have the kernel source code installed, + * and not all users choose to install it. I'd like to let people + * load Windows driver modules with the minimal amount of hassle + * and dependencies. <sys/bus.h> wants both device_if.h and bus_if.h + * to be defined, but it turns out the only thing we really need + * to get this module compiled is device_probe_desc, so we define + * that here, and let the build script create empty copies of + * device_if.h and bus_if.h to make the compiler happy. + */ + +extern struct kobjop_desc device_probe_desc; +typedef int device_probe_t(device_t dev); + +extern int windrv_load(module_t, vm_offset_t, size_t, + interface_type, void *, void *); +extern int windrv_unload(module_t, vm_offset_t, size_t); + +#ifndef DRV_DATA_START +#define DRV_DATA_START UNDEF_START +#endif + +#ifndef DRV_DATA_END +#define DRV_DATA_END UNDEF_END +#endif + +#ifndef DRV_NAME +#define DRV_NAME UNDEF_NAME +#endif + +extern uint8_t DRV_DATA_START; +extern uint8_t DRV_DATA_END; + +/* + * The following is stub code that makes it look as though we want + * to be a child device of all the buses that our supported devices + * might want to attach to. Our probe routine always fails. The + * reason we need this code is so that loading an ELF-ified Windows + * driver module will trigger a bus reprobe. + */ + +#define MODULE_DECL(x) \ + MODULE_DEPEND(x, ndisapi, 1, 1, 1); \ + MODULE_DEPEND(x, ndis, 1, 1, 1) + +MODULE_DECL(DRV_NAME); + +static int windrv_probe(device_t); +static int windrv_modevent(module_t, int, void *); +static int windrv_loaded = 0; + +static device_method_t windrv_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, windrv_probe), + + { 0, 0 } +}; + +static driver_t windrv_driver = { + "windrv_stub", + windrv_methods, + 0 +}; + +static devclass_t windrv_devclass; + +#define DRIVER_DECL(x) \ + DRIVER_MODULE(x, pci, windrv_driver, \ + windrv_devclass, windrv_modevent, NULL); \ + DRIVER_MODULE(x, cardbus, windrv_driver, \ + windrv_devclass, windrv_modevent, NULL); \ + DRIVER_MODULE(x, pccard, windrv_driver, \ + windrv_devclass, windrv_modevent, NULL); \ + DRIVER_MODULE(x, uhub, windrv_driver, \ + windrv_devclass, windrv_modevent, NULL); \ + MODULE_VERSION(x, 1) + +DRIVER_DECL(DRV_NAME); + +static int +windrv_probe(dev) + device_t dev; +{ + return (ENXIO); +} + +static int +windrv_modevent(mod, cmd, arg) + module_t mod; + int cmd; + void *arg; +{ + int drv_data_len; + int error = 0; + vm_offset_t drv_data_start; + vm_offset_t drv_data_end; + + drv_data_start = (vm_offset_t)&DRV_DATA_START; + drv_data_end = (vm_offset_t)&DRV_DATA_END; + + drv_data_len = drv_data_end - drv_data_start; + switch (cmd) { + case MOD_LOAD: + windrv_loaded++; + if (windrv_loaded > 1) + break; +#ifdef NDIS_PCI_DEV_TABLE + windrv_load(mod, drv_data_start, drv_data_len, PCIBus, + ndis_devs_pci, &ndis_regvals); +#endif +#ifdef NDIS_PCMCIA_DEV_TABLE + windrv_load(mod, drv_data_start, drv_data_len, PCMCIABus, + ndis_devs_pccard, &ndis_regvals); +#endif +#ifdef NDIS_USB_DEV_TABLE + windrv_load(mod, drv_data_start, drv_data_len, PNPBus, + ndis_devs_usb, &ndis_regvals); +#endif + break; + case MOD_UNLOAD: + windrv_loaded--; + if (windrv_loaded > 0) + break; +#ifdef NDIS_PCI_DEV_TABLE + windrv_unload(mod, drv_data_start, drv_data_len); +#endif +#ifdef NDIS_PCMCIA_DEV_TABLE + windrv_unload(mod, drv_data_start, drv_data_len); +#endif +#ifdef NDIS_USB_DEV_TABLE + windrv_unload(mod, drv_data_start, drv_data_len); +#endif + break; + case MOD_SHUTDOWN: + break; + default: + error = EINVAL; + break; + } + + return (error); +} |