117680Spst#!/bin/sh
217680Spst#
398524Sfenner# Copyright (c) 1990, 1996
498524Sfenner#	John Robert LoVerso. All rights reserved.
598524Sfenner# SMIv2 parsing copyright (c) 1999
698524Sfenner#	William C. Fenner.
717680Spst#
898524Sfenner# Redistribution and use in source and binary forms, with or without
998524Sfenner# modification, are permitted provided that the following conditions
1098524Sfenner# are met:
1117680Spst#
1298524Sfenner# 1. Redistributions of source code must retain the above copyright
1398524Sfenner#    notices, this list of conditions and the following disclaimer.
1498524Sfenner#
1598524Sfenner# 2. Redistributions in binary form must reproduce the above copyright
1698524Sfenner#    notices, this list of conditions and the following disclaimer in the
1798524Sfenner#    documentation and/or other materials provided with the distribution.
1898524Sfenner#
1998524Sfenner# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2098524Sfenner# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2198524Sfenner# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2298524Sfenner# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2398524Sfenner# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2498524Sfenner# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2598524Sfenner# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2698524Sfenner# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2798524Sfenner# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2898524Sfenner# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2998524Sfenner#
30190207Srpaulo# @(#) $Id: makemib,v 1.3 2001-09-17 22:16:52 fenner Exp $ (jlv)
3117680Spst
3217680Spst#
3317680Spst# This script will read either ASN.1-style MIB files or the ".defs" files
3417680Spst# created by the ISODE "mosy" program on such files.
3517680Spst#
3617680Spst# The output of this script is the "mib.h" file used by tcpdumps' ASN.1/SNMP
3717680Spst# decoding code.
3817680Spst#
3917680Spst# This script needs to be run by "gawk" (GNU awk).  "nawk" will work, but
4017680Spst# dump will get a recursion error if you process LARGE mibs.  While it would
4117680Spst# by farily easy to rewrite this not to use recursion (and also easy to
4217680Spst# eliminate use of gsub and functions to use classic "awk"), you have to 
4317680Spst# order the structure declarations in defined-first order for the compiler
4417680Spst# not to barf; too bad tsort doesn't take arguments.
4517680Spst#
4617680Spst
4717680Spstcat << EOF
4817680Spst/*
4917680Spst * This file was generated by tcpdump/makemib on `date`
5017680Spst * You probably don't want to edit this by hand!
5117680Spst *
5217680Spst * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer 
5317680Spst};
5417680Spst */
5517680Spst
5617680SpstEOF
5717680Spst
5856893Sfennerawk '
5917680SpstBEGIN {
6056893Sfenner	debug=0;
6117680Spst	# for sanity, we prep the namespace with objects from RFC-1155
6217680Spst	# (we manually establish the root)
6317680Spst	oid["iso"]=1
6417680Spst	oidadd("org", "iso", 3)
6517680Spst	oidadd("dod", "org", 6)
6617680Spst	oidadd("internet", "dod", 1)
6717680Spst	oidadd("directory", "internet", 1)
6817680Spst	oidadd("mgmt", "internet", 2)
6956893Sfenner#XXX	oidadd("mib", "mgmt", 1)
7056893Sfenner	oidadd("mib-2", "mgmt", 1)
7117680Spst	oidadd("experimental", "internet", 3)
7217680Spst	oidadd("private", "internet", 4)
7317680Spst	oidadd("enterprises", "private", 1)
7456893Sfenner	oidadd("ip", "mib-2", 4)
7556893Sfenner	oidadd("transmission", "mib-2", 10)
7617680Spst
7717680Spst	holddesc="none"
7817680Spst}
7917680Spst
8017680Spst#
8117680Spst# Read mosy "*.defs" file.  mosy does all the parsing work; we just read
8217680Spst# its simple and straightforward output.  It would not be too hard to make
8317680Spst# tcpdump directly read mosy output, but...
8417680Spst#
8556893Sfenner# Ignore these unless the current file is called something.defs; false
8656893Sfenner# positives are too common in DESCRIPTIONs.
8717680Spst
8856893SfennerNF > 1 && index($2,".")>0 && FILENAME ~ /\.defs/ {
8917680Spst	# currently ignore items of the form "{ iso.3.6.1 }"
9056893Sfenner	if (split($2, p, ".") == 2) {
9117680Spst		oidadd($1, p[1], p[2])
9256893Sfenner	}
9317680Spst	next
9417680Spst}
9517680Spst
9617680Spst#
9756893Sfenner# Must be a MIB file
9856893Sfenner# Make it easier to parse - used to be done by sed
9956893Sfenner{ sub(/--\*.*\*--/, ""); sub(/--.*/, ""); gsub(/[{}]/, " & "); }
10056893Sfenner
10117680Spst#
10256893Sfenner# this next section is simple and naive, but does the job ok
10356893Sfenner#
10417680Spst
10556893Sfenner# foo OBJECT IDENTIFIER ::= { baz 17 }
10656893Sfenner# or
10756893Sfenner# foo OBJECT IDENTIFIER ::=
10856893Sfenner# { baz 17 }
10917680Spst$2$3$4 == "OBJECTIDENTIFIER::=" {
11017680Spst	holddesc="none"
11117680Spst	if (NF == 8)
11217680Spst		oidadd($1, $6, $7)
11356893Sfenner	if (NF == 4)
11456893Sfenner		holddesc=$1
11556893Sfenner	next
11617680Spst}
11756893Sfenner$1 == "{" && holddesc != "none" && NF == 4 {
11856893Sfenner	oidadd(holddesc, $2, $3)
11956893Sfenner	holddesc="none"
12056893Sfenner}
12156893Sfenner#
12256893Sfenner# foo OBJECT IDENTIFIER
12356893Sfenner#  ::= { bar 1 }
12456893Sfenner$2$3 == "OBJECTIDENTIFIER" && $1 != "SYNTAX" && NF == 3 {
12517680Spst	holddesc=$1
12617680Spst}
12756893Sfenner#
12856893Sfenner# foo
12956893Sfenner# OBJECT IDENTIFIER ::= { bar 1 }
13056893Sfenner# a couple of heuristics to exclude single words in e.g. long
13156893Sfenner#  DESCRIPTION clauses
13256893SfennerNF == 1 && $1 ~ "[a-z][a-z]*[A-Z]" && $1 !~ /[(){}.,]/ && holddesc == "none" {
13356893Sfenner	holddesc=$1
13456893Sfenner}
13556893Sfenner$1$2$3 == "OBJECTIDENTIFIER::=" && holddesc != "none" {
13656893Sfenner	oidadd(holddesc, $5, $6)
13756893Sfenner	holddesc="none"
13856893Sfenner}
13956893Sfenner#
14056893Sfenner# "normal" style
14156893Sfenner# foo OBJECT-TYPE ...
14256893Sfenner# ...
14356893Sfenner#   ::= { baz 5 }
14456893Sfenner$2 == "MODULE-IDENTITY" || $2 == "MODULE-COMPLIANCE" ||
14556893Sfenner	$2 == "OBJECT-IDENTITY" || $2 == "OBJECT-TYPE" ||
14656893Sfenner	$2 == "OBJECT-GROUP" ||
14756893Sfenner	$2 == "NOTIFICATION-TYPE" || $2 == "NOTIFICATION-GROUP" {
14856893Sfenner	holddesc=$1
14956893Sfenner}
15017680Spst$1 == "::=" && holddesc != "none" && NF == 5 {
15117680Spst	oidadd(holddesc, $3, $4)
15217680Spst	holddesc="none"
15317680Spst}
15456893Sfenner#
15556893Sfenner# foo ::= { baz 17 }
15656893Sfenner$2$3 == "::={" {
15756893Sfenner	oidadd($1,$4,$5)
15856893Sfenner	holddesc="none"
15956893Sfenner}
16017680Spst
16156893Sfenner
16217680Spst# 
16317680Spst# End of the road - output the data.
16417680Spst#
16517680Spst
16617680SpstEND {
16717680Spst	print "struct obj"
16817680Spst	dump("iso")
16917680Spst	print "*mibroot = &_iso_obj;"
17017680Spst}
17117680Spst
17256893Sfennerfunction inn(file) {
17356893Sfenner	if (file == "" || file == "-")
17456893Sfenner		return ""
17556893Sfenner	return " in " file
17656893Sfenner}
17756893Sfenner
17817680Spst#
17917680Spst# add a new object to the tree
18017680Spst#
18117680Spst#		new OBJECT IDENTIFIER ::= { parent value }
18217680Spst#
18317680Spst
18417680Spstfunction oidadd(new, parent, value) {
18556893Sfenner	# Ignore 0.0
18656893Sfenner	if (parent == "0" && value == 0)
18756893Sfenner		return
18856893Sfenner	if (debug)
18956893Sfenner		print "/* oidadd" inn(FILENAME) ":", new, "in", parent, "as", value, "line", $0, "*/"
19017680Spst	# use safe C identifiers
19117680Spst	gsub(/[-&\/]/,"",new)
19217680Spst	gsub(/[-&\/]/,"",parent)
19317680Spst	# check if parent missing
19456893Sfenner	if (oid[parent] == "") {
19556893Sfenner		printf "/* parse problem%s: no parent for %s.%s(%d) */\n", \
19656893Sfenner			inn(FILENAME), parent, new, value
19717680Spst		return
19817680Spst	}
19917680Spst	# check if parent.value already exists
20017680Spst	if (oid[new] > 0 && oid[new] != value) {
20156893Sfenner		printf "/* parse problem%s: dup %s.%s(%d) != old (%d) */\n", \
20256893Sfenner			inn(FILENAME), parent, new, value, oid[new]
20317680Spst		return
20417680Spst	}
20517680Spst	# check for new name for parent.value
20617680Spst	if (child[parent] != "") {
20717680Spst		for (sib = child[parent]; sib != ""; sib = sibling[sib])
20817680Spst			if (oid[sib] == value) {
20956893Sfenner				if (new != sib)
21056893Sfenner					printf "/* parse problem%s: new name" \
21156893Sfenner						" \"%s\"" \
21256893Sfenner						" for %s.%s(%d) ignored */\n", \
21356893Sfenner						inn(FILENAME), new, parent, \
21456893Sfenner						sib, value
21517680Spst				return
21617680Spst			}
21717680Spst	}
21817680Spst
21917680Spst	oid[new]=value
22017680Spst	if (child[parent] == "") {
22117680Spst		child[parent] = new
22217680Spst	} else {
22317680Spst		sibling[new] = child[parent]
22417680Spst		child[parent] = new
22517680Spst	}
22617680Spst}
22717680Spst
22817680Spst#
22917680Spst# old(?) routine to recurse down the tree (in postfix order for convenience)
23017680Spst#
23117680Spst
23217680Spstfunction dump(item, c, s) {
23317680Spst#	newitem=sofar"."item"("oid[item]")"
23417680Spst#	printf "/* %s c=%s s=%s */\n", newitem, child[item], sibling[item]
23517680Spst	c="NULL"
23617680Spst	if (child[item] != "") {
23717680Spst		dump(child[item])
23817680Spst		c = "&_"child[item]"_obj"
23917680Spst	}
24017680Spst	s="NULL"
24117680Spst	if (sibling[item] != "") {
24217680Spst		dump(sibling[item])
24317680Spst		s = "&_"sibling[item]"_obj"
24417680Spst	}
24517680Spst	printf "_%s_obj = {\n\t\"%s\", %d, 0,\n\t%s, %s\n},\n", \
24617680Spst		item, item, oid[item], c, s
24717680Spst}
24856893Sfenner' $@
24917680Spstexit 0
250