Add the ndiscvt utility from FreeBSD-5, which is used to compile windows
authorMatthew Dillon <dillon@dragonflybsd.org>
Fri, 30 Jul 2004 00:24:24 +0000 (00:24 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Fri, 30 Jul 2004 00:24:24 +0000 (00:24 +0000)
device drivers for NDIS.

usr.sbin/Makefile
usr.sbin/ndiscvt/Makefile [new file with mode: 0644]
usr.sbin/ndiscvt/inf-parse.y [new file with mode: 0644]
usr.sbin/ndiscvt/inf-token.l [new file with mode: 0644]
usr.sbin/ndiscvt/inf.c [new file with mode: 0644]
usr.sbin/ndiscvt/inf.h [new file with mode: 0644]
usr.sbin/ndiscvt/ndiscvt.8 [new file with mode: 0644]
usr.sbin/ndiscvt/ndiscvt.c [new file with mode: 0644]

index 4e30c55..095fbda 100644 (file)
@@ -1,6 +1,6 @@
 #      From: @(#)Makefile      5.20 (Berkeley) 6/12/93
 # $FreeBSD: src/usr.sbin/Makefile,v 1.183.2.14 2003/04/16 11:01:51 ru Exp $
-# $DragonFly: src/usr.sbin/Makefile,v 1.11 2004/07/05 00:22:39 dillon Exp $
+# $DragonFly: src/usr.sbin/Makefile,v 1.12 2004/07/30 00:24:22 dillon Exp $
 
 # XXX MISSING:         mkproto
 SUBDIR=        IPXrouted \
@@ -54,6 +54,7 @@ SUBDIR=       IPXrouted \
        mrouted \
        mtest \
        mtree \
+       ndiscvt \
        ndp \
        newsyslog \
        ngctl \
diff --git a/usr.sbin/ndiscvt/Makefile b/usr.sbin/ndiscvt/Makefile
new file mode 100644 (file)
index 0000000..b372a3d
--- /dev/null
@@ -0,0 +1,24 @@
+# $FreeBSD: src/usr.sbin/ndiscvt/Makefile,v 1.5 2004/02/23 20:21:21 johan Exp $
+# $DragonFly: src/usr.sbin/ndiscvt/Makefile,v 1.1 2004/07/30 00:24:24 dillon Exp $
+
+.PATH: ${.CURDIR}/../../sys/emulation/ndis
+
+PROG=  ndiscvt
+SRCS=  ndiscvt.c
+SRCS+= subr_pe.c
+SRCS+= inf.c inf-token.l inf-parse.y y.tab.h
+
+MAN8=  ndiscvt.8
+
+WARNS?=        4
+
+DPADD=  ${LIBL}
+LDADD=  -ll
+
+YFLAGS+=-v
+
+CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys
+
+CLEANFILES= y.output
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ndiscvt/inf-parse.y b/usr.sbin/ndiscvt/inf-parse.y
new file mode 100644 (file)
index 0000000..5baedba
--- /dev/null
@@ -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.
+ *
+ * $DragonFly: src/usr.sbin/ndiscvt/inf-parse.y,v 1.1 2004/07/30 00:24:24 dillon Exp $
+ */
+
+#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 (file)
index 0000000..e244b2e
--- /dev/null
@@ -0,0 +1,129 @@
+%{
+/*
+ * 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.
+ *
+ * $DragonFly: src/usr.sbin/ndiscvt/inf-token.l,v 1.1 2004/07/30 00:24:24 dillon Exp $
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.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 '\"':
+                                               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 (file)
index 0000000..b9ed8e6
--- /dev/null
@@ -0,0 +1,724 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/usr.sbin/ndiscvt/inf.c,v 1.1 2004/07/30 00:24:24 dillon Exp $
+ */
+
+#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_pci      (void);
+static void    dump_deviceids_pcmcia   (void);
+static void    dump_pci_id     (const char *);
+static void    dump_pcmcia_id  (const char *);
+static void    dump_regvals    (void);
+static void    dump_paramreg   (const struct section *,
+                               const struct reg *, int);
+
+static FILE    *ofp;
+
+int
+inf_parse (FILE *fp, FILE *outfp)
+{
+       TAILQ_INIT(&sh);
+       TAILQ_INIT(&rh);
+       TAILQ_INIT(&ah);
+
+       ofp = outfp;
+       yyin = fp;
+       yyparse();
+
+       dump_deviceids_pci();
+       dump_deviceids_pcmcia();
+       fprintf(outfp, "#ifdef NDIS_REGVALS\n");
+       dump_regvals();
+       fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
+
+       return (0);
+}
+
+void
+section_add (const char *s)
+{
+       struct section *sec;
+
+       sec = malloc(sizeof(struct section));
+       bzero(sec, sizeof(struct section));
+       sec->name = s;
+       TAILQ_INSERT_TAIL(&sh, sec, link);
+
+       return;
+}
+
+static struct assign *
+find_assign (const char *s, const char *k)
+{
+       struct assign *assign;
+       char newkey[256];
+
+       /* Deal with string section lookups. */
+
+       if (k != NULL && k[0] == '%') {
+               bzero(newkey, sizeof(newkey));
+               strncpy(newkey, k + 1, strlen(k) - 2);
+               k = newkey;
+       }
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (strcasecmp(assign->section->name, s) == 0) {
+                       if (k == NULL)
+                               return(assign);
+                       else
+                               if (strcasecmp(assign->key, k) == 0)
+                                       return(assign);
+               }
+       }
+       return(NULL);
+}
+
+static const char *
+stringcvt(const char *s)
+{
+       struct assign *manf;
+
+       manf = find_assign("strings", s);
+       if (manf == NULL)
+               return(s);
+       return(manf->vals[0]);
+}
+
+struct section *
+find_section (const char *s)
+{
+       struct section *section;
+
+       TAILQ_FOREACH(section, &sh, link) {
+               if (strcasecmp(section->name, s) == 0)
+                       return(section);
+       }
+       return(NULL);
+}
+
+static void
+dump_pcmcia_id(const char *s)
+{
+       char *manstr, *devstr;
+       char *p0, *p;
+
+       p0 = __DECONST(char *, s);
+
+       p = strchr(p0, '\\');
+       if (p == NULL)
+               return;
+       p0 = p + 1;
+
+       p = strchr(p0, '-');
+       if (p == NULL)
+               return;
+       *p = '\0';
+
+       manstr = p0;
+
+       /* Convert any underscores to spaces. */
+
+       while (*p0 != '\0') {
+               if (*p0 == '_')
+                       *p0 = ' ';
+               p0++;
+       }
+
+       p0 = p + 1;
+       p = strchr(p0, '-');
+       if (p == NULL)
+               return;
+       *p = '\0';
+
+       devstr = p0;
+
+       /* Convert any underscores to spaces. */
+
+       while (*p0 != '\0') {
+               if (*p0 == '_')
+                       *p0 = ' ';
+               p0++;
+       }
+
+       fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
+       return;
+}
+
+static void
+dump_pci_id(const char *s)
+{
+       char *p;
+       char vidstr[7], didstr[7], subsysstr[14];
+
+       p = strcasestr(s, "VEN_");
+       if (p == NULL)
+               return;
+       p += 4;
+       strcpy(vidstr, "0x");
+       strncat(vidstr, p, 4);
+       p = strcasestr(s, "DEV_");
+       if (p == NULL)
+               return;
+       p += 4;
+       strcpy(didstr, "0x");
+       strncat(didstr, p, 4);
+       if (p == NULL)
+               return;
+       p = strcasestr(s, "SUBSYS_");
+       if (p == NULL)
+               strcpy(subsysstr, "0x00000000");
+       else {
+               p += 7;
+               strcpy(subsysstr, "0x");
+               strncat(subsysstr, p, 8);
+       }
+
+       fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
+       return;
+}
+
+static void
+dump_deviceids_pci()
+{
+       struct assign *manf, *dev;
+       struct section *sec;
+       struct assign *assign;
+       char xpsec[256];
+       int found = 0;
+
+       /* Find manufacturer name */
+       manf = find_assign("Manufacturer", NULL);
+
+       /* Find manufacturer section */
+       if (manf->vals[1] != NULL &&
+           (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
+               /* Handle Windows XP INF files. */
+               snprintf(xpsec, sizeof(xpsec), "%s.%s",
+                   manf->vals[0], manf->vals[1]);
+               sec = find_section(xpsec);
+       } else
+               sec = find_section(manf->vals[0]);
+
+       /* See if there are any PCI device definitions. */
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (assign->section == sec) {
+                       dev = find_assign("strings", assign->key);
+                       if (strcasestr(assign->vals[1], "PCI") != NULL) {
+                               found++;
+                               break;
+                       }
+               }
+       }
+
+       if (found == 0)
+               return;
+
+       found = 0;
+
+       /* Emit start of PCI device table */
+       fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
+
+retry:
+
+       /*
+        * Now run through all the device names listed
+        * in the manufacturer section and dump out the
+        * device descriptions and vendor/device IDs.
+        */
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (assign->section == sec) {
+                       dev = find_assign("strings", assign->key);
+                       /* Emit device IDs. */
+                       if (strcasestr(assign->vals[1], "PCI") != NULL)
+                               dump_pci_id(assign->vals[1]);
+                       else
+                               continue;
+                       /* Emit device description */
+                       fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
+                       found++;
+               }
+       }
+
+       /* Someone tried to fool us. Shame on them. */
+       if (!found) {
+               found++;
+               sec = find_section(manf->vals[0]);
+               goto retry;
+       }
+
+       /* Emit end of table */
+
+       fprintf(ofp, "\n\n");
+
+}
+
+static void
+dump_deviceids_pcmcia()
+{
+       struct assign *manf, *dev;
+       struct section *sec;
+       struct assign *assign;
+       char xpsec[256];
+       int found = 0;
+
+       /* Find manufacturer name */
+       manf = find_assign("Manufacturer", NULL);
+
+       /* Find manufacturer section */
+       if (manf->vals[1] != NULL &&
+           (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
+               /* Handle Windows XP INF files. */
+               snprintf(xpsec, sizeof(xpsec), "%s.%s",
+                   manf->vals[0], manf->vals[1]);
+               sec = find_section(xpsec);
+       } else
+               sec = find_section(manf->vals[0]);
+
+       /* See if there are any PCMCIA device definitions. */
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (assign->section == sec) {
+                       dev = find_assign("strings", assign->key);
+                       if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
+                               found++;
+                               break;
+                       }
+               }
+       }
+
+       if (found == 0)
+               return;
+
+       found = 0;
+
+       /* Emit start of PCMCIA device table */
+       fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
+
+retry:
+
+       /*
+        * Now run through all the device names listed
+        * in the manufacturer section and dump out the
+        * device descriptions and vendor/device IDs.
+        */
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (assign->section == sec) {
+                       dev = find_assign("strings", assign->key);
+                       /* Emit device IDs. */
+                       if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
+                               dump_pcmcia_id(assign->vals[1]);
+                       else
+                               continue;
+                       /* Emit device description */
+                       fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
+                       found++;
+               }
+       }
+
+       /* Someone tried to fool us. Shame on them. */
+       if (!found) {
+               found++;
+               sec = find_section(manf->vals[0]);
+               goto retry;
+       }
+
+       /* Emit end of table */
+
+       fprintf(ofp, "\n\n");
+
+}
+
+static void
+dump_addreg(const char *s, int devidx)
+{
+       struct section *sec;
+       struct reg *reg;
+
+       /* Find the addreg section */
+       sec = find_section(s);
+
+       /* Dump all the keys defined in it. */
+       TAILQ_FOREACH(reg, &rh, link) {
+               /*
+                * Keys with an empty subkey are very easy to parse,
+                * so just deal with them here. If a parameter key
+                * of the same name also exists, prefer that one and
+                * skip this one.
+                */
+               if (reg->section == sec) {
+                       if (reg->subkey == NULL) {
+                               fprintf(ofp, "\n\t{ \"%s\",", reg->key);
+                               fprintf(ofp,"\n\t\"%s \",", reg->key);
+                               fprintf(ofp, "\n\t{ \"%s\" }, %d },",
+                                   reg->value == NULL ? "" :
+                                   stringcvt(reg->value), devidx);
+                       } else if (strncasecmp(reg->subkey,
+                           "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
+                           (reg->key != NULL && strcasecmp(reg->key,
+                           "ParamDesc") == 0))
+                               dump_paramreg(sec, reg, devidx);
+               }
+       }
+
+       return;
+}
+
+static void
+dump_enumreg(const struct section *s, const struct reg *r)
+{
+       struct reg *reg;
+       char enumkey[256];
+
+       sprintf(enumkey, "%s\\enum", r->subkey);
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
+                       continue;
+               fprintf(ofp, " [%s=%s]", reg->key,
+                   stringcvt(reg->value));
+       }
+       return;
+}
+
+static void
+dump_editreg(const struct section *s, const struct reg *r)
+{
+       struct reg *reg;
+
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
+                       continue;
+               if (reg->key == NULL)
+                       continue;
+               if (strcasecmp(reg->key, "LimitText") == 0)
+                       fprintf(ofp, " [maxchars=%s]", reg->value);
+               if (strcasecmp(reg->key, "Optional") == 0 &&
+                   strcmp(reg->value, "1") == 0)
+                       fprintf(ofp, " [optional]");
+       }
+       return;
+}
+
+/* Use this for int too */
+static void
+dump_dwordreg(const struct section *s, const struct reg *r)
+{
+       struct reg *reg;
+
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
+                       continue;
+               if (reg->key == NULL)
+                       continue;
+               if (strcasecmp(reg->key, "min") == 0)
+                       fprintf(ofp, " [min=%s]", reg->value);
+               if (strcasecmp(reg->key, "max") == 0)
+                       fprintf(ofp, " [max=%s]", reg->value);
+       }
+       return;
+}
+
+static void
+dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
+{
+       struct reg *reg;
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
+                       continue;
+               if (reg->key == NULL || strcasecmp(reg->key, "Default"))
+                       continue;
+               fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
+                   stringcvt(reg->value), devidx);
+                       break;
+       }
+       return;
+}
+
+static void
+dump_paramdesc(const struct section *s, const struct reg *r)
+{
+       struct reg *reg;
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
+                       continue;
+               if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
+                       continue;
+               fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
+                       break;
+       }
+       return;
+}
+
+static void
+dump_typeinfo(const struct section *s, const struct reg *r)
+{
+       struct reg *reg;
+       TAILQ_FOREACH(reg, &rh, link) {
+               if (reg->section != s)
+                       continue;
+               if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
+                       continue;
+               if (reg->key == NULL)
+                       continue;
+               if (strcasecmp(reg->key, "type"))
+                       continue;
+               if (strcasecmp(reg->value, "dword") == 0 ||
+                   strcasecmp(reg->value, "int") == 0)
+                       dump_dwordreg(s, r);
+               if (strcasecmp(reg->value, "enum") == 0)
+                       dump_enumreg(s, r);
+               if (strcasecmp(reg->value, "edit") == 0)
+                       dump_editreg(s, r);
+       }
+       return;
+}
+
+static void
+dump_paramreg(const struct section *s, const struct reg *r, int devidx)
+{
+       const char *keyname;
+
+       keyname = r->subkey + strlen("Ndi\\params\\");
+       fprintf(ofp, "\n\t{ \"%s\",", keyname);
+       dump_paramdesc(s, r);
+       dump_typeinfo(s, r);
+       fprintf(ofp, "\",");
+       dump_defaultinfo(s, r, devidx);
+
+       return;
+}
+
+static void
+dump_regvals(void)
+{
+       struct assign *manf, *dev;
+       struct section *sec;
+       struct assign *assign;
+       char sname[256];
+       int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
+
+       /* Find signature to check for special case of WinNT. */
+       assign = find_assign("version", "signature");
+       if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
+               is_winnt++;
+
+       /* Find manufacturer name */
+       manf = find_assign("Manufacturer", NULL);
+
+       /* Find manufacturer section */
+       if (manf->vals[1] != NULL &&
+           (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86") == 0 ||
+           strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
+               is_winxp++;
+               /* Handle Windows XP INF files. */
+               snprintf(sname, sizeof(sname), "%s.%s",
+                   manf->vals[0], manf->vals[1]);
+               sec = find_section(sname);
+       } else
+               sec = find_section(manf->vals[0]);
+
+       /* Emit start of block */
+       fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
+
+retry:
+
+       TAILQ_FOREACH(assign, &ah, link) {
+               if (assign->section == sec) {
+                       found++;
+                       /*
+                        * Find all the AddReg sections.
+                        * Look for section names with .NT, unless
+                        * this is a WinXP .INF file.
+                        */
+                       if (is_winxp) {
+                               sprintf(sname, "%s.NTx86", assign->vals[0]);
+                               dev = find_assign(sname, "AddReg");
+                               if (dev == NULL)
+                                       dev = find_assign(assign->vals[0],
+                                           "AddReg");
+                       } else {
+                               sprintf(sname, "%s.NT", assign->vals[0]);
+                               dev = find_assign(sname, "AddReg");
+                               if (dev == NULL && is_winnt)
+                                       dev = find_assign(assign->vals[0],
+                                           "AddReg");
+                       }
+                       /* Section not found. */
+                       if (dev == NULL)
+                               continue;
+                       for (i = 0; i < W_MAX; i++) {
+                               if (dev->vals[i] != NULL)
+                                       dump_addreg(dev->vals[i], devidx);
+                       }
+                       devidx++;
+               }
+       }
+
+       if (!found) {
+               sec = find_section(manf->vals[0]);
+               is_winxp = 0;
+               found++;
+               goto retry;
+       }
+
+       fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
+
+       return;
+}
+
+void
+assign_add (const char *a)
+{
+       struct assign *assign;
+       int i;
+
+       assign = malloc(sizeof(struct assign));
+       bzero(assign, sizeof(struct assign));
+       assign->section = TAILQ_LAST(&sh, section_head);
+       assign->key = sstrdup(a);
+       for (i = 0; i < idx; i++)
+               assign->vals[(idx - 1) - i] = sstrdup(words[i]);
+       TAILQ_INSERT_TAIL(&ah, assign, link);
+
+       clear_words();
+       return;
+}
+
+void
+define_add (const char *d __unused)
+{
+#ifdef notdef
+       fprintf(stderr, "define \"%s\"\n", d);
+#endif
+       return;
+}
+
+static char *
+sstrdup(const char *str)
+{
+       if (str != NULL && strlen(str))
+               return (strdup(str));
+       return (NULL);
+}
+
+static int
+satoi (const char *nptr)
+{
+       if (nptr != NULL && strlen(nptr))
+               return (atoi(nptr));
+       return (0);
+}
+
+void
+regkey_add (const char *r)
+{
+       struct reg *reg;
+
+       reg = malloc(sizeof(struct reg));
+       bzero(reg, sizeof(struct reg));
+       reg->section = TAILQ_LAST(&sh, section_head);
+       reg->root = sstrdup(r);
+       reg->subkey = sstrdup(words[3]);
+       reg->key = sstrdup(words[2]);
+       reg->flags = satoi(words[1]);
+       reg->value = sstrdup(words[0]);
+       TAILQ_INSERT_TAIL(&rh, reg, link);
+
+       free(__DECONST(char *, r));
+       clear_words();
+       return;
+}
+
+void
+push_word (const char *w)
+{
+       if (w && strlen(w))
+               words[idx++] = w;
+       else
+               words[idx++] = NULL;
+       return;
+}
+
+void
+clear_words (void)
+{
+       int i;
+
+       for (i = 0; i < idx; i++) {
+               if (words[i]) {
+                       free(__DECONST(char *, words[i]));
+               }
+       }
+       idx = 0;
+       bzero(words, sizeof(words));
+       return;
+}
diff --git a/usr.sbin/ndiscvt/inf.h b/usr.sbin/ndiscvt/inf.h
new file mode 100644 (file)
index 0000000..33f7869
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * $Id: inf.h,v 1.3 2003/11/30 21:58:16 winter Exp $
+ *
+ * $FreeBSD: src/usr.sbin/ndiscvt/inf.h,v 1.1 2003/12/11 22:38:14 wpaul Exp $
+ * $DragonFly: src/usr.sbin/ndiscvt/inf.h,v 1.1 2004/07/30 00:24:24 dillon Exp $
+ */
+
+#define W_MAX  16
+
+struct section {
+       const char *    name;
+
+       TAILQ_ENTRY(section)    link;
+};
+TAILQ_HEAD(section_head, section);
+
+struct assign {
+       struct section  *section;
+
+       const char *    key;
+       const char *    vals[W_MAX];
+
+       TAILQ_ENTRY(assign)     link;
+};
+TAILQ_HEAD(assign_head, assign);
+
+struct reg {
+       struct section *section;
+
+       const char *    root;
+       const char *    subkey;
+       const char *    key;
+       u_int           flags;
+       const char *    value;
+
+       TAILQ_ENTRY(reg)        link;
+};
+TAILQ_HEAD(reg_head, reg);
+
+#define        FLG_ADDREG_TYPE_SZ              0x00000000
+#define        FLG_ADDREG_BINVALUETYPE         0x00000001
+#define        FLG_ADDREG_NOCLOBBER            0x00000002
+#define        FLG_ADDREG_DELVAL               0x00000004
+#define        FLG_ADDREG_APPEND               0x00000008
+#define        FLG_ADDREG_KEYONLY              0x00000010
+#define        FLG_ADDREG_OVERWRITEONLY        0x00000020
+#define        FLG_ADDREG_64BITKEY             0x00001000
+#define        FLG_ADDREG_KEYONLY_COMMON       0x00002000
+#define        FLG_ADDREG_32BITKEY             0x00004000
+#define        FLG_ADDREG_TYPE_MULTI_SZ        0x00010000
+#define        FLG_ADDREG_TYPE_EXPAND_SZ       0x00020000
+#define        FLG_ADDREG_TYPE_DWORD           0x00010001
+#define        FLG_ADDREG_TYPE_NONE            0x00020001
+
+extern void    section_add     (const char *);
+extern void    assign_add      (const char *);
+extern void    define_add      (const char *);
+extern void    regkey_add      (const char *);
+
+extern void    push_word       (const char *);
+extern void    clear_words     (void);
+extern int     inf_parse       (FILE *, FILE *);
diff --git a/usr.sbin/ndiscvt/ndiscvt.8 b/usr.sbin/ndiscvt/ndiscvt.8
new file mode 100644 (file)
index 0000000..ff58541
--- /dev/null
@@ -0,0 +1,169 @@
+.\" 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: src/usr.sbin/ndiscvt/ndiscvt.8,v 1.4 2004/06/13 18:03:42 ru Exp $
+.\" $DragonFly: src/usr.sbin/ndiscvt/ndiscvt.8,v 1.1 2004/07/30 00:24:24 dillon Exp $
+.\"
+.Dd December 10, 2003
+.Dt NDISCVT 8
+.Os
+.Sh NAME
+.Nm ndiscvt
+.Nd convert
+.Tn Windows\[rg]
+NDIS drivers for use with
+.Fx
+.Sh SYNOPSIS
+.Nm
+.Op Fl i Ar inffile
+.Fl s Ar sysfile
+.Op Fl n Ar devname
+.Op Fl o Ar outfile
+.Sh DESCRIPTION
+The
+.Nm
+utility transforms a
+.Tn Windows\[rg]
+NDIS driver into a data file which
+is used to build an
+.Xr ndis 4
+compatibility driver module.
+.Tn Windows\[rg]
+drivers consist of two main parts: a
+.Pa .SYS
+file, which contains the actual driver executable code,
+and an
+.Pa .INF
+file, which provides the
+.Tn Windows\[rg]
+installer with device
+identifier information and a list of driver-specific registry keys.
+The
+.Nm
+utility can convert these files into a header file that is compiled
+into
+.Pa if_ndis.c
+to create an object code module that can be linked into
+the
+.Fx
+kernel.
+.Pp
+The
+.Pa .INF
+file is typically required since only it contains device
+identification data such as PCI vendor and device IDs or PCMCIA
+indentifier strings.
+The
+.Pa .INF
+file may be optionally omitted however,
+in which case the
+.Nm
+utility will only perform the conversion of the
+.Pa .SYS
+file.
+This is useful for debugging purposes only.
+.Sh OPTIONS
+The options are as follows:
+.Bl -tag -width indent
+.It Fl i Ar inffile
+Open and parse the specified
+.Pa .INF
+file when performing conversion.
+The
+.Nm
+utility will parse this file and emit a device identification
+structure and registry key configuration structures which will be
+used by the
+.Xr ndis 4
+driver and
+.Xr ndisapi 9
+kernel subsystem.
+If this is omitted,
+.Nm
+will emit a dummy configuration structure only.
+.It Fl s Ar sysfile
+Open and parse the specified
+.Pa .SYS
+file.
+This file must contain a
+.Tn Windows\[rg]
+driver image.
+The
+.Nm
+utility will perform some manipulation of the sections within the
+executable file to make runtime linking within the kernel a little
+easier and then convert the image into a data array.
+.It Fl n Ar devname
+Specify an alternate name for the network device/interface which will
+be created when the driver is instantiated.
+If you need to load more
+than one NDIS driver into your system (i.e., if you have two different
+network cards in your system which require NDIS driver support), each
+module you create must have a unique name.
+Device can not be larger than
+.Dv IFNAMSIZ .
+If no name is specified, the driver will use the
+default a default name
+.Pq Dq Li ndis .
+.It Fl o Ar outfile
+Specify the output file in which to place the resulting data.
+This can be any file pathname.
+If
+.Ar outfile
+is a single dash
+.Pq Sq Fl ,
+the data will be written to the standard output.
+The
+.Pa if_ndis.c
+module expects to find the driver data in a file called
+.Pa ndis_driver_data.h ,
+so it is recommended that this name be used.
+.El
+.Sh SEE ALSO
+.Xr ndis 4 ,
+.Xr ndisapi 9
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was written by
+.An Bill Paul Aq wpaul@windriver.com .
+The
+.Xr lex 1
+and
+.Xr yacc 1
+.Pa INF
+file parser was written by
+.An Matthew Dodd Aq mdodd@FreeBSD.org .
diff --git a/usr.sbin/ndiscvt/ndiscvt.c b/usr.sbin/ndiscvt/ndiscvt.c
new file mode 100644 (file)
index 0000000..8599e76
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * 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.
+ *
+ * $DragonFly: src/usr.sbin/ndiscvt/ndiscvt.c,v 1.1 2004/07/30 00:24:24 dillon Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+
+#include <emulation/ndis/regcall.h>
+#include <emulation/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> "
+           "[-n devname] [-o outfile]\n", __progname);
+       exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+       FILE            *fp, *outfp;
+       void            *img;
+       int             n, fsize, cnt;
+       unsigned char   *ptr;
+       int             i;
+       char            *inffile = NULL, *sysfile = NULL, *outfile = NULL;
+       char            *dname = NULL;
+       int             ch;
+
+       while((ch = getopt(argc, argv, "i:s:o:n:")) != -1) {
+               switch(ch) {
+               case 'i':
+                       inffile = optarg;
+                       break;
+               case 's':
+                       sysfile = optarg;
+                       break;
+               case 'o':
+                       outfile = optarg;
+                       break;
+               case 'n':
+                       dname = optarg;
+                       break;
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (sysfile == NULL)
+               usage();
+
+       /* Open the .SYS file and load it into memory */
+       fp = fopen(sysfile, "r");
+       if (fp == NULL)
+               err(1, "opening .SYS file '%s' failed", sysfile);
+       fseek (fp, 0L, SEEK_END);
+       fsize = ftell (fp);
+       rewind (fp);
+       img = calloc(fsize, 1);
+       n = fread (img, fsize, 1, fp);
+
+       fclose(fp);
+
+       if (insert_padding(&img, &fsize)) {
+               fprintf(stderr, "section relocation failed\n");
+               exit(1);
+       }
+
+       if (outfile == NULL || strcmp(outfile, "-") == 0)
+               outfp = stdout;
+       else {
+               outfp = fopen(outfile, "w");
+               if (outfp == NULL)
+                       err(1, "opening output file '%s' failed", outfile);
+       }
+
+       fprintf(outfp, "\n/*\n");
+       fprintf(outfp, " * Generated from %s and %s (%d bytes)\n",
+           inffile == NULL ? "<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");
+       fprintf(outfp, "\nextern unsigned char drv_data[];\n\n");
+
+       fprintf(outfp, "__asm__(\".data\");\n");
+       fprintf(outfp, "__asm__(\".type   drv_data, @object\");\n");
+       fprintf(outfp, "__asm__(\".size   drv_data, %d\");\n", fsize);
+       fprintf(outfp, "__asm__(\"drv_data:\");\n");
+
+       ptr = img;
+       cnt = 0;
+       while(cnt < fsize) {
+               fprintf (outfp, "__asm__(\".byte ");
+               for (i = 0; i < 10; i++) {
+                       cnt++;
+                       if (cnt == fsize) {
+                               fprintf(outfp, "0x%.2X\");\n", ptr[i]);
+                               goto done;
+                       } else {
+                               if (i == 9)
+                                       fprintf(outfp, "0x%.2X\");\n", ptr[i]);
+                               else
+                                       fprintf(outfp, "0x%.2X, ", ptr[i]);
+                       }
+               }
+               ptr += 10;
+       }
+
+done:
+
+       fprintf(outfp, "#endif /* NDIS_IMAGE */\n");
+       if (fp != NULL)
+               fclose(fp);
+       fclose(outfp);
+       free(img);
+       exit(0);
+}