summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ndiscvt
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ndiscvt')
-rw-r--r--usr.sbin/ndiscvt/Makefile23
-rw-r--r--usr.sbin/ndiscvt/inf-parse.y83
-rw-r--r--usr.sbin/ndiscvt/inf-token.l91
-rw-r--r--usr.sbin/ndiscvt/inf.c484
-rw-r--r--usr.sbin/ndiscvt/inf.h61
-rw-r--r--usr.sbin/ndiscvt/ndiscvt.8132
-rw-r--r--usr.sbin/ndiscvt/ndiscvt.c264
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);
+}
OpenPOWER on IntegriCloud