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