Commit | Line | Data |
---|---|---|
0945b4fe TH |
1 | /* |
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 | * | |
b2e02284 KK |
21 | * |
22 | * | |
23 | * | |
cbb86718 KK |
24 | * Copyright (C) 2005 Takahiro Hirofuchi |
25 | * - names_deinit() is added. | |
b2e02284 | 26 | * |
0945b4fe TH |
27 | */ |
28 | ||
0945b4fe TH |
29 | #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 | ||
0945b4fe | 40 | #include "names.h" |
b2e02284 | 41 | #include "usbip_common.h" |
0945b4fe TH |
42 | |
43 | struct vendor { | |
44 | struct vendor *next; | |
45 | u_int16_t vendorid; | |
46 | char name[1]; | |
47 | }; | |
48 | ||
49 | struct product { | |
50 | struct product *next; | |
51 | u_int16_t vendorid, productid; | |
52 | char name[1]; | |
53 | }; | |
54 | ||
55 | struct class { | |
56 | struct class *next; | |
57 | u_int8_t classid; | |
58 | char name[1]; | |
59 | }; | |
60 | ||
61 | struct subclass { | |
62 | struct subclass *next; | |
63 | u_int8_t classid, subclassid; | |
64 | char name[1]; | |
65 | }; | |
66 | ||
67 | struct protocol { | |
68 | struct protocol *next; | |
69 | u_int8_t classid, subclassid, protocolid; | |
70 | char name[1]; | |
71 | }; | |
72 | ||
0945b4fe | 73 | struct genericstrtable { |
cbb86718 KK |
74 | struct genericstrtable *next; |
75 | unsigned int num; | |
76 | char name[1]; | |
0945b4fe TH |
77 | }; |
78 | ||
0945b4fe TH |
79 | |
80 | #define HASH1 0x10 | |
81 | #define HASH2 0x02 | |
82 | #define HASHSZ 16 | |
83 | ||
84 | static 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 | ||
0945b4fe TH |
94 | |
95 | static struct vendor *vendors[HASHSZ] = { NULL, }; | |
96 | static struct product *products[HASHSZ] = { NULL, }; | |
97 | static struct class *classes[HASHSZ] = { NULL, }; | |
98 | static struct subclass *subclasses[HASHSZ] = { NULL, }; | |
99 | static struct protocol *protocols[HASHSZ] = { NULL, }; | |
0945b4fe TH |
100 | |
101 | const 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 | ||
112 | const 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 | ||
123 | const 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 | ||
134 | const 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 | ||
9db91e1b KK |
145 | const char *names_protocol(u_int8_t classid, u_int8_t subclassid, |
146 | u_int8_t protocolid) | |
0945b4fe TH |
147 | { |
148 | struct protocol *p; | |
149 | ||
9db91e1b KK |
150 | p = protocols[hashnum((classid << 16) | (subclassid << 8) |
151 | | protocolid)]; | |
0945b4fe | 152 | for (; p; p = p->next) |
9db91e1b KK |
153 | if (p->classid == classid && p->subclassid == subclassid && |
154 | p->protocolid == protocolid) | |
0945b4fe TH |
155 | return p->name; |
156 | return NULL; | |
157 | } | |
158 | ||
0945b4fe | 159 | /* add a cleanup function by takahiro */ |
0945b4fe TH |
160 | struct pool { |
161 | struct pool *next; | |
162 | void *mem; | |
163 | }; | |
164 | ||
5af7746f | 165 | static struct pool *pool_head; |
0945b4fe TH |
166 | |
167 | static void *my_malloc(size_t size) | |
168 | { | |
169 | struct pool *p; | |
170 | ||
171 | p = calloc(1, sizeof(struct pool)); | |
2a7470d9 | 172 | if (!p) |
0945b4fe | 173 | return NULL; |
0945b4fe TH |
174 | |
175 | p->mem = calloc(1, size); | |
2a7470d9 HS |
176 | if (!p->mem) { |
177 | free(p); | |
0945b4fe | 178 | return NULL; |
2a7470d9 | 179 | } |
0945b4fe TH |
180 | |
181 | p->next = pool_head; | |
182 | pool_head = p; | |
183 | ||
184 | return p->mem; | |
185 | } | |
186 | ||
187 | void 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 | ||
0945b4fe TH |
206 | static 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 | ||
9db91e1b KK |
225 | static int new_product(const char *name, u_int16_t vendorid, |
226 | u_int16_t productid) | |
0945b4fe TH |
227 | { |
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 | ||
246 | static 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 | ||
265 | static 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 | ||
9db91e1b KK |
285 | static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, |
286 | u_int8_t protocolid) | |
0945b4fe TH |
287 | { |
288 | struct protocol *p; | |
9db91e1b KK |
289 | unsigned int h = hashnum((classid << 16) | (subclassid << 8) |
290 | | protocolid); | |
0945b4fe TH |
291 | |
292 | p = protocols[h]; | |
293 | for (; p; p = p->next) | |
9db91e1b KK |
294 | if (p->classid == classid && p->subclassid == subclassid |
295 | && p->protocolid == protocolid) | |
0945b4fe TH |
296 | 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 | ||
0945b4fe TH |
309 | static void parse(FILE *f) |
310 | { | |
311 | char buf[512], *cp; | |
312 | unsigned int linectr = 0; | |
9db91e1b KK |
313 | int lastvendor = -1; |
314 | int lastclass = -1; | |
315 | int lastsubclass = -1; | |
316 | int lasthut = -1; | |
317 | int lastlang = -1; | |
0945b4fe TH |
318 | unsigned int u; |
319 | ||
320 | while (fgets(buf, sizeof(buf), f)) { | |
321 | linectr++; | |
322 | /* remove line ends */ | |
69f45263 | 323 | cp = strchr(buf, '\r'); |
6f19a2b1 | 324 | if (cp) |
0945b4fe | 325 | *cp = 0; |
69f45263 | 326 | cp = strchr(buf, '\n'); |
6f19a2b1 | 327 | if (cp) |
0945b4fe TH |
328 | *cp = 0; |
329 | if (buf[0] == '#' || !buf[0]) | |
330 | continue; | |
331 | cp = buf; | |
b2e02284 KK |
332 | 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] == ' ') { | |
cbb86718 | 336 | continue; |
cbb86718 | 337 | } |
b2e02284 KK |
338 | if (buf[0] == 'P' && buf[1] == 'H' && |
339 | buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { | |
cbb86718 | 340 | continue; |
cbb86718 | 341 | } |
b2e02284 KK |
342 | if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && |
343 | buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { | |
cbb86718 | 344 | continue; |
cbb86718 KK |
345 | } |
346 | if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { | |
cbb86718 | 347 | lasthut = lastclass = lastvendor = lastsubclass = -1; |
b2e02284 KK |
348 | /* |
349 | * set 1 as pseudo-id to indicate that the parser is | |
350 | * in a `L' section. | |
351 | */ | |
352 | lastlang = 1; | |
cbb86718 KK |
353 | continue; |
354 | } | |
0945b4fe TH |
355 | 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)) { | |
b2e02284 | 361 | err("Invalid class spec at line %u", linectr); |
0945b4fe TH |
362 | continue; |
363 | } | |
364 | u = strtoul(cp, &cp, 16); | |
365 | while (isspace(*cp)) | |
366 | cp++; | |
367 | if (!*cp) { | |
b2e02284 | 368 | err("Invalid class spec at line %u", linectr); |
0945b4fe TH |
369 | continue; |
370 | } | |
371 | if (new_class(cp, u)) | |
b2e02284 KK |
372 | err("Duplicate class spec at line %u class %04x %s", |
373 | linectr, u, cp); | |
374 | dbg("line %5u class %02x %s", linectr, u, cp); | |
0945b4fe TH |
375 | 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 */ | |
0945b4fe TH |
381 | continue; |
382 | } | |
9db91e1b KK |
383 | if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' |
384 | && isspace(buf[3])) { | |
0945b4fe | 385 | /* HID Descriptor bCountryCode */ |
cbb86718 | 386 | continue; |
0945b4fe TH |
387 | } |
388 | if (isxdigit(*cp)) { | |
389 | /* vendor */ | |
390 | u = strtoul(cp, &cp, 16); | |
391 | while (isspace(*cp)) | |
392 | cp++; | |
393 | if (!*cp) { | |
b2e02284 | 394 | err("Invalid vendor spec at line %u", linectr); |
0945b4fe TH |
395 | continue; |
396 | } | |
397 | if (new_vendor(cp, u)) | |
b2e02284 KK |
398 | err("Duplicate vendor spec at line %u vendor %04x %s", |
399 | linectr, u, cp); | |
400 | dbg("line %5u vendor %04x %s", linectr, u, cp); | |
0945b4fe TH |
401 | 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) { | |
b2e02284 KK |
411 | err("Invalid product/subclass spec at line %u", |
412 | linectr); | |
0945b4fe TH |
413 | continue; |
414 | } | |
415 | if (lastvendor != -1) { | |
416 | if (new_product(cp, lastvendor, u)) | |
b2e02284 KK |
417 | 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); | |
0945b4fe TH |
421 | continue; |
422 | } | |
423 | if (lastclass != -1) { | |
424 | if (new_subclass(cp, lastclass, u)) | |
b2e02284 KK |
425 | 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); | |
0945b4fe TH |
429 | lastsubclass = u; |
430 | continue; | |
431 | } | |
432 | if (lasthut != -1) { | |
b2e02284 | 433 | /* do not store hut */ |
0945b4fe TH |
434 | continue; |
435 | } | |
436 | if (lastlang != -1) { | |
b2e02284 | 437 | /* do not store langid */ |
cbb86718 KK |
438 | continue; |
439 | } | |
b2e02284 KK |
440 | err("Product/Subclass spec without prior Vendor/Class spec at line %u", |
441 | linectr); | |
0945b4fe TH |
442 | 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) { | |
b2e02284 KK |
450 | err("Invalid protocol spec at line %u", |
451 | linectr); | |
0945b4fe TH |
452 | continue; |
453 | } | |
454 | if (lastclass != -1 && lastsubclass != -1) { | |
b2e02284 KK |
455 | 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); | |
0945b4fe TH |
462 | continue; |
463 | } | |
b2e02284 KK |
464 | err("Protocol spec without prior Class and Subclass spec at line %u", |
465 | linectr); | |
0945b4fe TH |
466 | continue; |
467 | } | |
b2e02284 KK |
468 | if (buf[0] == 'H' && buf[1] == 'I' && |
469 | buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { | |
cbb86718 | 470 | continue; |
0945b4fe | 471 | } |
b2e02284 KK |
472 | if (buf[0] == 'H' && buf[1] == 'U' && |
473 | buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { | |
0945b4fe | 474 | lastlang = lastclass = lastvendor = lastsubclass = -1; |
b2e02284 KK |
475 | /* |
476 | * set 1 as pseudo-id to indicate that the parser is | |
477 | * in a `HUT' section. | |
478 | */ | |
479 | lasthut = 1; | |
cbb86718 | 480 | continue; |
cbb86718 | 481 | } |
b2e02284 | 482 | if (buf[0] == 'R' && buf[1] == ' ') |
cbb86718 KK |
483 | continue; |
484 | ||
b2e02284 | 485 | if (buf[0] == 'V' && buf[1] == 'T') |
0945b4fe | 486 | continue; |
b2e02284 KK |
487 | |
488 | err("Unknown line at line %u", linectr); | |
0945b4fe TH |
489 | } |
490 | } | |
491 | ||
0945b4fe TH |
492 | |
493 | int names_init(char *n) | |
494 | { | |
495 | FILE *f; | |
496 | ||
6f19a2b1 KK |
497 | f = fopen(n, "r"); |
498 | if (!f) | |
0945b4fe | 499 | return errno; |
6f19a2b1 | 500 | |
0945b4fe TH |
501 | parse(f); |
502 | fclose(f); | |
503 | return 0; | |
504 | } |