• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 struct vendor {
26 	struct vendor *next;
27 	u_int16_t vendorid;
28 	char name[1];
29 };
30 
31 struct product {
32 	struct product *next;
33 	u_int16_t vendorid, productid;
34 	char name[1];
35 };
36 
37 struct class {
38 	struct class *next;
39 	u_int8_t classid;
40 	char name[1];
41 };
42 
43 struct subclass {
44 	struct subclass *next;
45 	u_int8_t classid, subclassid;
46 	char name[1];
47 };
48 
49 struct protocol {
50 	struct protocol *next;
51 	u_int8_t classid, subclassid, protocolid;
52 	char name[1];
53 };
54 
55 struct 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 
hashnum(unsigned int num)66 static 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 
77 static struct vendor *vendors[HASHSZ] = { NULL, };
78 static struct product *products[HASHSZ] = { NULL, };
79 static struct class *classes[HASHSZ] = { NULL, };
80 static struct subclass *subclasses[HASHSZ] = { NULL, };
81 static struct protocol *protocols[HASHSZ] = { NULL, };
82 
names_vendor(u_int16_t vendorid)83 const 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 
names_product(u_int16_t vendorid,u_int16_t productid)94 const 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 
names_class(u_int8_t classid)105 const 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 
names_subclass(u_int8_t classid,u_int8_t subclassid)116 const 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 
names_protocol(u_int8_t classid,u_int8_t subclassid,u_int8_t protocolid)127 const 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 */
142 struct pool {
143 	struct pool *next;
144 	void *mem;
145 };
146 
147 static struct pool *pool_head;
148 
my_malloc(size_t size)149 static 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 
names_free(void)169 void 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 
new_vendor(const char * name,u_int16_t vendorid)188 static 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 
new_product(const char * name,u_int16_t vendorid,u_int16_t productid)207 static 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 
new_class(const char * name,u_int8_t classid)228 static 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 
new_subclass(const char * name,u_int8_t classid,u_int8_t subclassid)247 static 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 
new_protocol(const char * name,u_int8_t classid,u_int8_t subclassid,u_int8_t protocolid)267 static 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 
parse(FILE * f)291 static 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 
names_init(char * n)475 int 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