1#!/bin/sh
2#
3# Copyright (c) 1990, 1996
4#	John Robert LoVerso. All rights reserved.
5# SMIv2 parsing copyright (c) 1999
6#	William C. Fenner.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11#
12# 1. Redistributions of source code must retain the above copyright
13#    notices, this list of conditions and the following disclaimer.
14#
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notices, this list of conditions and the following disclaimer in the
17#    documentation and/or other materials provided with the distribution.
18#
19# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
20# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29#
30# @(#) $Id: makemib,v 1.3 2001-09-17 22:16:52 fenner Exp $ (jlv)
31
32#
33# This script will read either ASN.1-style MIB files or the ".defs" files
34# created by the ISODE "mosy" program on such files.
35#
36# The output of this script is the "mib.h" file used by tcpdumps' ASN.1/SNMP
37# decoding code.
38#
39# This script needs to be run by "gawk" (GNU awk).  "nawk" will work, but
40# dump will get a recursion error if you process LARGE mibs.  While it would
41# by farily easy to rewrite this not to use recursion (and also easy to
42# eliminate use of gsub and functions to use classic "awk"), you have to 
43# order the structure declarations in defined-first order for the compiler
44# not to barf; too bad tsort doesn't take arguments.
45#
46
47cat << EOF
48/*
49 * This file was generated by tcpdump/makemib on `date`
50 * You probably don't want to edit this by hand!
51 *
52 * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer 
53};
54 */
55
56EOF
57
58awk '
59BEGIN {
60	debug=0;
61	# for sanity, we prep the namespace with objects from RFC-1155
62	# (we manually establish the root)
63	oid["iso"]=1
64	oidadd("org", "iso", 3)
65	oidadd("dod", "org", 6)
66	oidadd("internet", "dod", 1)
67	oidadd("directory", "internet", 1)
68	oidadd("mgmt", "internet", 2)
69#XXX	oidadd("mib", "mgmt", 1)
70	oidadd("mib-2", "mgmt", 1)
71	oidadd("experimental", "internet", 3)
72	oidadd("private", "internet", 4)
73	oidadd("enterprises", "private", 1)
74	oidadd("ip", "mib-2", 4)
75	oidadd("transmission", "mib-2", 10)
76
77	holddesc="none"
78}
79
80#
81# Read mosy "*.defs" file.  mosy does all the parsing work; we just read
82# its simple and straightforward output.  It would not be too hard to make
83# tcpdump directly read mosy output, but...
84#
85# Ignore these unless the current file is called something.defs; false
86# positives are too common in DESCRIPTIONs.
87
88NF > 1 && index($2,".")>0 && FILENAME ~ /\.defs/ {
89	# currently ignore items of the form "{ iso.3.6.1 }"
90	if (split($2, p, ".") == 2) {
91		oidadd($1, p[1], p[2])
92	}
93	next
94}
95
96#
97# Must be a MIB file
98# Make it easier to parse - used to be done by sed
99{ sub(/--\*.*\*--/, ""); sub(/--.*/, ""); gsub(/[{}]/, " & "); }
100
101#
102# this next section is simple and naive, but does the job ok
103#
104
105# foo OBJECT IDENTIFIER ::= { baz 17 }
106# or
107# foo OBJECT IDENTIFIER ::=
108# { baz 17 }
109$2$3$4 == "OBJECTIDENTIFIER::=" {
110	holddesc="none"
111	if (NF == 8)
112		oidadd($1, $6, $7)
113	if (NF == 4)
114		holddesc=$1
115	next
116}
117$1 == "{" && holddesc != "none" && NF == 4 {
118	oidadd(holddesc, $2, $3)
119	holddesc="none"
120}
121#
122# foo OBJECT IDENTIFIER
123#  ::= { bar 1 }
124$2$3 == "OBJECTIDENTIFIER" && $1 != "SYNTAX" && NF == 3 {
125	holddesc=$1
126}
127#
128# foo
129# OBJECT IDENTIFIER ::= { bar 1 }
130# a couple of heuristics to exclude single words in e.g. long
131#  DESCRIPTION clauses
132NF == 1 && $1 ~ "[a-z][a-z]*[A-Z]" && $1 !~ /[(){}.,]/ && holddesc == "none" {
133	holddesc=$1
134}
135$1$2$3 == "OBJECTIDENTIFIER::=" && holddesc != "none" {
136	oidadd(holddesc, $5, $6)
137	holddesc="none"
138}
139#
140# "normal" style
141# foo OBJECT-TYPE ...
142# ...
143#   ::= { baz 5 }
144$2 == "MODULE-IDENTITY" || $2 == "MODULE-COMPLIANCE" ||
145	$2 == "OBJECT-IDENTITY" || $2 == "OBJECT-TYPE" ||
146	$2 == "OBJECT-GROUP" ||
147	$2 == "NOTIFICATION-TYPE" || $2 == "NOTIFICATION-GROUP" {
148	holddesc=$1
149}
150$1 == "::=" && holddesc != "none" && NF == 5 {
151	oidadd(holddesc, $3, $4)
152	holddesc="none"
153}
154#
155# foo ::= { baz 17 }
156$2$3 == "::={" {
157	oidadd($1,$4,$5)
158	holddesc="none"
159}
160
161
162# 
163# End of the road - output the data.
164#
165
166END {
167	print "struct obj"
168	dump("iso")
169	print "*mibroot = &_iso_obj;"
170}
171
172function inn(file) {
173	if (file == "" || file == "-")
174		return ""
175	return " in " file
176}
177
178#
179# add a new object to the tree
180#
181#		new OBJECT IDENTIFIER ::= { parent value }
182#
183
184function oidadd(new, parent, value) {
185	# Ignore 0.0
186	if (parent == "0" && value == 0)
187		return
188	if (debug)
189		print "/* oidadd" inn(FILENAME) ":", new, "in", parent, "as", value, "line", $0, "*/"
190	# use safe C identifiers
191	gsub(/[-&\/]/,"",new)
192	gsub(/[-&\/]/,"",parent)
193	# check if parent missing
194	if (oid[parent] == "") {
195		printf "/* parse problem%s: no parent for %s.%s(%d) */\n", \
196			inn(FILENAME), parent, new, value
197		return
198	}
199	# check if parent.value already exists
200	if (oid[new] > 0 && oid[new] != value) {
201		printf "/* parse problem%s: dup %s.%s(%d) != old (%d) */\n", \
202			inn(FILENAME), parent, new, value, oid[new]
203		return
204	}
205	# check for new name for parent.value
206	if (child[parent] != "") {
207		for (sib = child[parent]; sib != ""; sib = sibling[sib])
208			if (oid[sib] == value) {
209				if (new != sib)
210					printf "/* parse problem%s: new name" \
211						" \"%s\"" \
212						" for %s.%s(%d) ignored */\n", \
213						inn(FILENAME), new, parent, \
214						sib, value
215				return
216			}
217	}
218
219	oid[new]=value
220	if (child[parent] == "") {
221		child[parent] = new
222	} else {
223		sibling[new] = child[parent]
224		child[parent] = new
225	}
226}
227
228#
229# old(?) routine to recurse down the tree (in postfix order for convenience)
230#
231
232function dump(item, c, s) {
233#	newitem=sofar"."item"("oid[item]")"
234#	printf "/* %s c=%s s=%s */\n", newitem, child[item], sibling[item]
235	c="NULL"
236	if (child[item] != "") {
237		dump(child[item])
238		c = "&_"child[item]"_obj"
239	}
240	s="NULL"
241	if (sibling[item] != "") {
242		dump(sibling[item])
243		s = "&_"sibling[item]"_obj"
244	}
245	printf "_%s_obj = {\n\t\"%s\", %d, 0,\n\t%s, %s\n},\n", \
246		item, item, oid[item], c, s
247}
248' $@
249exit 0
250