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