linux/lib/oid_registry.c
<<
>>
Prefs
   1/* ASN.1 Object identifier (OID) registry
   2 *
   3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#include <linux/export.h>
  13#include <linux/oid_registry.h>
  14#include <linux/kernel.h>
  15#include <linux/errno.h>
  16#include <linux/bug.h>
  17#include "oid_registry_data.c"
  18
  19/**
  20 * look_up_OID - Find an OID registration for the specified data
  21 * @data: Binary representation of the OID
  22 * @datasize: Size of the binary representation
  23 */
  24enum OID look_up_OID(const void *data, size_t datasize)
  25{
  26        const unsigned char *octets = data;
  27        enum OID oid;
  28        unsigned char xhash;
  29        unsigned i, j, k, hash;
  30        size_t len;
  31
  32        /* Hash the OID data */
  33        hash = datasize - 1;
  34
  35        for (i = 0; i < datasize; i++)
  36                hash += octets[i] * 33;
  37        hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
  38        hash &= 0xff;
  39
  40        /* Binary search the OID registry.  OIDs are stored in ascending order
  41         * of hash value then ascending order of size and then in ascending
  42         * order of reverse value.
  43         */
  44        i = 0;
  45        k = OID__NR;
  46        while (i < k) {
  47                j = (i + k) / 2;
  48
  49                xhash = oid_search_table[j].hash;
  50                if (xhash > hash) {
  51                        k = j;
  52                        continue;
  53                }
  54                if (xhash < hash) {
  55                        i = j + 1;
  56                        continue;
  57                }
  58
  59                oid = oid_search_table[j].oid;
  60                len = oid_index[oid + 1] - oid_index[oid];
  61                if (len > datasize) {
  62                        k = j;
  63                        continue;
  64                }
  65                if (len < datasize) {
  66                        i = j + 1;
  67                        continue;
  68                }
  69
  70                /* Variation is most likely to be at the tail end of the
  71                 * OID, so do the comparison in reverse.
  72                 */
  73                while (len > 0) {
  74                        unsigned char a = oid_data[oid_index[oid] + --len];
  75                        unsigned char b = octets[len];
  76                        if (a > b) {
  77                                k = j;
  78                                goto next;
  79                        }
  80                        if (a < b) {
  81                                i = j + 1;
  82                                goto next;
  83                        }
  84                }
  85                return oid;
  86        next:
  87                ;
  88        }
  89
  90        return OID__NR;
  91}
  92EXPORT_SYMBOL_GPL(look_up_OID);
  93
  94/*
  95 * sprint_OID - Print an Object Identifier into a buffer
  96 * @data: The encoded OID to print
  97 * @datasize: The size of the encoded OID
  98 * @buffer: The buffer to render into
  99 * @bufsize: The size of the buffer
 100 *
 101 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 102 * bytes is returned.  -EBADMSG is returned if the data could not be intepreted
 103 * and -ENOBUFS if the buffer was too small.
 104 */
 105int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
 106{
 107        const unsigned char *v = data, *end = v + datasize;
 108        unsigned long num;
 109        unsigned char n;
 110        size_t ret;
 111        int count;
 112
 113        if (v >= end)
 114                return -EBADMSG;
 115
 116        n = *v++;
 117        ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
 118        buffer += count;
 119        bufsize -= count;
 120        if (bufsize == 0)
 121                return -ENOBUFS;
 122
 123        while (v < end) {
 124                num = 0;
 125                n = *v++;
 126                if (!(n & 0x80)) {
 127                        num = n;
 128                } else {
 129                        num = n & 0x7f;
 130                        do {
 131                                if (v >= end)
 132                                        return -EBADMSG;
 133                                n = *v++;
 134                                num <<= 7;
 135                                num |= n & 0x7f;
 136                        } while (n & 0x80);
 137                }
 138                ret += count = snprintf(buffer, bufsize, ".%lu", num);
 139                buffer += count;
 140                bufsize -= count;
 141                if (bufsize == 0)
 142                        return -ENOBUFS;
 143        }
 144
 145        return ret;
 146}
 147EXPORT_SYMBOL_GPL(sprint_oid);
 148
 149/**
 150 * sprint_OID - Print an Object Identifier into a buffer
 151 * @oid: The OID to print
 152 * @buffer: The buffer to render into
 153 * @bufsize: The size of the buffer
 154 *
 155 * The OID is rendered into the buffer in "a.b.c.d" format and the number of
 156 * bytes is returned.
 157 */
 158int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
 159{
 160        int ret;
 161
 162        BUG_ON(oid >= OID__NR);
 163
 164        ret = sprint_oid(oid_data + oid_index[oid],
 165                         oid_index[oid + 1] - oid_index[oid],
 166                         buffer, bufsize);
 167        BUG_ON(ret == -EBADMSG);
 168        return ret;
 169}
 170EXPORT_SYMBOL_GPL(sprint_OID);
 171
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.