linux/tools/usb/usbip/libsrc/names.c
<<
>>
Prefs
   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