diff options
author | wpaul <wpaul@FreeBSD.org> | 2003-12-11 22:38:14 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 2003-12-11 22:38:14 +0000 |
commit | 4b660977b3a9c1a1fc5c78ebbcea353f5051e59f (patch) | |
tree | 7c2d5abaacdb24db0fe7ad5dd49024bfe7023096 /usr.sbin/ndiscvt | |
parent | 7e1ac581496c0d5c9235e96f48e6664b7783122e (diff) | |
download | FreeBSD-src-4b660977b3a9c1a1fc5c78ebbcea353f5051e59f.zip FreeBSD-src-4b660977b3a9c1a1fc5c78ebbcea353f5051e59f.tar.gz |
Commit the ndiscvt(8) utility too. (Missed it in the last import.)
Diffstat (limited to 'usr.sbin/ndiscvt')
-rw-r--r-- | usr.sbin/ndiscvt/Makefile | 23 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf-parse.y | 83 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf-token.l | 91 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf.c | 484 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/inf.h | 61 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndiscvt.8 | 132 | ||||
-rw-r--r-- | usr.sbin/ndiscvt/ndiscvt.c | 264 |
7 files changed, 1138 insertions, 0 deletions
diff --git a/usr.sbin/ndiscvt/Makefile b/usr.sbin/ndiscvt/Makefile new file mode 100644 index 0000000..a54b553 --- /dev/null +++ b/usr.sbin/ndiscvt/Makefile @@ -0,0 +1,23 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../sys/dev/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 <bsd.prog.mk> diff --git a/usr.sbin/ndiscvt/inf-parse.y b/usr.sbin/ndiscvt/inf-parse.y new file mode 100644 index 0000000..05be126 --- /dev/null +++ b/usr.sbin/ndiscvt/inf-parse.y @@ -0,0 +1,83 @@ +%{ +/* + * $Id: inf-parse.y,v 1.3 2003/11/30 21:58:16 winter Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <stdio.h> +#include <sys/types.h> +#include <sys/queue.h> + +#include "inf.h" + +extern int yyparse (void); +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..4f192c5 --- /dev/null +++ b/usr.sbin/ndiscvt/inf-token.l @@ -0,0 +1,91 @@ +%{ +/* + * $Id: inf-token.l,v 1.2 2003/11/30 20:41:06 winter Exp $ + */ + +#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; +#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 '\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..68c18b2 --- /dev/null +++ b/usr.sbin/ndiscvt/inf.c @@ -0,0 +1,484 @@ +/* + * $Id: inf.c,v 1.3 2003/11/30 21:58:16 winter Exp $ + */ + +#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 section + *find_section (const char *); +static void dump_deviceids (void); +static void dump_pci_id (const char *); +static void dump_regvals (void); +static void dump_paramreg (const struct section *, const struct reg *); + +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(); + dump_regvals(); + + 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_pci_id(const char *s) +{ + char *p; + char vidstr[7], didstr[7]; + + 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; + + fprintf(ofp, "\t\\\n\t{ %s, %s,", vidstr, didstr); + return; +} + +static void +dump_deviceids() +{ + struct assign *manf, *dev; + struct section *sec; + struct assign *assign; + + /* Find manufacturer name */ + manf = find_assign("Manufacturer", NULL); + + /* Find manufacturer section */ + sec = find_section(manf->vals[0]); + + /* Emit start of device table */ + fprintf (ofp, "#define NDIS_DEV_TABLE"); + + /* + * 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]); +#ifdef notdef + else if (strcasestr(assign->vals[1], "PCMCIA") != NULL) + dump_pcmcia_id(assign->vals[1]); +#endif + /* Emit device description */ + fprintf (ofp, "\t\\\n\t\"%s\"", dev->vals[0]); + } + } + + /* Emit end of table */ + + fprintf(ofp, " },\n\n"); +} + +static void +dump_addreg(const char *s) +{ + 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\" } },", + reg->value == NULL ? "" : + reg->value); + } else if (strcasestr(reg->subkey, + "Ndi\\params") != NULL && + strcasecmp(reg->key, "ParamDesc") == 0) + dump_paramreg(sec, reg); + } + } + + 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 (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 (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) +{ + struct reg *reg; + TAILQ_FOREACH(reg, &rh, link) { + if (reg->section != s) + continue; + if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey)) + continue; + if (strcasecmp(reg->key, "Default")) + continue; + fprintf(ofp, "\n\t{ \"%s\" } },", reg->value == NULL ? "" : + reg->value); + 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 (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 (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) +{ + 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); + + return; +} + +static void +dump_regvals(void) +{ + struct assign *manf, *dev, *dev_dup; + struct section *sec; + struct assign *assign; + struct assign_head tmp_ah; + char sname[256]; + int i; + + TAILQ_INIT(&tmp_ah); + + /* Find manufacturer name */ + manf = find_assign("Manufacturer", NULL); + + /* Find manufacturer section */ + sec = find_section(manf->vals[0]); + + /* Emit start of block */ + fprintf (ofp, "ndis_cfg ndis_regvals[] = {"); + + TAILQ_FOREACH(assign, &ah, link) { + /* Avoid repeating the same section. */ + i = 0; + TAILQ_FOREACH(dev_dup, &tmp_ah, link) + if (strcmp(dev_dup->vals[0], assign->vals[0]) == 0) { + i++; + break; + } + if (i) + continue; + dev_dup = malloc(sizeof(struct assign)); + bcopy((char *)assign, (char *)dev_dup, + sizeof(struct assign)); + TAILQ_INSERT_TAIL(&tmp_ah, dev_dup, link); + if (assign->section == sec) { + /* Ignore Windows 95-era data. */ + sprintf(sname, "%s.NT", assign->vals[0]); + /* Find all the AddReg sections. */ + dev = find_assign(sname, "AddReg"); + for (i = 0; i < W_MAX; i++) { + if (dev->vals[i] != NULL) + dump_addreg(dev->vals[i]); + } + } + } + + fprintf(ofp, "\n\t{ NULL, NULL, { 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 0000000..8d0b0c1 --- /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 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 0000000..a724fe2 --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.8 @@ -0,0 +1,132 @@ +.\" 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 Windows(r) NDIS drivers for use with FreeBSD +.Sh SYNOPSIS +.Nm +.Op Fl i Ar <inffile> +.Fl s Ar <sysfile> +.Op Fl o Ar <outfile> +.Sh DESCRIPTION +The +.Nm +utility transforms a Windows(r) NDIS driver into a data file which +is used to build an +.Xr ndis 4 +compatibility driver module. Windows(r) drivers consist of two main +parts: a .SYS file, which contains the actual driver executable code, +and a .INF file, which provides the Windows(r) 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 +intoe +.Pa if_ndis.c +to create an object code module that can be linked into +the +.Fx +kernel. +.Pp +The .INF file is typically required since only it contains device +identification data such as PCI vendor and device IDs or PCMCIA +indentifier strings. The .INF file may be optionally omitted however, +in which case the +.Nm +utility will only perform the conversion of the .SYS file. This is +useful for debugging purposes only. +.Pp +.Sh OPTIONS +The options are as follows: +.Bl -tag -width indent +.It Op Fl i Ar <inffile> +Open and parse the specified .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 .SYS file. This file must contain +a Windows(r) 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 Op 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, 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 BUGS +Some Windows(r) drivers support multiple devices which each may +require sets of registry keys. The .INF file format allows all of +these devices to be supported in a single file. The +.Nm +utility will emit keys for all of the devices that it are specified +in a given file, even if this results in some duplicated entries. +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 5.3. +.Sh AUTHORS +The +.Nm +utility was written by +.An Bill Paul Aq wpaul@windriver.com . +The +.Xr lex 1 +and +.Xr yacc 1 +INF file parser was written by +.An Mathew Dodd Aq mdodd@freebsd.org . diff --git a/usr.sbin/ndiscvt/ndiscvt.c b/usr.sbin/ndiscvt/ndiscvt.c new file mode 100644 index 0000000..e307595 --- /dev/null +++ b/usr.sbin/ndiscvt/ndiscvt.c @@ -0,0 +1,264 @@ +/* + * 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 <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <err.h> + +#include <compat/ndis/pe_var.h> + +#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 <inffile>] -s <sysfile> " + "[-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; + int ch; + + while((ch = getopt(argc, argv, "i:s:o")) != -1) { + switch(ch) { + case 'i': + inffile = optarg; + break; + case 's': + sysfile = optarg; + break; + case 'o': + outfile = 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, sysfile, fsize); + fprintf(outfp, " */\n\n"); + + if (fp == NULL) { + fprintf (outfp, "ndis_cfg ndis_regvals[] = {\n"); + fprintf (outfp, "\t{ NULL, NULL, ndis_parm_int, { 0 } }\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\nunsigned char drv_data[] = { \n"); + + ptr = img; + cnt = 0; + while(cnt < fsize) { + for (i = 0; i < 12; i++) { + cnt++; + if (cnt == fsize) { + fprintf(outfp, "0x%.2X\n", ptr[i]); + goto done; + } else + fprintf(outfp, "0x%.2X, ", ptr[i]); + } + fprintf(outfp, "\n"); + ptr += 12; + } + +done: + fprintf(outfp, "};\n"); + + if (fp != NULL) + fclose(fp); + fclose(outfp); + free(img); + exit(0); +} |