Deal with the netgraph NULL function dereference on shutdown()
[dragonfly.git] / usr.sbin / ndiscvt / inf.c
blob49342ad5de7f3937ec01050a9d71f4018212b6b2
1 /*
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $DragonFly: src/usr.sbin/ndiscvt/inf.c,v 1.2 2005/12/05 02:40:27 swildner Exp $
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/types.h>
40 #include <sys/queue.h>
42 #include "inf.h"
44 extern FILE *yyin;
45 int yyparse (void);
47 const char *words[W_MAX]; /* More than we'll need. */
48 int idx;
50 static struct section_head sh;
51 static struct reg_head rh;
52 static struct assign_head ah;
54 static char *sstrdup (const char *);
55 static struct assign
56 *find_assign (const char *, const char *);
57 static struct section
58 *find_section (const char *);
59 static void dump_deviceids_pci (void);
60 static void dump_deviceids_pcmcia (void);
61 static void dump_pci_id (const char *);
62 static void dump_pcmcia_id (const char *);
63 static void dump_regvals (void);
64 static void dump_paramreg (const struct section *,
65 const struct reg *, int);
67 static FILE *ofp;
69 int
70 inf_parse(FILE *fp, FILE *outfp)
72 TAILQ_INIT(&sh);
73 TAILQ_INIT(&rh);
74 TAILQ_INIT(&ah);
76 ofp = outfp;
77 yyin = fp;
78 yyparse();
80 dump_deviceids_pci();
81 dump_deviceids_pcmcia();
82 fprintf(outfp, "#ifdef NDIS_REGVALS\n");
83 dump_regvals();
84 fprintf(outfp, "#endif /* NDIS_REGVALS */\n");
86 return (0);
89 void
90 section_add(const char *s)
92 struct section *sec;
94 sec = malloc(sizeof(struct section));
95 bzero(sec, sizeof(struct section));
96 sec->name = s;
97 TAILQ_INSERT_TAIL(&sh, sec, link);
99 return;
102 static struct assign *
103 find_assign(const char *s, const char *k)
105 struct assign *assign;
106 char newkey[256];
108 /* Deal with string section lookups. */
110 if (k != NULL && k[0] == '%') {
111 bzero(newkey, sizeof(newkey));
112 strncpy(newkey, k + 1, strlen(k) - 2);
113 k = newkey;
116 TAILQ_FOREACH(assign, &ah, link) {
117 if (strcasecmp(assign->section->name, s) == 0) {
118 if (k == NULL)
119 return(assign);
120 else
121 if (strcasecmp(assign->key, k) == 0)
122 return(assign);
125 return(NULL);
128 static const char *
129 stringcvt(const char *s)
131 struct assign *manf;
133 manf = find_assign("strings", s);
134 if (manf == NULL)
135 return(s);
136 return(manf->vals[0]);
139 struct section *
140 find_section(const char *s)
142 struct section *section;
144 TAILQ_FOREACH(section, &sh, link) {
145 if (strcasecmp(section->name, s) == 0)
146 return(section);
148 return(NULL);
151 static void
152 dump_pcmcia_id(const char *s)
154 char *manstr, *devstr;
155 char *p0, *p;
157 p0 = __DECONST(char *, s);
159 p = strchr(p0, '\\');
160 if (p == NULL)
161 return;
162 p0 = p + 1;
164 p = strchr(p0, '-');
165 if (p == NULL)
166 return;
167 *p = '\0';
169 manstr = p0;
171 /* Convert any underscores to spaces. */
173 while (*p0 != '\0') {
174 if (*p0 == '_')
175 *p0 = ' ';
176 p0++;
179 p0 = p + 1;
180 p = strchr(p0, '-');
181 if (p == NULL)
182 return;
183 *p = '\0';
185 devstr = p0;
187 /* Convert any underscores to spaces. */
189 while (*p0 != '\0') {
190 if (*p0 == '_')
191 *p0 = ' ';
192 p0++;
195 fprintf(ofp, "\t\\\n\t{ \"%s\", \"%s\", ", manstr, devstr);
196 return;
199 static void
200 dump_pci_id(const char *s)
202 char *p;
203 char vidstr[7], didstr[7], subsysstr[14];
205 p = strcasestr(s, "VEN_");
206 if (p == NULL)
207 return;
208 p += 4;
209 strcpy(vidstr, "0x");
210 strncat(vidstr, p, 4);
211 p = strcasestr(s, "DEV_");
212 if (p == NULL)
213 return;
214 p += 4;
215 strcpy(didstr, "0x");
216 strncat(didstr, p, 4);
217 if (p == NULL)
218 return;
219 p = strcasestr(s, "SUBSYS_");
220 if (p == NULL)
221 strcpy(subsysstr, "0x00000000");
222 else {
223 p += 7;
224 strcpy(subsysstr, "0x");
225 strncat(subsysstr, p, 8);
228 fprintf(ofp, "\t\\\n\t{ %s, %s, %s, ", vidstr, didstr, subsysstr);
229 return;
232 static void
233 dump_deviceids_pci(void)
235 struct assign *manf, *dev;
236 struct section *sec;
237 struct assign *assign;
238 char xpsec[256];
239 int found = 0;
241 /* Find manufacturer name */
242 manf = find_assign("Manufacturer", NULL);
244 /* Find manufacturer section */
245 if (manf->vals[1] != NULL &&
246 (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
247 strcasecmp(manf->vals[1], "NTx86") == 0 ||
248 strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
249 /* Handle Windows XP INF files. */
250 snprintf(xpsec, sizeof(xpsec), "%s.%s",
251 manf->vals[0], manf->vals[1]);
252 sec = find_section(xpsec);
253 } else
254 sec = find_section(manf->vals[0]);
256 /* See if there are any PCI device definitions. */
258 TAILQ_FOREACH(assign, &ah, link) {
259 if (assign->section == sec) {
260 dev = find_assign("strings", assign->key);
261 if (strcasestr(assign->vals[1], "PCI") != NULL) {
262 found++;
263 break;
268 if (found == 0)
269 return;
271 found = 0;
273 /* Emit start of PCI device table */
274 fprintf (ofp, "#define NDIS_PCI_DEV_TABLE");
276 retry:
279 * Now run through all the device names listed
280 * in the manufacturer section and dump out the
281 * device descriptions and vendor/device IDs.
284 TAILQ_FOREACH(assign, &ah, link) {
285 if (assign->section == sec) {
286 dev = find_assign("strings", assign->key);
287 /* Emit device IDs. */
288 if (strcasestr(assign->vals[1], "PCI") != NULL)
289 dump_pci_id(assign->vals[1]);
290 else
291 continue;
292 /* Emit device description */
293 fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
294 found++;
298 /* Someone tried to fool us. Shame on them. */
299 if (!found) {
300 found++;
301 sec = find_section(manf->vals[0]);
302 goto retry;
305 /* Emit end of table */
307 fprintf(ofp, "\n\n");
311 static void
312 dump_deviceids_pcmcia(void)
314 struct assign *manf, *dev;
315 struct section *sec;
316 struct assign *assign;
317 char xpsec[256];
318 int found = 0;
320 /* Find manufacturer name */
321 manf = find_assign("Manufacturer", NULL);
323 /* Find manufacturer section */
324 if (manf->vals[1] != NULL &&
325 (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
326 strcasecmp(manf->vals[1], "NTx86") == 0 ||
327 strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
328 /* Handle Windows XP INF files. */
329 snprintf(xpsec, sizeof(xpsec), "%s.%s",
330 manf->vals[0], manf->vals[1]);
331 sec = find_section(xpsec);
332 } else
333 sec = find_section(manf->vals[0]);
335 /* See if there are any PCMCIA device definitions. */
337 TAILQ_FOREACH(assign, &ah, link) {
338 if (assign->section == sec) {
339 dev = find_assign("strings", assign->key);
340 if (strcasestr(assign->vals[1], "PCMCIA") != NULL) {
341 found++;
342 break;
347 if (found == 0)
348 return;
350 found = 0;
352 /* Emit start of PCMCIA device table */
353 fprintf (ofp, "#define NDIS_PCMCIA_DEV_TABLE");
355 retry:
358 * Now run through all the device names listed
359 * in the manufacturer section and dump out the
360 * device descriptions and vendor/device IDs.
363 TAILQ_FOREACH(assign, &ah, link) {
364 if (assign->section == sec) {
365 dev = find_assign("strings", assign->key);
366 /* Emit device IDs. */
367 if (strcasestr(assign->vals[1], "PCMCIA") != NULL)
368 dump_pcmcia_id(assign->vals[1]);
369 else
370 continue;
371 /* Emit device description */
372 fprintf (ofp, "\t\\\n\t\"%s\" },", dev->vals[0]);
373 found++;
377 /* Someone tried to fool us. Shame on them. */
378 if (!found) {
379 found++;
380 sec = find_section(manf->vals[0]);
381 goto retry;
384 /* Emit end of table */
386 fprintf(ofp, "\n\n");
390 static void
391 dump_addreg(const char *s, int devidx)
393 struct section *sec;
394 struct reg *reg;
396 /* Find the addreg section */
397 sec = find_section(s);
399 /* Dump all the keys defined in it. */
400 TAILQ_FOREACH(reg, &rh, link) {
402 * Keys with an empty subkey are very easy to parse,
403 * so just deal with them here. If a parameter key
404 * of the same name also exists, prefer that one and
405 * skip this one.
407 if (reg->section == sec) {
408 if (reg->subkey == NULL) {
409 fprintf(ofp, "\n\t{ \"%s\",", reg->key);
410 fprintf(ofp,"\n\t\"%s \",", reg->key);
411 fprintf(ofp, "\n\t{ \"%s\" }, %d },",
412 reg->value == NULL ? "" :
413 stringcvt(reg->value), devidx);
414 } else if (strncasecmp(reg->subkey,
415 "Ndi\\params", strlen("Ndi\\params")-1) == 0 &&
416 (reg->key != NULL && strcasecmp(reg->key,
417 "ParamDesc") == 0))
418 dump_paramreg(sec, reg, devidx);
422 return;
425 static void
426 dump_enumreg(const struct section *s, const struct reg *r)
428 struct reg *reg;
429 char enumkey[256];
431 sprintf(enumkey, "%s\\enum", r->subkey);
432 TAILQ_FOREACH(reg, &rh, link) {
433 if (reg->section != s)
434 continue;
435 if (reg->subkey == NULL || strcasecmp(reg->subkey, enumkey))
436 continue;
437 fprintf(ofp, " [%s=%s]", reg->key,
438 stringcvt(reg->value));
440 return;
443 static void
444 dump_editreg(const struct section *s, const struct reg *r)
446 struct reg *reg;
448 TAILQ_FOREACH(reg, &rh, link) {
449 if (reg->section != s)
450 continue;
451 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
452 continue;
453 if (reg->key == NULL)
454 continue;
455 if (strcasecmp(reg->key, "LimitText") == 0)
456 fprintf(ofp, " [maxchars=%s]", reg->value);
457 if (strcasecmp(reg->key, "Optional") == 0 &&
458 strcmp(reg->value, "1") == 0)
459 fprintf(ofp, " [optional]");
461 return;
464 /* Use this for int too */
465 static void
466 dump_dwordreg(const struct section *s, const struct reg *r)
468 struct reg *reg;
470 TAILQ_FOREACH(reg, &rh, link) {
471 if (reg->section != s)
472 continue;
473 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
474 continue;
475 if (reg->key == NULL)
476 continue;
477 if (strcasecmp(reg->key, "min") == 0)
478 fprintf(ofp, " [min=%s]", reg->value);
479 if (strcasecmp(reg->key, "max") == 0)
480 fprintf(ofp, " [max=%s]", reg->value);
482 return;
485 static void
486 dump_defaultinfo(const struct section *s, const struct reg *r, int devidx)
488 struct reg *reg;
489 TAILQ_FOREACH(reg, &rh, link) {
490 if (reg->section != s)
491 continue;
492 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
493 continue;
494 if (reg->key == NULL || strcasecmp(reg->key, "Default"))
495 continue;
496 fprintf(ofp, "\n\t{ \"%s\" }, %d },", reg->value == NULL ? "" :
497 stringcvt(reg->value), devidx);
498 break;
500 return;
503 static void
504 dump_paramdesc(const struct section *s, const struct reg *r)
506 struct reg *reg;
507 TAILQ_FOREACH(reg, &rh, link) {
508 if (reg->section != s)
509 continue;
510 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
511 continue;
512 if (reg->key == NULL || strcasecmp(reg->key, "ParamDesc"))
513 continue;
514 fprintf(ofp, "\n\t\"%s", stringcvt(r->value));
515 break;
517 return;
520 static void
521 dump_typeinfo(const struct section *s, const struct reg *r)
523 struct reg *reg;
524 TAILQ_FOREACH(reg, &rh, link) {
525 if (reg->section != s)
526 continue;
527 if (reg->subkey == NULL || strcasecmp(reg->subkey, r->subkey))
528 continue;
529 if (reg->key == NULL)
530 continue;
531 if (strcasecmp(reg->key, "type"))
532 continue;
533 if (strcasecmp(reg->value, "dword") == 0 ||
534 strcasecmp(reg->value, "int") == 0)
535 dump_dwordreg(s, r);
536 if (strcasecmp(reg->value, "enum") == 0)
537 dump_enumreg(s, r);
538 if (strcasecmp(reg->value, "edit") == 0)
539 dump_editreg(s, r);
541 return;
544 static void
545 dump_paramreg(const struct section *s, const struct reg *r, int devidx)
547 const char *keyname;
549 keyname = r->subkey + strlen("Ndi\\params\\");
550 fprintf(ofp, "\n\t{ \"%s\",", keyname);
551 dump_paramdesc(s, r);
552 dump_typeinfo(s, r);
553 fprintf(ofp, "\",");
554 dump_defaultinfo(s, r, devidx);
556 return;
559 static void
560 dump_regvals(void)
562 struct assign *manf, *dev;
563 struct section *sec;
564 struct assign *assign;
565 char sname[256];
566 int found = 0, i, is_winxp = 0, is_winnt = 0, devidx = 0;
568 /* Find signature to check for special case of WinNT. */
569 assign = find_assign("version", "signature");
570 if (strcasecmp(assign->vals[0], "$windows nt$") == 0)
571 is_winnt++;
573 /* Find manufacturer name */
574 manf = find_assign("Manufacturer", NULL);
576 /* Find manufacturer section */
577 if (manf->vals[1] != NULL &&
578 (strcasecmp(manf->vals[1], "NT.5.1") == 0 ||
579 strcasecmp(manf->vals[1], "NTx86") == 0 ||
580 strcasecmp(manf->vals[1], "NTx86.5.1") == 0)) {
581 is_winxp++;
582 /* Handle Windows XP INF files. */
583 snprintf(sname, sizeof(sname), "%s.%s",
584 manf->vals[0], manf->vals[1]);
585 sec = find_section(sname);
586 } else
587 sec = find_section(manf->vals[0]);
589 /* Emit start of block */
590 fprintf (ofp, "ndis_cfg ndis_regvals[] = {");
592 retry:
594 TAILQ_FOREACH(assign, &ah, link) {
595 if (assign->section == sec) {
596 found++;
598 * Find all the AddReg sections.
599 * Look for section names with .NT, unless
600 * this is a WinXP .INF file.
602 if (is_winxp) {
603 sprintf(sname, "%s.NTx86", assign->vals[0]);
604 dev = find_assign(sname, "AddReg");
605 if (dev == NULL)
606 dev = find_assign(assign->vals[0],
607 "AddReg");
608 } else {
609 sprintf(sname, "%s.NT", assign->vals[0]);
610 dev = find_assign(sname, "AddReg");
611 if (dev == NULL && is_winnt)
612 dev = find_assign(assign->vals[0],
613 "AddReg");
615 /* Section not found. */
616 if (dev == NULL)
617 continue;
618 for (i = 0; i < W_MAX; i++) {
619 if (dev->vals[i] != NULL)
620 dump_addreg(dev->vals[i], devidx);
622 devidx++;
626 if (!found) {
627 sec = find_section(manf->vals[0]);
628 is_winxp = 0;
629 found++;
630 goto retry;
633 fprintf(ofp, "\n\t{ NULL, NULL, { 0 }, 0 }\n};\n\n");
635 return;
638 void
639 assign_add(const char *a)
641 struct assign *assign;
642 int i;
644 assign = malloc(sizeof(struct assign));
645 bzero(assign, sizeof(struct assign));
646 assign->section = TAILQ_LAST(&sh, section_head);
647 assign->key = sstrdup(a);
648 for (i = 0; i < idx; i++)
649 assign->vals[(idx - 1) - i] = sstrdup(words[i]);
650 TAILQ_INSERT_TAIL(&ah, assign, link);
652 clear_words();
653 return;
656 void
657 define_add(const char *d __unused)
659 #ifdef notdef
660 fprintf(stderr, "define \"%s\"\n", d);
661 #endif
662 return;
665 static char *
666 sstrdup(const char *str)
668 if (str != NULL && strlen(str))
669 return (strdup(str));
670 return (NULL);
673 static int
674 satoi(const char *nptr)
676 if (nptr != NULL && strlen(nptr))
677 return (atoi(nptr));
678 return (0);
681 void
682 regkey_add(const char *r)
684 struct reg *reg;
686 reg = malloc(sizeof(struct reg));
687 bzero(reg, sizeof(struct reg));
688 reg->section = TAILQ_LAST(&sh, section_head);
689 reg->root = sstrdup(r);
690 reg->subkey = sstrdup(words[3]);
691 reg->key = sstrdup(words[2]);
692 reg->flags = satoi(words[1]);
693 reg->value = sstrdup(words[0]);
694 TAILQ_INSERT_TAIL(&rh, reg, link);
696 free(__DECONST(char *, r));
697 clear_words();
698 return;
701 void
702 push_word(const char *w)
704 if (w && strlen(w))
705 words[idx++] = w;
706 else
707 words[idx++] = NULL;
708 return;
711 void
712 clear_words(void)
714 int i;
716 for (i = 0; i < idx; i++) {
717 if (words[i]) {
718 free(__DECONST(char *, words[i]));
721 idx = 0;
722 bzero(words, sizeof(words));
723 return;