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 # 31 # This script will read either ASN.1-style MIB files or the ".defs" files 32 # created by the ISODE "mosy" program on such files. 33 # 34 # The output of this script is the "mib.h" file used by tcpdumps' ASN.1/SNMP 35 # decoding code. 36 # 37 # This script needs to be run by "gawk" (GNU awk). "nawk" will work, but 38 # dump will get a recursion error if you process LARGE mibs. While it would 39 # by farily easy to rewrite this not to use recursion (and also easy to 40 # eliminate use of gsub and functions to use classic "awk"), you have to 41 # order the structure declarations in defined-first order for the compiler 42 # not to barf; too bad tsort doesn't take arguments. 43 # 44 45 cat << EOF 46 /* 47 * This file was generated by tcpdump/makemib on `date` 48 * You probably don't want to edit this by hand! 49 * 50 * struct mib somename = { desc, oid-octet, type, child-pointer, next-pointer 51 }; 52 */ 53 54 EOF 55 56 awk ' 57 BEGIN { 58 debug=0; 59 # for sanity, we prep the namespace with objects from RFC-1155 60 # (we manually establish the root) 61 oid["iso"]=1 62 oidadd("org", "iso", 3) 63 oidadd("dod", "org", 6) 64 oidadd("internet", "dod", 1) 65 oidadd("directory", "internet", 1) 66 oidadd("mgmt", "internet", 2) 67 #XXX oidadd("mib", "mgmt", 1) 68 oidadd("mib-2", "mgmt", 1) 69 oidadd("experimental", "internet", 3) 70 oidadd("private", "internet", 4) 71 oidadd("enterprises", "private", 1) 72 oidadd("ip", "mib-2", 4) 73 oidadd("transmission", "mib-2", 10) 74 75 holddesc="none" 76 } 77 78 # 79 # Read mosy "*.defs" file. mosy does all the parsing work; we just read 80 # its simple and straightforward output. It would not be too hard to make 81 # tcpdump directly read mosy output, but... 82 # 83 # Ignore these unless the current file is called something.defs; false 84 # positives are too common in DESCRIPTIONs. 85 86 NF > 1 && index($2,".")>0 && FILENAME ~ /\.defs/ { 87 # currently ignore items of the form "{ iso.3.6.1 }" 88 if (split($2, p, ".") == 2) { 89 oidadd($1, p[1], p[2]) 90 } 91 next 92 } 93 94 # 95 # Must be a MIB file 96 # Make it easier to parse - used to be done by sed 97 { sub(/--\*.*\*--/, ""); sub(/--.*/, ""); gsub(/[{}]/, " & "); } 98 99 # 100 # this next section is simple and naive, but does the job ok 101 # 102 103 # foo OBJECT IDENTIFIER ::= { baz 17 } 104 # or 105 # foo OBJECT IDENTIFIER ::= 106 # { baz 17 } 107 $2$3$4 == "OBJECTIDENTIFIER::=" { 108 holddesc="none" 109 if (NF == 8) 110 oidadd($1, $6, $7) 111 if (NF == 4) 112 holddesc=$1 113 next 114 } 115 $1 == "{" && holddesc != "none" && NF == 4 { 116 oidadd(holddesc, $2, $3) 117 holddesc="none" 118 } 119 # 120 # foo OBJECT IDENTIFIER 121 # ::= { bar 1 } 122 $2$3 == "OBJECTIDENTIFIER" && $1 != "SYNTAX" && NF == 3 { 123 holddesc=$1 124 } 125 # 126 # foo 127 # OBJECT IDENTIFIER ::= { bar 1 } 128 # a couple of heuristics to exclude single words in e.g. long 129 # DESCRIPTION clauses 130 NF == 1 && $1 ~ "[a-z][a-z]*[A-Z]" && $1 !~ /[(){}.,]/ && holddesc == "none" { 131 holddesc=$1 132 } 133 $1$2$3 == "OBJECTIDENTIFIER::=" && holddesc != "none" { 134 oidadd(holddesc, $5, $6) 135 holddesc="none" 136 } 137 # 138 # "normal" style 139 # foo OBJECT-TYPE ... 140 # ... 141 # ::= { baz 5 } 142 $2 == "MODULE-IDENTITY" || $2 == "MODULE-COMPLIANCE" || 143 $2 == "OBJECT-IDENTITY" || $2 == "OBJECT-TYPE" || 144 $2 == "OBJECT-GROUP" || 145 $2 == "NOTIFICATION-TYPE" || $2 == "NOTIFICATION-GROUP" { 146 holddesc=$1 147 } 148 $1 == "::=" && holddesc != "none" && NF == 5 { 149 oidadd(holddesc, $3, $4) 150 holddesc="none" 151 } 152 # 153 # foo ::= { baz 17 } 154 $2$3 == "::={" { 155 oidadd($1,$4,$5) 156 holddesc="none" 157 } 158 159 160 # 161 # End of the road - output the data. 162 # 163 164 END { 165 print "struct obj" 166 dump("iso") 167 print "*mibroot = &_iso_obj;" 168 } 169 170 function inn(file) { 171 if (file == "" || file == "-") 172 return "" 173 return " in " file 174 } 175 176 # 177 # add a new object to the tree 178 # 179 # new OBJECT IDENTIFIER ::= { parent value } 180 # 181 182 function oidadd(new, parent, value) { 183 # Ignore 0.0 184 if (parent == "0" && value == 0) 185 return 186 if (debug) 187 print "/* oidadd" inn(FILENAME) ":", new, "in", parent, "as", value, "line", $0, "*/" 188 # use safe C identifiers 189 gsub(/[-&\/]/,"",new) 190 gsub(/[-&\/]/,"",parent) 191 # check if parent missing 192 if (oid[parent] == "") { 193 printf "/* parse problem%s: no parent for %s.%s(%d) */\n", \ 194 inn(FILENAME), parent, new, value 195 return 196 } 197 # check if parent.value already exists 198 if (oid[new] > 0 && oid[new] != value) { 199 printf "/* parse problem%s: dup %s.%s(%d) != old (%d) */\n", \ 200 inn(FILENAME), parent, new, value, oid[new] 201 return 202 } 203 # check for new name for parent.value 204 if (child[parent] != "") { 205 for (sib = child[parent]; sib != ""; sib = sibling[sib]) 206 if (oid[sib] == value) { 207 if (new != sib) 208 printf "/* parse problem%s: new name" \ 209 " \"%s\"" \ 210 " for %s.%s(%d) ignored */\n", \ 211 inn(FILENAME), new, parent, \ 212 sib, value 213 return 214 } 215 } 216 217 oid[new]=value 218 if (child[parent] == "") { 219 child[parent] = new 220 } else { 221 sibling[new] = child[parent] 222 child[parent] = new 223 } 224 } 225 226 # 227 # old(?) routine to recurse down the tree (in postfix order for convenience) 228 # 229 230 function dump(item, c, s) { 231 # newitem=sofar"."item"("oid[item]")" 232 # printf "/* %s c=%s s=%s */\n", newitem, child[item], sibling[item] 233 c="NULL" 234 if (child[item] != "") { 235 dump(child[item]) 236 c = "&_"child[item]"_obj" 237 } 238 s="NULL" 239 if (sibling[item] != "") { 240 dump(sibling[item]) 241 s = "&_"sibling[item]"_obj" 242 } 243 printf "_%s_obj = {\n\t\"%s\", %d, 0,\n\t%s, %s\n},\n", \ 244 item, item, oid[item], c, s 245 } 246 ' $@ 247 exit 0 248