xref: /openbmc/linux/lib/build_OID_registry (revision a77ad6ea)
1*a77ad6eaSDavid Howells#!/usr/bin/perl -w
2*a77ad6eaSDavid Howells#
3*a77ad6eaSDavid Howells# Build a static ASN.1 Object Identified (OID) registry
4*a77ad6eaSDavid Howells#
5*a77ad6eaSDavid Howells# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
6*a77ad6eaSDavid Howells# Written by David Howells (dhowells@redhat.com)
7*a77ad6eaSDavid Howells#
8*a77ad6eaSDavid Howells# This program is free software; you can redistribute it and/or
9*a77ad6eaSDavid Howells# modify it under the terms of the GNU General Public Licence
10*a77ad6eaSDavid Howells# as published by the Free Software Foundation; either version
11*a77ad6eaSDavid Howells# 2 of the Licence, or (at your option) any later version.
12*a77ad6eaSDavid Howells#
13*a77ad6eaSDavid Howells
14*a77ad6eaSDavid Howellsuse strict;
15*a77ad6eaSDavid Howells
16*a77ad6eaSDavid Howellsmy @names = ();
17*a77ad6eaSDavid Howellsmy @oids = ();
18*a77ad6eaSDavid Howells
19*a77ad6eaSDavid Howellsif ($#ARGV != 1) {
20*a77ad6eaSDavid Howells    print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
21*a77ad6eaSDavid Howells    exit(2);
22*a77ad6eaSDavid Howells}
23*a77ad6eaSDavid Howells
24*a77ad6eaSDavid Howells#
25*a77ad6eaSDavid Howells# Open the file to read from
26*a77ad6eaSDavid Howells#
27*a77ad6eaSDavid Howellsopen IN_FILE, "<$ARGV[0]" || die;
28*a77ad6eaSDavid Howellswhile (<IN_FILE>) {
29*a77ad6eaSDavid Howells    chomp;
30*a77ad6eaSDavid Howells    if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
31*a77ad6eaSDavid Howells	push @names, $1;
32*a77ad6eaSDavid Howells	push @oids, $2;
33*a77ad6eaSDavid Howells    }
34*a77ad6eaSDavid Howells}
35*a77ad6eaSDavid Howellsclose IN_FILE || die;
36*a77ad6eaSDavid Howells
37*a77ad6eaSDavid Howells#
38*a77ad6eaSDavid Howells# Open the files to write into
39*a77ad6eaSDavid Howells#
40*a77ad6eaSDavid Howellsopen C_FILE, ">$ARGV[1]" or die;
41*a77ad6eaSDavid Howellsprint C_FILE "/*\n";
42*a77ad6eaSDavid Howellsprint C_FILE " * Automatically generated by ", $0, ".  Do not edit\n";
43*a77ad6eaSDavid Howellsprint C_FILE " */\n";
44*a77ad6eaSDavid Howells
45*a77ad6eaSDavid Howells#
46*a77ad6eaSDavid Howells# Split the data up into separate lists and also determine the lengths of the
47*a77ad6eaSDavid Howells# encoded data arrays.
48*a77ad6eaSDavid Howells#
49*a77ad6eaSDavid Howellsmy @indices = ();
50*a77ad6eaSDavid Howellsmy @lengths = ();
51*a77ad6eaSDavid Howellsmy $total_length = 0;
52*a77ad6eaSDavid Howells
53*a77ad6eaSDavid Howellsprint "Compiling ", $#names + 1, " OIDs\n";
54*a77ad6eaSDavid Howells
55*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
56*a77ad6eaSDavid Howells    my $name = $names[$i];
57*a77ad6eaSDavid Howells    my $oid = $oids[$i];
58*a77ad6eaSDavid Howells
59*a77ad6eaSDavid Howells    my @components = split(/[.]/, $oid);
60*a77ad6eaSDavid Howells
61*a77ad6eaSDavid Howells    # Determine the encoded length of this OID
62*a77ad6eaSDavid Howells    my $size = $#components;
63*a77ad6eaSDavid Howells    for (my $loop = 2; $loop <= $#components; $loop++) {
64*a77ad6eaSDavid Howells	my $c = $components[$loop];
65*a77ad6eaSDavid Howells
66*a77ad6eaSDavid Howells	# We will base128 encode the number
67*a77ad6eaSDavid Howells	my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
68*a77ad6eaSDavid Howells	$tmp = int($tmp / 7);
69*a77ad6eaSDavid Howells	$size += $tmp;
70*a77ad6eaSDavid Howells    }
71*a77ad6eaSDavid Howells    push @lengths, $size;
72*a77ad6eaSDavid Howells    push @indices, $total_length;
73*a77ad6eaSDavid Howells    $total_length += $size;
74*a77ad6eaSDavid Howells}
75*a77ad6eaSDavid Howells
76*a77ad6eaSDavid Howells#
77*a77ad6eaSDavid Howells# Emit the look-up-by-OID index table
78*a77ad6eaSDavid Howells#
79*a77ad6eaSDavid Howellsprint C_FILE "\n";
80*a77ad6eaSDavid Howellsif ($total_length <= 255) {
81*a77ad6eaSDavid Howells    print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
82*a77ad6eaSDavid Howells} else {
83*a77ad6eaSDavid Howells    print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
84*a77ad6eaSDavid Howells}
85*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
86*a77ad6eaSDavid Howells    print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
87*a77ad6eaSDavid Howells}
88*a77ad6eaSDavid Howellsprint C_FILE "\t[OID__NR] = ", $total_length, "\n";
89*a77ad6eaSDavid Howellsprint C_FILE "};\n";
90*a77ad6eaSDavid Howells
91*a77ad6eaSDavid Howells#
92*a77ad6eaSDavid Howells# Encode the OIDs
93*a77ad6eaSDavid Howells#
94*a77ad6eaSDavid Howellsmy @encoded_oids = ();
95*a77ad6eaSDavid Howells
96*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
97*a77ad6eaSDavid Howells    my @octets = ();
98*a77ad6eaSDavid Howells
99*a77ad6eaSDavid Howells    my @components = split(/[.]/, $oids[$i]);
100*a77ad6eaSDavid Howells
101*a77ad6eaSDavid Howells    push @octets, $components[0] * 40 + $components[1];
102*a77ad6eaSDavid Howells
103*a77ad6eaSDavid Howells    for (my $loop = 2; $loop <= $#components; $loop++) {
104*a77ad6eaSDavid Howells	my $c = $components[$loop];
105*a77ad6eaSDavid Howells
106*a77ad6eaSDavid Howells	# Base128 encode the number
107*a77ad6eaSDavid Howells	my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
108*a77ad6eaSDavid Howells	$tmp = int($tmp / 7);
109*a77ad6eaSDavid Howells
110*a77ad6eaSDavid Howells	for (; $tmp > 0; $tmp--) {
111*a77ad6eaSDavid Howells	    push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
112*a77ad6eaSDavid Howells	}
113*a77ad6eaSDavid Howells	push @octets, $c & 0x7f;
114*a77ad6eaSDavid Howells    }
115*a77ad6eaSDavid Howells
116*a77ad6eaSDavid Howells    push @encoded_oids, \@octets;
117*a77ad6eaSDavid Howells}
118*a77ad6eaSDavid Howells
119*a77ad6eaSDavid Howells#
120*a77ad6eaSDavid Howells# Create a hash value for each OID
121*a77ad6eaSDavid Howells#
122*a77ad6eaSDavid Howellsmy @hash_values = ();
123*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
124*a77ad6eaSDavid Howells    my @octets = @{$encoded_oids[$i]};
125*a77ad6eaSDavid Howells
126*a77ad6eaSDavid Howells    my $hash = $#octets;
127*a77ad6eaSDavid Howells    foreach (@octets) {
128*a77ad6eaSDavid Howells	$hash += $_ * 33;
129*a77ad6eaSDavid Howells    }
130*a77ad6eaSDavid Howells
131*a77ad6eaSDavid Howells    $hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
132*a77ad6eaSDavid Howells
133*a77ad6eaSDavid Howells    push @hash_values, $hash & 0xff;
134*a77ad6eaSDavid Howells}
135*a77ad6eaSDavid Howells
136*a77ad6eaSDavid Howells#
137*a77ad6eaSDavid Howells# Emit the OID data
138*a77ad6eaSDavid Howells#
139*a77ad6eaSDavid Howellsprint C_FILE "\n";
140*a77ad6eaSDavid Howellsprint C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
141*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
142*a77ad6eaSDavid Howells    my @octets = @{$encoded_oids[$i]};
143*a77ad6eaSDavid Howells    print C_FILE "\t";
144*a77ad6eaSDavid Howells    print C_FILE $_, ", " foreach (@octets);
145*a77ad6eaSDavid Howells    print C_FILE "\t// ", $names[$i];
146*a77ad6eaSDavid Howells    print C_FILE "\n";
147*a77ad6eaSDavid Howells}
148*a77ad6eaSDavid Howellsprint C_FILE "};\n";
149*a77ad6eaSDavid Howells
150*a77ad6eaSDavid Howells#
151*a77ad6eaSDavid Howells# Build the search index table (ordered by length then hash then content)
152*a77ad6eaSDavid Howells#
153*a77ad6eaSDavid Howellsmy @index_table = ( 0 .. $#names );
154*a77ad6eaSDavid Howells
155*a77ad6eaSDavid Howells@index_table = sort {
156*a77ad6eaSDavid Howells    my @octets_a = @{$encoded_oids[$a]};
157*a77ad6eaSDavid Howells    my @octets_b = @{$encoded_oids[$b]};
158*a77ad6eaSDavid Howells
159*a77ad6eaSDavid Howells    return $hash_values[$a] <=> $hash_values[$b]
160*a77ad6eaSDavid Howells	if ($hash_values[$a] != $hash_values[$b]);
161*a77ad6eaSDavid Howells    return $#octets_a <=> $#octets_b
162*a77ad6eaSDavid Howells	if ($#octets_a != $#octets_b);
163*a77ad6eaSDavid Howells    for (my $i = $#octets_a; $i >= 0; $i--) {
164*a77ad6eaSDavid Howells	return $octets_a[$i] <=> $octets_b[$i]
165*a77ad6eaSDavid Howells	    if ($octets_a[$i] != $octets_b[$i]);
166*a77ad6eaSDavid Howells    }
167*a77ad6eaSDavid Howells    return 0;
168*a77ad6eaSDavid Howells
169*a77ad6eaSDavid Howells} @index_table;
170*a77ad6eaSDavid Howells
171*a77ad6eaSDavid Howells#
172*a77ad6eaSDavid Howells# Emit the search index and hash value table
173*a77ad6eaSDavid Howells#
174*a77ad6eaSDavid Howellsprint C_FILE "\n";
175*a77ad6eaSDavid Howellsprint C_FILE "static const struct {\n";
176*a77ad6eaSDavid Howellsprint C_FILE "\tunsigned char hash;\n";
177*a77ad6eaSDavid Howellsif ($#names <= 255) {
178*a77ad6eaSDavid Howells    print C_FILE "\tenum OID oid : 8;\n";
179*a77ad6eaSDavid Howells} else {
180*a77ad6eaSDavid Howells    print C_FILE "\tenum OID oid : 16;\n";
181*a77ad6eaSDavid Howells}
182*a77ad6eaSDavid Howellsprint C_FILE "} oid_search_table[OID__NR] = {\n";
183*a77ad6eaSDavid Howellsfor (my $i = 0; $i <= $#names; $i++) {
184*a77ad6eaSDavid Howells    my @octets = @{$encoded_oids[$index_table[$i]]};
185*a77ad6eaSDavid Howells    printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
186*a77ad6eaSDavid Howells	   $i,
187*a77ad6eaSDavid Howells	   $hash_values[$index_table[$i]],
188*a77ad6eaSDavid Howells	   $names[$index_table[$i]]);
189*a77ad6eaSDavid Howells    printf C_FILE "%02x", $_ foreach (@octets);
190*a77ad6eaSDavid Howells    print C_FILE "\n";
191*a77ad6eaSDavid Howells}
192*a77ad6eaSDavid Howellsprint C_FILE "};\n";
193*a77ad6eaSDavid Howells
194*a77ad6eaSDavid Howells#
195*a77ad6eaSDavid Howells# Emit the OID debugging name table
196*a77ad6eaSDavid Howells#
197*a77ad6eaSDavid Howells#print C_FILE "\n";
198*a77ad6eaSDavid Howells#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
199*a77ad6eaSDavid Howells#
200*a77ad6eaSDavid Howells#for (my $i = 0; $i <= $#names; $i++) {
201*a77ad6eaSDavid Howells#    print C_FILE "\t\"", $names[$i], "\",\n"
202*a77ad6eaSDavid Howells#}
203*a77ad6eaSDavid Howells#print C_FILE "\t\"Unknown-OID\"\n";
204*a77ad6eaSDavid Howells#print C_FILE "};\n";
205*a77ad6eaSDavid Howells
206*a77ad6eaSDavid Howells#
207*a77ad6eaSDavid Howells# Polish off
208*a77ad6eaSDavid Howells#
209*a77ad6eaSDavid Howellsclose C_FILE or die;
210