487 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * names.c -- USB name database manipulation routines4 *5 * Copyright (C) 1999, 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)6 *7 * Copyright (C) 2005 Takahiro Hirofuchi8 * - 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 0x1063#define HASH2 0x0264#define HASHSZ 1665 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 == subclassid277 && 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 is332 * 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 is459 * 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