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(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((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(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((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((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(vendorid);
192
193	v = vendors[h];
194	for (; v; v = v->next)
195		if (v->vendorid == vendorid)
196			return -1;
197	v = my_malloc(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((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(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(classid);
232
233	c = classes[h];
234	for (; c; c = c->next)
235		if (c->classid == classid)
236			return -1;
237	c = my_malloc(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((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(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((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(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(cp, 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(cp, 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(cp, lastvendor, 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(cp, lastclass, 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(cp, lastclass, lastsubclass,
438						 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