1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * names.c -- USB name database manipulation routines
4 *
5 * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
6 *
7 * Copyright (C) 2005 Takahiro Hirofuchi
8 * - names_deinit() is added.
9 */
10
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <dirent.h>
15#include <string.h>
16#include <errno.h>
17#include <stdlib.h>
18#include <unistd.h>
19#include <stdio.h>
20#include <ctype.h>
21
22#include "names.h"
23#include "usbip_common.h"
24
25struct vendor {
26 struct vendor *next;
27 u_int16_t vendorid;
28 char name[1];
29};
30
31struct product {
32 struct product *next;
33 u_int16_t vendorid, productid;
34 char name[1];
35};
36
37struct class {
38 struct class *next;
39 u_int8_t classid;
40 char name[1];
41};
42
43struct subclass {
44 struct subclass *next;
45 u_int8_t classid, subclassid;
46 char name[1];
47};
48
49struct protocol {
50 struct protocol *next;
51 u_int8_t classid, subclassid, protocolid;
52 char name[1];
53};
54
55struct genericstrtable {
56 struct genericstrtable *next;
57 unsigned int num;
58 char name[1];
59};
60
61
62#define HASH1 0x10
63#define HASH2 0x02
64#define HASHSZ 16
65
66static unsigned int hashnum(unsigned int num)
67{
68 unsigned int mask1 = HASH1 << 27, mask2 = HASH2 << 27;
69
70 for (; mask1 >= HASH1; mask1 >>= 1, mask2 >>= 1)
71 if (num & mask1)
72 num ^= mask2;
73 return num & (HASHSZ-1);
74}
75
76
77static struct vendor *vendors[HASHSZ] = { NULL, };
78static struct product *products[HASHSZ] = { NULL, };
79static struct class *classes[HASHSZ] = { NULL, };
80static struct subclass *subclasses[HASHSZ] = { NULL, };
81static struct protocol *protocols[HASHSZ] = { NULL, };
82
83const char *names_vendor(u_int16_t vendorid)
84{
85 struct vendor *v;
86
87 v = vendors[hashnum(num: vendorid)];
88 for (; v; v = v->next)
89 if (v->vendorid == vendorid)
90 return v->name;
91 return NULL;
92}
93
94const char *names_product(u_int16_t vendorid, u_int16_t productid)
95{
96 struct product *p;
97
98 p = products[hashnum(num: (vendorid << 16) | productid)];
99 for (; p; p = p->next)
100 if (p->vendorid == vendorid && p->productid == productid)
101 return p->name;
102 return NULL;
103}
104
105const char *names_class(u_int8_t classid)
106{
107 struct class *c;
108
109 c = classes[hashnum(num: classid)];
110 for (; c; c = c->next)
111 if (c->classid == classid)
112 return c->name;
113 return NULL;
114}
115
116const char *names_subclass(u_int8_t classid, u_int8_t subclassid)
117{
118 struct subclass *s;
119
120 s = subclasses[hashnum(num: (classid << 8) | subclassid)];
121 for (; s; s = s->next)
122 if (s->classid == classid && s->subclassid == subclassid)
123 return s->name;
124 return NULL;
125}
126
127const char *names_protocol(u_int8_t classid, u_int8_t subclassid,
128 u_int8_t protocolid)
129{
130 struct protocol *p;
131
132 p = protocols[hashnum(num: (classid << 16) | (subclassid << 8)
133 | protocolid)];
134 for (; p; p = p->next)
135 if (p->classid == classid && p->subclassid == subclassid &&
136 p->protocolid == protocolid)
137 return p->name;
138 return NULL;
139}
140
141/* add a cleanup function by takahiro */
142struct pool {
143 struct pool *next;
144 void *mem;
145};
146
147static struct pool *pool_head;
148
149static void *my_malloc(size_t size)
150{
151 struct pool *p;
152
153 p = calloc(1, sizeof(struct pool));
154 if (!p)
155 return NULL;
156
157 p->mem = calloc(1, size);
158 if (!p->mem) {
159 free(p);
160 return NULL;
161 }
162
163 p->next = pool_head;
164 pool_head = p;
165
166 return p->mem;
167}
168
169void names_free(void)
170{
171 struct pool *pool;
172
173 if (!pool_head)
174 return;
175
176 for (pool = pool_head; pool != NULL; ) {
177 struct pool *tmp;
178
179 if (pool->mem)
180 free(pool->mem);
181
182 tmp = pool;
183 pool = pool->next;
184 free(tmp);
185 }
186}
187
188static int new_vendor(const char *name, u_int16_t vendorid)
189{
190 struct vendor *v;
191 unsigned int h = hashnum(num: vendorid);
192
193 v = vendors[h];
194 for (; v; v = v->next)
195 if (v->vendorid == vendorid)
196 return -1;
197 v = my_malloc(size: sizeof(struct vendor) + strlen(name));
198 if (!v)
199 return -1;
200 strcpy(v->name, name);
201 v->vendorid = vendorid;
202 v->next = vendors[h];
203 vendors[h] = v;
204 return 0;
205}
206
207static int new_product(const char *name, u_int16_t vendorid,
208 u_int16_t productid)
209{
210 struct product *p;
211 unsigned int h = hashnum(num: (vendorid << 16) | productid);
212
213 p = products[h];
214 for (; p; p = p->next)
215 if (p->vendorid == vendorid && p->productid == productid)
216 return -1;
217 p = my_malloc(size: sizeof(struct product) + strlen(name));
218 if (!p)
219 return -1;
220 strcpy(p->name, name);
221 p->vendorid = vendorid;
222 p->productid = productid;
223 p->next = products[h];
224 products[h] = p;
225 return 0;
226}
227
228static int new_class(const char *name, u_int8_t classid)
229{
230 struct class *c;
231 unsigned int h = hashnum(num: classid);
232
233 c = classes[h];
234 for (; c; c = c->next)
235 if (c->classid == classid)
236 return -1;
237 c = my_malloc(size: sizeof(struct class) + strlen(name));
238 if (!c)
239 return -1;
240 strcpy(c->name, name);
241 c->classid = classid;
242 c->next = classes[h];
243 classes[h] = c;
244 return 0;
245}
246
247static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid)
248{
249 struct subclass *s;
250 unsigned int h = hashnum(num: (classid << 8) | subclassid);
251
252 s = subclasses[h];
253 for (; s; s = s->next)
254 if (s->classid == classid && s->subclassid == subclassid)
255 return -1;
256 s = my_malloc(size: sizeof(struct subclass) + strlen(name));
257 if (!s)
258 return -1;
259 strcpy(s->name, name);
260 s->classid = classid;
261 s->subclassid = subclassid;
262 s->next = subclasses[h];
263 subclasses[h] = s;
264 return 0;
265}
266
267static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid,
268 u_int8_t protocolid)
269{
270 struct protocol *p;
271 unsigned int h = hashnum(num: (classid << 16) | (subclassid << 8)
272 | protocolid);
273
274 p = protocols[h];
275 for (; p; p = p->next)
276 if (p->classid == classid && p->subclassid == subclassid
277 && p->protocolid == protocolid)
278 return -1;
279 p = my_malloc(size: sizeof(struct protocol) + strlen(name));
280 if (!p)
281 return -1;
282 strcpy(p->name, name);
283 p->classid = classid;
284 p->subclassid = subclassid;
285 p->protocolid = protocolid;
286 p->next = protocols[h];
287 protocols[h] = p;
288 return 0;
289}
290
291static void parse(FILE *f)
292{
293 char buf[512], *cp;
294 unsigned int linectr = 0;
295 int lastvendor = -1;
296 int lastclass = -1;
297 int lastsubclass = -1;
298 int lasthut = -1;
299 int lastlang = -1;
300 unsigned int u;
301
302 while (fgets(buf, sizeof(buf), f)) {
303 linectr++;
304 /* remove line ends */
305 cp = strchr(buf, '\r');
306 if (cp)
307 *cp = 0;
308 cp = strchr(buf, '\n');
309 if (cp)
310 *cp = 0;
311 if (buf[0] == '#' || !buf[0])
312 continue;
313 cp = buf;
314 if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' &&
315 buf[3] == 'S' && buf[4] == 'D' &&
316 buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/
317 buf[7] == ' ') {
318 continue;
319 }
320 if (buf[0] == 'P' && buf[1] == 'H' &&
321 buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') {
322 continue;
323 }
324 if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' &&
325 buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') {
326 continue;
327 }
328 if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') {
329 lasthut = lastclass = lastvendor = lastsubclass = -1;
330 /*
331 * set 1 as pseudo-id to indicate that the parser is
332 * in a `L' section.
333 */
334 lastlang = 1;
335 continue;
336 }
337 if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') {
338 /* class spec */
339 cp = buf+2;
340 while (isspace(*cp))
341 cp++;
342 if (!isxdigit(*cp)) {
343 err("Invalid class spec at line %u", linectr);
344 continue;
345 }
346 u = strtoul(cp, &cp, 16);
347 while (isspace(*cp))
348 cp++;
349 if (!*cp) {
350 err("Invalid class spec at line %u", linectr);
351 continue;
352 }
353 if (new_class(name: cp, classid: u))
354 err("Duplicate class spec at line %u class %04x %s",
355 linectr, u, cp);
356 dbg("line %5u class %02x %s", linectr, u, cp);
357 lasthut = lastlang = lastvendor = lastsubclass = -1;
358 lastclass = u;
359 continue;
360 }
361 if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) {
362 /* audio terminal type spec */
363 continue;
364 }
365 if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C'
366 && isspace(buf[3])) {
367 /* HID Descriptor bCountryCode */
368 continue;
369 }
370 if (isxdigit(*cp)) {
371 /* vendor */
372 u = strtoul(cp, &cp, 16);
373 while (isspace(*cp))
374 cp++;
375 if (!*cp) {
376 err("Invalid vendor spec at line %u", linectr);
377 continue;
378 }
379 if (new_vendor(name: cp, vendorid: u))
380 err("Duplicate vendor spec at line %u vendor %04x %s",
381 linectr, u, cp);
382 dbg("line %5u vendor %04x %s", linectr, u, cp);
383 lastvendor = u;
384 lasthut = lastlang = lastclass = lastsubclass = -1;
385 continue;
386 }
387 if (buf[0] == '\t' && isxdigit(buf[1])) {
388 /* product or subclass spec */
389 u = strtoul(buf+1, &cp, 16);
390 while (isspace(*cp))
391 cp++;
392 if (!*cp) {
393 err("Invalid product/subclass spec at line %u",
394 linectr);
395 continue;
396 }
397 if (lastvendor != -1) {
398 if (new_product(name: cp, vendorid: lastvendor, productid: u))
399 err("Duplicate product spec at line %u product %04x:%04x %s",
400 linectr, lastvendor, u, cp);
401 dbg("line %5u product %04x:%04x %s", linectr,
402 lastvendor, u, cp);
403 continue;
404 }
405 if (lastclass != -1) {
406 if (new_subclass(name: cp, classid: lastclass, subclassid: u))
407 err("Duplicate subclass spec at line %u class %02x:%02x %s",
408 linectr, lastclass, u, cp);
409 dbg("line %5u subclass %02x:%02x %s", linectr,
410 lastclass, u, cp);
411 lastsubclass = u;
412 continue;
413 }
414 if (lasthut != -1) {
415 /* do not store hut */
416 continue;
417 }
418 if (lastlang != -1) {
419 /* do not store langid */
420 continue;
421 }
422 err("Product/Subclass spec without prior Vendor/Class spec at line %u",
423 linectr);
424 continue;
425 }
426 if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) {
427 /* protocol spec */
428 u = strtoul(buf+2, &cp, 16);
429 while (isspace(*cp))
430 cp++;
431 if (!*cp) {
432 err("Invalid protocol spec at line %u",
433 linectr);
434 continue;
435 }
436 if (lastclass != -1 && lastsubclass != -1) {
437 if (new_protocol(name: cp, classid: lastclass, subclassid: lastsubclass,
438 protocolid: u))
439 err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s",
440 linectr, lastclass, lastsubclass,
441 u, cp);
442 dbg("line %5u protocol %02x:%02x:%02x %s",
443 linectr, lastclass, lastsubclass, u, cp);
444 continue;
445 }
446 err("Protocol spec without prior Class and Subclass spec at line %u",
447 linectr);
448 continue;
449 }
450 if (buf[0] == 'H' && buf[1] == 'I' &&
451 buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') {
452 continue;
453 }
454 if (buf[0] == 'H' && buf[1] == 'U' &&
455 buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') {
456 lastlang = lastclass = lastvendor = lastsubclass = -1;
457 /*
458 * set 1 as pseudo-id to indicate that the parser is
459 * in a `HUT' section.
460 */
461 lasthut = 1;
462 continue;
463 }
464 if (buf[0] == 'R' && buf[1] == ' ')
465 continue;
466
467 if (buf[0] == 'V' && buf[1] == 'T')
468 continue;
469
470 err("Unknown line at line %u", linectr);
471 }
472}
473
474
475int names_init(char *n)
476{
477 FILE *f;
478
479 f = fopen(n, "r");
480 if (!f)
481 return errno;
482
483 parse(f);
484 fclose(f);
485 return 0;
486}
487

source code of linux/tools/usb/usbip/libsrc/names.c