2019-05-20 09:19:02 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2011-05-14 03:55:07 -07:00
/*
* names . c - - USB name database manipulation routines
*
* Copyright ( C ) 1999 , 2000 Thomas Sailer ( sailer @ ife . ee . ethz . ch )
*
2013-02-22 12:13:25 +01:00
* Copyright ( C ) 2005 Takahiro Hirofuchi
* - names_deinit ( ) is added .
2011-05-14 03:55:07 -07:00
*/
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <dirent.h>
# include <string.h>
# include <errno.h>
# include <stdlib.h>
# include <unistd.h>
# include <stdio.h>
# include <ctype.h>
# include "names.h"
2013-04-04 16:03:14 +02:00
# include "usbip_common.h"
2011-05-14 03:55:07 -07:00
struct vendor {
struct vendor * next ;
u_int16_t vendorid ;
char name [ 1 ] ;
} ;
struct product {
struct product * next ;
u_int16_t vendorid , productid ;
char name [ 1 ] ;
} ;
struct class {
struct class * next ;
u_int8_t classid ;
char name [ 1 ] ;
} ;
struct subclass {
struct subclass * next ;
u_int8_t classid , subclassid ;
char name [ 1 ] ;
} ;
struct protocol {
struct protocol * next ;
u_int8_t classid , subclassid , protocolid ;
char name [ 1 ] ;
} ;
struct genericstrtable {
2013-02-22 12:13:25 +01:00
struct genericstrtable * next ;
unsigned int num ;
char name [ 1 ] ;
2011-05-14 03:55:07 -07:00
} ;
# define HASH1 0x10
# define HASH2 0x02
# define HASHSZ 16
static unsigned int hashnum ( unsigned int num )
{
unsigned int mask1 = HASH1 < < 27 , mask2 = HASH2 < < 27 ;
for ( ; mask1 > = HASH1 ; mask1 > > = 1 , mask2 > > = 1 )
if ( num & mask1 )
num ^ = mask2 ;
return num & ( HASHSZ - 1 ) ;
}
static struct vendor * vendors [ HASHSZ ] = { NULL , } ;
static struct product * products [ HASHSZ ] = { NULL , } ;
static struct class * classes [ HASHSZ ] = { NULL , } ;
static struct subclass * subclasses [ HASHSZ ] = { NULL , } ;
static struct protocol * protocols [ HASHSZ ] = { NULL , } ;
const char * names_vendor ( u_int16_t vendorid )
{
struct vendor * v ;
v = vendors [ hashnum ( vendorid ) ] ;
for ( ; v ; v = v - > next )
if ( v - > vendorid = = vendorid )
return v - > name ;
return NULL ;
}
const char * names_product ( u_int16_t vendorid , u_int16_t productid )
{
struct product * p ;
p = products [ hashnum ( ( vendorid < < 16 ) | productid ) ] ;
for ( ; p ; p = p - > next )
if ( p - > vendorid = = vendorid & & p - > productid = = productid )
return p - > name ;
return NULL ;
}
const char * names_class ( u_int8_t classid )
{
struct class * c ;
c = classes [ hashnum ( classid ) ] ;
for ( ; c ; c = c - > next )
if ( c - > classid = = classid )
return c - > name ;
return NULL ;
}
const char * names_subclass ( u_int8_t classid , u_int8_t subclassid )
{
struct subclass * s ;
s = subclasses [ hashnum ( ( classid < < 8 ) | subclassid ) ] ;
for ( ; s ; s = s - > next )
if ( s - > classid = = classid & & s - > subclassid = = subclassid )
return s - > name ;
return NULL ;
}
2013-02-22 12:13:29 +01:00
const char * names_protocol ( u_int8_t classid , u_int8_t subclassid ,
u_int8_t protocolid )
2011-05-14 03:55:07 -07:00
{
struct protocol * p ;
2013-02-22 12:13:29 +01:00
p = protocols [ hashnum ( ( classid < < 16 ) | ( subclassid < < 8 )
| protocolid ) ] ;
2011-05-14 03:55:07 -07:00
for ( ; p ; p = p - > next )
2013-02-22 12:13:29 +01:00
if ( p - > classid = = classid & & p - > subclassid = = subclassid & &
p - > protocolid = = protocolid )
2011-05-14 03:55:07 -07:00
return p - > name ;
return NULL ;
}
/* add a cleanup function by takahiro */
struct pool {
struct pool * next ;
void * mem ;
} ;
2013-02-22 12:13:26 +01:00
static struct pool * pool_head ;
2011-05-14 03:55:07 -07:00
static void * my_malloc ( size_t size )
{
struct pool * p ;
p = calloc ( 1 , sizeof ( struct pool ) ) ;
2014-01-28 21:16:46 +01:00
if ( ! p )
2011-05-14 03:55:07 -07:00
return NULL ;
p - > mem = calloc ( 1 , size ) ;
2014-01-28 21:16:46 +01:00
if ( ! p - > mem ) {
free ( p ) ;
2011-05-14 03:55:07 -07:00
return NULL ;
2014-01-28 21:16:46 +01:00
}
2011-05-14 03:55:07 -07:00
p - > next = pool_head ;
pool_head = p ;
return p - > mem ;
}
void names_free ( void )
{
struct pool * pool ;
if ( ! pool_head )
return ;
for ( pool = pool_head ; pool ! = NULL ; ) {
struct pool * tmp ;
if ( pool - > mem )
free ( pool - > mem ) ;
tmp = pool ;
pool = pool - > next ;
free ( tmp ) ;
}
}
static int new_vendor ( const char * name , u_int16_t vendorid )
{
struct vendor * v ;
unsigned int h = hashnum ( vendorid ) ;
v = vendors [ h ] ;
for ( ; v ; v = v - > next )
if ( v - > vendorid = = vendorid )
return - 1 ;
v = my_malloc ( sizeof ( struct vendor ) + strlen ( name ) ) ;
if ( ! v )
return - 1 ;
strcpy ( v - > name , name ) ;
v - > vendorid = vendorid ;
v - > next = vendors [ h ] ;
vendors [ h ] = v ;
return 0 ;
}
2013-02-22 12:13:29 +01:00
static int new_product ( const char * name , u_int16_t vendorid ,
u_int16_t productid )
2011-05-14 03:55:07 -07:00
{
struct product * p ;
unsigned int h = hashnum ( ( vendorid < < 16 ) | productid ) ;
p = products [ h ] ;
for ( ; p ; p = p - > next )
if ( p - > vendorid = = vendorid & & p - > productid = = productid )
return - 1 ;
p = my_malloc ( sizeof ( struct product ) + strlen ( name ) ) ;
if ( ! p )
return - 1 ;
strcpy ( p - > name , name ) ;
p - > vendorid = vendorid ;
p - > productid = productid ;
p - > next = products [ h ] ;
products [ h ] = p ;
return 0 ;
}
static int new_class ( const char * name , u_int8_t classid )
{
struct class * c ;
unsigned int h = hashnum ( classid ) ;
c = classes [ h ] ;
for ( ; c ; c = c - > next )
if ( c - > classid = = classid )
return - 1 ;
c = my_malloc ( sizeof ( struct class ) + strlen ( name ) ) ;
if ( ! c )
return - 1 ;
strcpy ( c - > name , name ) ;
c - > classid = classid ;
c - > next = classes [ h ] ;
classes [ h ] = c ;
return 0 ;
}
static int new_subclass ( const char * name , u_int8_t classid , u_int8_t subclassid )
{
struct subclass * s ;
unsigned int h = hashnum ( ( classid < < 8 ) | subclassid ) ;
s = subclasses [ h ] ;
for ( ; s ; s = s - > next )
if ( s - > classid = = classid & & s - > subclassid = = subclassid )
return - 1 ;
s = my_malloc ( sizeof ( struct subclass ) + strlen ( name ) ) ;
if ( ! s )
return - 1 ;
strcpy ( s - > name , name ) ;
s - > classid = classid ;
s - > subclassid = subclassid ;
s - > next = subclasses [ h ] ;
subclasses [ h ] = s ;
return 0 ;
}
2013-02-22 12:13:29 +01:00
static int new_protocol ( const char * name , u_int8_t classid , u_int8_t subclassid ,
u_int8_t protocolid )
2011-05-14 03:55:07 -07:00
{
struct protocol * p ;
2013-02-22 12:13:29 +01:00
unsigned int h = hashnum ( ( classid < < 16 ) | ( subclassid < < 8 )
| protocolid ) ;
2011-05-14 03:55:07 -07:00
p = protocols [ h ] ;
for ( ; p ; p = p - > next )
2013-02-22 12:13:29 +01:00
if ( p - > classid = = classid & & p - > subclassid = = subclassid
& & p - > protocolid = = protocolid )
2011-05-14 03:55:07 -07:00
return - 1 ;
p = my_malloc ( sizeof ( struct protocol ) + strlen ( name ) ) ;
if ( ! p )
return - 1 ;
strcpy ( p - > name , name ) ;
p - > classid = classid ;
p - > subclassid = subclassid ;
p - > protocolid = protocolid ;
p - > next = protocols [ h ] ;
protocols [ h ] = p ;
return 0 ;
}
static void parse ( FILE * f )
{
char buf [ 512 ] , * cp ;
unsigned int linectr = 0 ;
2013-02-22 12:13:29 +01:00
int lastvendor = - 1 ;
int lastclass = - 1 ;
int lastsubclass = - 1 ;
int lasthut = - 1 ;
int lastlang = - 1 ;
2011-05-14 03:55:07 -07:00
unsigned int u ;
while ( fgets ( buf , sizeof ( buf ) , f ) ) {
linectr + + ;
/* remove line ends */
2013-04-04 16:03:02 +02:00
cp = strchr ( buf , ' \r ' ) ;
2013-02-22 12:13:30 +01:00
if ( cp )
2011-05-14 03:55:07 -07:00
* cp = 0 ;
2013-04-04 16:03:02 +02:00
cp = strchr ( buf , ' \n ' ) ;
2013-02-22 12:13:30 +01:00
if ( cp )
2011-05-14 03:55:07 -07:00
* cp = 0 ;
if ( buf [ 0 ] = = ' # ' | | ! buf [ 0 ] )
continue ;
cp = buf ;
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' P ' & & buf [ 1 ] = = ' H ' & & buf [ 2 ] = = ' Y ' & &
buf [ 3 ] = = ' S ' & & buf [ 4 ] = = ' D ' & &
buf [ 5 ] = = ' E ' & & buf [ 6 ] = = ' S ' & & /*isspace(buf[7])*/
buf [ 7 ] = = ' ' ) {
2013-02-22 12:13:25 +01:00
continue ;
}
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' P ' & & buf [ 1 ] = = ' H ' & &
buf [ 2 ] = = ' Y ' & & /*isspace(buf[3])*/ buf [ 3 ] = = ' ' ) {
2013-02-22 12:13:25 +01:00
continue ;
}
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' B ' & & buf [ 1 ] = = ' I ' & & buf [ 2 ] = = ' A ' & &
buf [ 3 ] = = ' S ' & & /*isspace(buf[4])*/ buf [ 4 ] = = ' ' ) {
2013-02-22 12:13:25 +01:00
continue ;
}
if ( buf [ 0 ] = = ' L ' & & /*isspace(buf[1])*/ buf [ 1 ] = = ' ' ) {
lasthut = lastclass = lastvendor = lastsubclass = - 1 ;
2013-04-04 16:03:14 +02:00
/*
* set 1 as pseudo - id to indicate that the parser is
* in a ` L ' section .
*/
lastlang = 1 ;
2013-02-22 12:13:25 +01:00
continue ;
}
2011-05-14 03:55:07 -07:00
if ( buf [ 0 ] = = ' C ' & & /*isspace(buf[1])*/ buf [ 1 ] = = ' ' ) {
/* class spec */
cp = buf + 2 ;
while ( isspace ( * cp ) )
cp + + ;
if ( ! isxdigit ( * cp ) ) {
2013-04-04 16:03:14 +02:00
err ( " Invalid class spec at line %u " , linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
u = strtoul ( cp , & cp , 16 ) ;
while ( isspace ( * cp ) )
cp + + ;
if ( ! * cp ) {
2013-04-04 16:03:14 +02:00
err ( " Invalid class spec at line %u " , linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( new_class ( cp , u ) )
2013-04-04 16:03:14 +02:00
err ( " Duplicate class spec at line %u class %04x %s " ,
linectr , u , cp ) ;
dbg ( " line %5u class %02x %s " , linectr , u , cp ) ;
2011-05-14 03:55:07 -07:00
lasthut = lastlang = lastvendor = lastsubclass = - 1 ;
lastclass = u ;
continue ;
}
if ( buf [ 0 ] = = ' A ' & & buf [ 1 ] = = ' T ' & & isspace ( buf [ 2 ] ) ) {
/* audio terminal type spec */
continue ;
}
2013-02-22 12:13:29 +01:00
if ( buf [ 0 ] = = ' H ' & & buf [ 1 ] = = ' C ' & & buf [ 2 ] = = ' C '
& & isspace ( buf [ 3 ] ) ) {
2011-05-14 03:55:07 -07:00
/* HID Descriptor bCountryCode */
2013-02-22 12:13:25 +01:00
continue ;
2011-05-14 03:55:07 -07:00
}
if ( isxdigit ( * cp ) ) {
/* vendor */
u = strtoul ( cp , & cp , 16 ) ;
while ( isspace ( * cp ) )
cp + + ;
if ( ! * cp ) {
2013-04-04 16:03:14 +02:00
err ( " Invalid vendor spec at line %u " , linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( new_vendor ( cp , u ) )
2013-04-04 16:03:14 +02:00
err ( " Duplicate vendor spec at line %u vendor %04x %s " ,
linectr , u , cp ) ;
dbg ( " line %5u vendor %04x %s " , linectr , u , cp ) ;
2011-05-14 03:55:07 -07:00
lastvendor = u ;
lasthut = lastlang = lastclass = lastsubclass = - 1 ;
continue ;
}
if ( buf [ 0 ] = = ' \t ' & & isxdigit ( buf [ 1 ] ) ) {
/* product or subclass spec */
u = strtoul ( buf + 1 , & cp , 16 ) ;
while ( isspace ( * cp ) )
cp + + ;
if ( ! * cp ) {
2013-04-04 16:03:14 +02:00
err ( " Invalid product/subclass spec at line %u " ,
linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( lastvendor ! = - 1 ) {
if ( new_product ( cp , lastvendor , u ) )
2013-04-04 16:03:14 +02:00
err ( " Duplicate product spec at line %u product %04x:%04x %s " ,
linectr , lastvendor , u , cp ) ;
dbg ( " line %5u product %04x:%04x %s " , linectr ,
lastvendor , u , cp ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( lastclass ! = - 1 ) {
if ( new_subclass ( cp , lastclass , u ) )
2013-04-04 16:03:14 +02:00
err ( " Duplicate subclass spec at line %u class %02x:%02x %s " ,
linectr , lastclass , u , cp ) ;
dbg ( " line %5u subclass %02x:%02x %s " , linectr ,
lastclass , u , cp ) ;
2011-05-14 03:55:07 -07:00
lastsubclass = u ;
continue ;
}
if ( lasthut ! = - 1 ) {
2013-04-04 16:03:14 +02:00
/* do not store hut */
2011-05-14 03:55:07 -07:00
continue ;
}
if ( lastlang ! = - 1 ) {
2013-04-04 16:03:14 +02:00
/* do not store langid */
2013-02-22 12:13:25 +01:00
continue ;
}
2013-04-04 16:03:14 +02:00
err ( " Product/Subclass spec without prior Vendor/Class spec at line %u " ,
linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( buf [ 0 ] = = ' \t ' & & buf [ 1 ] = = ' \t ' & & isxdigit ( buf [ 2 ] ) ) {
/* protocol spec */
u = strtoul ( buf + 2 , & cp , 16 ) ;
while ( isspace ( * cp ) )
cp + + ;
if ( ! * cp ) {
2013-04-04 16:03:14 +02:00
err ( " Invalid protocol spec at line %u " ,
linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
if ( lastclass ! = - 1 & & lastsubclass ! = - 1 ) {
2013-04-04 16:03:14 +02:00
if ( new_protocol ( cp , lastclass , lastsubclass ,
u ) )
err ( " Duplicate protocol spec at line %u class %02x:%02x:%02x %s " ,
linectr , lastclass , lastsubclass ,
u , cp ) ;
dbg ( " line %5u protocol %02x:%02x:%02x %s " ,
linectr , lastclass , lastsubclass , u , cp ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
2013-04-04 16:03:14 +02:00
err ( " Protocol spec without prior Class and Subclass spec at line %u " ,
linectr ) ;
2011-05-14 03:55:07 -07:00
continue ;
}
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' H ' & & buf [ 1 ] = = ' I ' & &
buf [ 2 ] = = ' D ' & & /*isspace(buf[3])*/ buf [ 3 ] = = ' ' ) {
2013-02-22 12:13:25 +01:00
continue ;
2011-05-14 03:55:07 -07:00
}
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' H ' & & buf [ 1 ] = = ' U ' & &
buf [ 2 ] = = ' T ' & & /*isspace(buf[3])*/ buf [ 3 ] = = ' ' ) {
2011-05-14 03:55:07 -07:00
lastlang = lastclass = lastvendor = lastsubclass = - 1 ;
2013-04-04 16:03:14 +02:00
/*
* set 1 as pseudo - id to indicate that the parser is
* in a ` HUT ' section .
*/
lasthut = 1 ;
2013-02-22 12:13:25 +01:00
continue ;
}
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' R ' & & buf [ 1 ] = = ' ' )
2013-02-22 12:13:25 +01:00
continue ;
2013-04-04 16:03:14 +02:00
if ( buf [ 0 ] = = ' V ' & & buf [ 1 ] = = ' T ' )
2011-05-14 03:55:07 -07:00
continue ;
2013-04-04 16:03:14 +02:00
err ( " Unknown line at line %u " , linectr ) ;
2011-05-14 03:55:07 -07:00
}
}
int names_init ( char * n )
{
FILE * f ;
2013-02-22 12:13:30 +01:00
f = fopen ( n , " r " ) ;
if ( ! f )
2011-05-14 03:55:07 -07:00
return errno ;
2013-02-22 12:13:30 +01:00
2011-05-14 03:55:07 -07:00
parse ( f ) ;
fclose ( f ) ;
return 0 ;
}