Back to home page

LXR

 
 

    


0001 /* ASN.1 Object identifier (OID) registry
0002  *
0003  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
0004  * Written by David Howells (dhowells@redhat.com)
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU General Public Licence
0008  * as published by the Free Software Foundation; either version
0009  * 2 of the Licence, or (at your option) any later version.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/export.h>
0014 #include <linux/oid_registry.h>
0015 #include <linux/kernel.h>
0016 #include <linux/errno.h>
0017 #include <linux/bug.h>
0018 #include "oid_registry_data.c"
0019 
0020 MODULE_DESCRIPTION("OID Registry");
0021 MODULE_AUTHOR("Red Hat, Inc.");
0022 MODULE_LICENSE("GPL");
0023 
0024 /**
0025  * look_up_OID - Find an OID registration for the specified data
0026  * @data: Binary representation of the OID
0027  * @datasize: Size of the binary representation
0028  */
0029 enum OID look_up_OID(const void *data, size_t datasize)
0030 {
0031     const unsigned char *octets = data;
0032     enum OID oid;
0033     unsigned char xhash;
0034     unsigned i, j, k, hash;
0035     size_t len;
0036 
0037     /* Hash the OID data */
0038     hash = datasize - 1;
0039 
0040     for (i = 0; i < datasize; i++)
0041         hash += octets[i] * 33;
0042     hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
0043     hash &= 0xff;
0044 
0045     /* Binary search the OID registry.  OIDs are stored in ascending order
0046      * of hash value then ascending order of size and then in ascending
0047      * order of reverse value.
0048      */
0049     i = 0;
0050     k = OID__NR;
0051     while (i < k) {
0052         j = (i + k) / 2;
0053 
0054         xhash = oid_search_table[j].hash;
0055         if (xhash > hash) {
0056             k = j;
0057             continue;
0058         }
0059         if (xhash < hash) {
0060             i = j + 1;
0061             continue;
0062         }
0063 
0064         oid = oid_search_table[j].oid;
0065         len = oid_index[oid + 1] - oid_index[oid];
0066         if (len > datasize) {
0067             k = j;
0068             continue;
0069         }
0070         if (len < datasize) {
0071             i = j + 1;
0072             continue;
0073         }
0074 
0075         /* Variation is most likely to be at the tail end of the
0076          * OID, so do the comparison in reverse.
0077          */
0078         while (len > 0) {
0079             unsigned char a = oid_data[oid_index[oid] + --len];
0080             unsigned char b = octets[len];
0081             if (a > b) {
0082                 k = j;
0083                 goto next;
0084             }
0085             if (a < b) {
0086                 i = j + 1;
0087                 goto next;
0088             }
0089         }
0090         return oid;
0091     next:
0092         ;
0093     }
0094 
0095     return OID__NR;
0096 }
0097 EXPORT_SYMBOL_GPL(look_up_OID);
0098 
0099 /*
0100  * sprint_OID - Print an Object Identifier into a buffer
0101  * @data: The encoded OID to print
0102  * @datasize: The size of the encoded OID
0103  * @buffer: The buffer to render into
0104  * @bufsize: The size of the buffer
0105  *
0106  * The OID is rendered into the buffer in "a.b.c.d" format and the number of
0107  * bytes is returned.  -EBADMSG is returned if the data could not be intepreted
0108  * and -ENOBUFS if the buffer was too small.
0109  */
0110 int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
0111 {
0112     const unsigned char *v = data, *end = v + datasize;
0113     unsigned long num;
0114     unsigned char n;
0115     size_t ret;
0116     int count;
0117 
0118     if (v >= end)
0119         return -EBADMSG;
0120 
0121     n = *v++;
0122     ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
0123     buffer += count;
0124     bufsize -= count;
0125     if (bufsize == 0)
0126         return -ENOBUFS;
0127 
0128     while (v < end) {
0129         num = 0;
0130         n = *v++;
0131         if (!(n & 0x80)) {
0132             num = n;
0133         } else {
0134             num = n & 0x7f;
0135             do {
0136                 if (v >= end)
0137                     return -EBADMSG;
0138                 n = *v++;
0139                 num <<= 7;
0140                 num |= n & 0x7f;
0141             } while (n & 0x80);
0142         }
0143         ret += count = snprintf(buffer, bufsize, ".%lu", num);
0144         buffer += count;
0145         bufsize -= count;
0146         if (bufsize == 0)
0147             return -ENOBUFS;
0148     }
0149 
0150     return ret;
0151 }
0152 EXPORT_SYMBOL_GPL(sprint_oid);
0153 
0154 /**
0155  * sprint_OID - Print an Object Identifier into a buffer
0156  * @oid: The OID to print
0157  * @buffer: The buffer to render into
0158  * @bufsize: The size of the buffer
0159  *
0160  * The OID is rendered into the buffer in "a.b.c.d" format and the number of
0161  * bytes is returned.
0162  */
0163 int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
0164 {
0165     int ret;
0166 
0167     BUG_ON(oid >= OID__NR);
0168 
0169     ret = sprint_oid(oid_data + oid_index[oid],
0170              oid_index[oid + 1] - oid_index[oid],
0171              buffer, bufsize);
0172     BUG_ON(ret == -EBADMSG);
0173     return ret;
0174 }
0175 EXPORT_SYMBOL_GPL(sprint_OID);