names.c (10679B)
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}