blob: 81ff8522405c29eb69675982cd3dc0407728964a [file] [log] [blame]
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -07001/*
2 * names.c -- USB name database manipulation routines
3 *
4 * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 *
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +020021 *
22 *
23 *
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +010024 * Copyright (C) 2005 Takahiro Hirofuchi
25 * - names_deinit() is added.
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +020026 *
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070027 */
28
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070029#include <sys/types.h>
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <dirent.h>
33#include <string.h>
34#include <errno.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <stdio.h>
38#include <ctype.h>
39
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070040#include "names.h"
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +020041#include "usbip_common.h"
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070042
43struct vendor {
44 struct vendor *next;
45 u_int16_t vendorid;
46 char name[1];
47};
48
49struct product {
50 struct product *next;
51 u_int16_t vendorid, productid;
52 char name[1];
53};
54
55struct class {
56 struct class *next;
57 u_int8_t classid;
58 char name[1];
59};
60
61struct subclass {
62 struct subclass *next;
63 u_int8_t classid, subclassid;
64 char name[1];
65};
66
67struct protocol {
68 struct protocol *next;
69 u_int8_t classid, subclassid, protocolid;
70 char name[1];
71};
72
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070073struct genericstrtable {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +010074 struct genericstrtable *next;
75 unsigned int num;
76 char name[1];
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070077};
78
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070079
80#define HASH1 0x10
81#define HASH2 0x02
82#define HASHSZ 16
83
84static unsigned int hashnum(unsigned int num)
85{
86 unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
87
88 for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
89 if (num & mask1)
90 num ^= mask2;
91 return num & (HASHSZ-1);
92}
93
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -070094
95static struct vendor *vendors[HASHSZ] = { NULL, };
96static struct product *products[HASHSZ] = { NULL, };
97static struct class *classes[HASHSZ] = { NULL, };
98static struct subclass *subclasses[HASHSZ] = { NULL, };
99static struct protocol *protocols[HASHSZ] = { NULL, };
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700100
101const char *names_vendor(u_int16_t vendorid)
102{
103 struct vendor *v;
104
105 v = vendors[hashnum(vendorid)];
106 for (; v; v = v->next)
107 if (v->vendorid == vendorid)
108 return v->name;
109 return NULL;
110}
111
112const char *names_product(u_int16_t vendorid, u_int16_t productid)
113{
114 struct product *p;
115
116 p = products[hashnum((vendorid << 16) | productid)];
117 for (; p; p = p->next)
118 if (p->vendorid == vendorid && p->productid == productid)
119 return p->name;
120 return NULL;
121}
122
123const char *names_class(u_int8_t classid)
124{
125 struct class *c;
126
127 c = classes[hashnum(classid)];
128 for (; c; c = c->next)
129 if (c->classid == classid)
130 return c->name;
131 return NULL;
132}
133
134const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
135{
136 struct subclass *s;
137
138 s = subclasses[hashnum((classid << 8) | subclassid)];
139 for (; s; s = s->next)
140 if (s->classid == classid && s->subclassid == subclassid)
141 return s->name;
142 return NULL;
143}
144
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100145const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
146 u_int8_t protocolid)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700147{
148 struct protocol *p;
149
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100150 p = protocols[hashnum((classid << 16) | (subclassid << 8)
151 | protocolid)];
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700152 for (; p; p = p->next)
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100153 if (p->classid == classid && p->subclassid == subclassid &&
154 p->protocolid == protocolid)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700155 return p->name;
156 return NULL;
157}
158
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700159/* add a cleanup function by takahiro */
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700160struct pool {
161 struct pool *next;
162 void *mem;
163};
164
Kurt Kanzenbach5af7746f2013-02-22 12:13:26 +0100165static struct pool *pool_head;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700166
167static void *my_malloc(size_t size)
168{
169 struct pool *p;
170
171 p = calloc(1, sizeof(struct pool));
Heinrich Schuchardt2a7470d2014-01-28 21:16:46 +0100172 if (!p)
173 return NULL;
174
175 p->mem = calloc(1, size);
176 if (!p->mem) {
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700177 free(p);
178 return NULL;
179 }
180
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700181 p->next = pool_head;
182 pool_head = p;
183
184 return p->mem;
185}
186
187void names_free(void)
188{
189 struct pool *pool;
190
191 if (!pool_head)
192 return;
193
194 for (pool = pool_head; pool != NULL; ) {
195 struct pool *tmp;
196
197 if (pool->mem)
198 free(pool->mem);
199
200 tmp = pool;
201 pool = pool->next;
202 free(tmp);
203 }
204}
205
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700206static int new_vendor(const char *name, u_int16_t vendorid)
207{
208 struct vendor *v;
209 unsigned int h = hashnum(vendorid);
210
211 v = vendors[h];
212 for (; v; v = v->next)
213 if (v->vendorid == vendorid)
214 return -1;
215 v = my_malloc(sizeof(struct vendor) + strlen(name));
216 if (!v)
217 return -1;
218 strcpy(v->name, name);
219 v->vendorid = vendorid;
220 v->next = vendors[h];
221 vendors[h] = v;
222 return 0;
223}
224
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100225static int new_product(const char *name, u_int16_t vendorid,
226 u_int16_t productid)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700227{
228 struct product *p;
229 unsigned int h = hashnum((vendorid << 16) | productid);
230
231 p = products[h];
232 for (; p; p = p->next)
233 if (p->vendorid == vendorid && p->productid == productid)
234 return -1;
235 p = my_malloc(sizeof(struct product) + strlen(name));
236 if (!p)
237 return -1;
238 strcpy(p->name, name);
239 p->vendorid = vendorid;
240 p->productid = productid;
241 p->next = products[h];
242 products[h] = p;
243 return 0;
244}
245
246static int new_class(const char *name, u_int8_t classid)
247{
248 struct class *c;
249 unsigned int h = hashnum(classid);
250
251 c = classes[h];
252 for (; c; c = c->next)
253 if (c->classid == classid)
254 return -1;
255 c = my_malloc(sizeof(struct class) + strlen(name));
256 if (!c)
257 return -1;
258 strcpy(c->name, name);
259 c->classid = classid;
260 c->next = classes[h];
261 classes[h] = c;
262 return 0;
263}
264
265static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
266{
267 struct subclass *s;
268 unsigned int h = hashnum((classid << 8) | subclassid);
269
270 s = subclasses[h];
271 for (; s; s = s->next)
272 if (s->classid == classid && s->subclassid == subclassid)
273 return -1;
274 s = my_malloc(sizeof(struct subclass) + strlen(name));
275 if (!s)
276 return -1;
277 strcpy(s->name, name);
278 s->classid = classid;
279 s->subclassid = subclassid;
280 s->next = subclasses[h];
281 subclasses[h] = s;
282 return 0;
283}
284
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100285static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
286 u_int8_t protocolid)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700287{
288 struct protocol *p;
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100289 unsigned int h = hashnum((classid << 16) | (subclassid << 8)
290 | protocolid);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700291
292 p = protocols[h];
293 for (; p; p = p->next)
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100294 if (p->classid == classid && p->subclassid == subclassid
295 && p->protocolid == protocolid)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700296 return -1;
297 p = my_malloc(sizeof(struct protocol) + strlen(name));
298 if (!p)
299 return -1;
300 strcpy(p->name, name);
301 p->classid = classid;
302 p->subclassid = subclassid;
303 p->protocolid = protocolid;
304 p->next = protocols[h];
305 protocols[h] = p;
306 return 0;
307}
308
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700309static void parse(FILE *f)
310{
311 char buf[512], *cp;
312 unsigned int linectr = 0;
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100313 int lastvendor = -1;
314 int lastclass = -1;
315 int lastsubclass = -1;
316 int lasthut = -1;
317 int lastlang = -1;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700318 unsigned int u;
319
320 while (fgets(buf, sizeof(buf), f)) {
321 linectr++;
322 /* remove line ends */
Stefan Reif69f45262013-04-04 16:03:02 +0200323 cp = strchr(buf, '\r');
Kurt Kanzenbach6f19a2b2013-02-22 12:13:30 +0100324 if (cp)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700325 *cp = 0;
Stefan Reif69f45262013-04-04 16:03:02 +0200326 cp = strchr(buf, '\n');
Kurt Kanzenbach6f19a2b2013-02-22 12:13:30 +0100327 if (cp)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700328 *cp = 0;
329 if (buf[0] == '#' || !buf[0])
330 continue;
331 cp = buf;
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200332 if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
333 buf[3] == 'S' && buf[4] == 'D' &&
334 buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
335 buf[7] == ' ') {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100336 continue;
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100337 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200338 if (buf[0] == 'P' && buf[1] == 'H' &&
339 buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100340 continue;
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100341 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200342 if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
343 buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100344 continue;
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100345 }
346 if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100347 lasthut = lastclass = lastvendor = lastsubclass = -1;
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200348 /*
349 * set 1 as pseudo-id to indicate that the parser is
350 * in a `L' section.
351 */
352 lastlang = 1;
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100353 continue;
354 }
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700355 if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
356 /* class spec */
357 cp = buf+2;
358 while (isspace(*cp))
359 cp++;
360 if (!isxdigit(*cp)) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200361 err("Invalid class spec at line %u", linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700362 continue;
363 }
364 u = strtoul(cp, &cp, 16);
365 while (isspace(*cp))
366 cp++;
367 if (!*cp) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200368 err("Invalid class spec at line %u", linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700369 continue;
370 }
371 if (new_class(cp, u))
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200372 err("Duplicate class spec at line %u class %04x %s",
373 linectr, u, cp);
374 dbg("line %5u class %02x %s", linectr, u, cp);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700375 lasthut = lastlang = lastvendor = lastsubclass = -1;
376 lastclass = u;
377 continue;
378 }
379 if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
380 /* audio terminal type spec */
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700381 continue;
382 }
Kurt Kanzenbach9db91e12013-02-22 12:13:29 +0100383 if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
384 && isspace(buf[3])) {
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700385 /* HID Descriptor bCountryCode */
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100386 continue;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700387 }
388 if (isxdigit(*cp)) {
389 /* vendor */
390 u = strtoul(cp, &cp, 16);
391 while (isspace(*cp))
392 cp++;
393 if (!*cp) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200394 err("Invalid vendor spec at line %u", linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700395 continue;
396 }
397 if (new_vendor(cp, u))
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200398 err("Duplicate vendor spec at line %u vendor %04x %s",
399 linectr, u, cp);
400 dbg("line %5u vendor %04x %s", linectr, u, cp);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700401 lastvendor = u;
402 lasthut = lastlang = lastclass = lastsubclass = -1;
403 continue;
404 }
405 if (buf[0] == '\t' && isxdigit(buf[1])) {
406 /* product or subclass spec */
407 u = strtoul(buf+1, &cp, 16);
408 while (isspace(*cp))
409 cp++;
410 if (!*cp) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200411 err("Invalid product/subclass spec at line %u",
412 linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700413 continue;
414 }
415 if (lastvendor != -1) {
416 if (new_product(cp, lastvendor, u))
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200417 err("Duplicate product spec at line %u product %04x:%04x %s",
418 linectr, lastvendor, u, cp);
419 dbg("line %5u product %04x:%04x %s", linectr,
420 lastvendor, u, cp);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700421 continue;
422 }
423 if (lastclass != -1) {
424 if (new_subclass(cp, lastclass, u))
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200425 err("Duplicate subclass spec at line %u class %02x:%02x %s",
426 linectr, lastclass, u, cp);
427 dbg("line %5u subclass %02x:%02x %s", linectr,
428 lastclass, u, cp);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700429 lastsubclass = u;
430 continue;
431 }
432 if (lasthut != -1) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200433 /* do not store hut */
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700434 continue;
435 }
436 if (lastlang != -1) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200437 /* do not store langid */
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100438 continue;
439 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200440 err("Product/Subclass spec without prior Vendor/Class spec at line %u",
441 linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700442 continue;
443 }
444 if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
445 /* protocol spec */
446 u = strtoul(buf+2, &cp, 16);
447 while (isspace(*cp))
448 cp++;
449 if (!*cp) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200450 err("Invalid protocol spec at line %u",
451 linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700452 continue;
453 }
454 if (lastclass != -1 && lastsubclass != -1) {
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200455 if (new_protocol(cp, lastclass, lastsubclass,
456 u))
457 err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
458 linectr, lastclass, lastsubclass,
459 u, cp);
460 dbg("line %5u protocol %02x:%02x:%02x %s",
461 linectr, lastclass, lastsubclass, u, cp);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700462 continue;
463 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200464 err("Protocol spec without prior Class and Subclass spec at line %u",
465 linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700466 continue;
467 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200468 if (buf[0] == 'H' && buf[1] == 'I' &&
469 buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100470 continue;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700471 }
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200472 if (buf[0] == 'H' && buf[1] == 'U' &&
473 buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700474 lastlang = lastclass = lastvendor = lastsubclass = -1;
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200475 /*
476 * set 1 as pseudo-id to indicate that the parser is
477 * in a `HUT' section.
478 */
479 lasthut = 1;
480 continue;
481 }
482 if (buf[0] == 'R' && buf[1] == ' ')
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100483 continue;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700484
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200485 if (buf[0] == 'V' && buf[1] == 'T')
Kurt Kanzenbachcbb86712013-02-22 12:13:25 +0100486 continue;
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700487
Kurt Kanzenbachb2e02282013-04-04 16:03:14 +0200488 err("Unknown line at line %u", linectr);
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700489 }
490}
491
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700492
493int names_init(char *n)
494{
495 FILE *f;
496
Kurt Kanzenbach6f19a2b2013-02-22 12:13:30 +0100497 f = fopen(n, "r");
498 if (!f)
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700499 return errno;
Kurt Kanzenbach6f19a2b2013-02-22 12:13:30 +0100500
Takahiro Hirofuchi0945b4f2011-05-14 03:55:07 -0700501 parse(f);
502 fclose(f);
503 return 0;
504}