2005-04-16 15:20:36 -07:00
/**
2005-09-25 14:28:13 +10:00
* \ file drm_auth . c
2005-04-16 15:20:36 -07:00
* IOCTLs for authentication
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Created : Tue Feb 2 08 : 37 : 54 1999 by faith @ valinux . com
*
* Copyright 1999 Precision Insight , Inc . , Cedar Park , Texas .
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* VA LINUX SYSTEMS AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*/
# include "drmP.h"
/**
* Generate a hash key from a magic .
*
* \ param magic magic .
* \ return hash key .
*
* The key is the modulus of the hash table size , # DRM_HASH_SIZE , which must be
* a power of 2.
*/
static int drm_hash_magic ( drm_magic_t magic )
{
2005-09-25 14:28:13 +10:00
return magic & ( DRM_HASH_SIZE - 1 ) ;
2005-04-16 15:20:36 -07:00
}
/**
* Find the file with the given magic number .
*
* \ param dev DRM device .
* \ param magic magic number .
*
* Searches in drm_device : : magiclist within all files with the same hash key
2006-02-02 19:37:46 +11:00
* the one with matching magic number , while holding the drm_device : : struct_mutex
2005-04-16 15:20:36 -07:00
* lock .
*/
2005-09-25 14:28:13 +10:00
static drm_file_t * drm_find_file ( drm_device_t * dev , drm_magic_t magic )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
drm_file_t * retval = NULL ;
2005-04-16 15:20:36 -07:00
drm_magic_entry_t * pt ;
2005-09-25 14:28:13 +10:00
int hash = drm_hash_magic ( magic ) ;
2005-04-16 15:20:36 -07:00
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( pt = dev - > magiclist [ hash ] . head ; pt ; pt = pt - > next ) {
if ( pt - > magic = = magic ) {
retval = pt - > priv ;
break ;
}
}
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return retval ;
}
/**
* Adds a magic number .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param dev DRM device .
* \ param priv file private data .
* \ param magic magic number .
*
* Creates a drm_magic_entry structure and appends to the linked list
* associated the magic number hash key in drm_device : : magiclist , while holding
2006-02-02 19:37:46 +11:00
* the drm_device : : struct_mutex lock .
2005-04-16 15:20:36 -07:00
*/
2005-09-25 14:28:13 +10:00
static int drm_add_magic ( drm_device_t * dev , drm_file_t * priv ,
drm_magic_t magic )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
int hash ;
2005-04-16 15:20:36 -07:00
drm_magic_entry_t * entry ;
DRM_DEBUG ( " %d \n " , magic ) ;
2005-09-25 14:28:13 +10:00
hash = drm_hash_magic ( magic ) ;
entry = drm_alloc ( sizeof ( * entry ) , DRM_MEM_MAGIC ) ;
if ( ! entry )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
memset ( entry , 0 , sizeof ( * entry ) ) ;
entry - > magic = magic ;
2005-09-25 14:28:13 +10:00
entry - > priv = priv ;
entry - > next = NULL ;
2005-04-16 15:20:36 -07:00
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( dev - > magiclist [ hash ] . tail ) {
dev - > magiclist [ hash ] . tail - > next = entry ;
2005-09-25 14:28:13 +10:00
dev - > magiclist [ hash ] . tail = entry ;
2005-04-16 15:20:36 -07:00
} else {
2005-09-25 14:28:13 +10:00
dev - > magiclist [ hash ] . head = entry ;
dev - > magiclist [ hash ] . tail = entry ;
2005-04-16 15:20:36 -07:00
}
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/**
* Remove a magic number .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param dev DRM device .
* \ param magic magic number .
*
* Searches and unlinks the entry in drm_device : : magiclist with the magic
2006-02-02 19:37:46 +11:00
* number hash key , while holding the drm_device : : struct_mutex lock .
2005-04-16 15:20:36 -07:00
*/
2005-09-25 14:28:13 +10:00
static int drm_remove_magic ( drm_device_t * dev , drm_magic_t magic )
2005-04-16 15:20:36 -07:00
{
drm_magic_entry_t * prev = NULL ;
drm_magic_entry_t * pt ;
2005-09-25 14:28:13 +10:00
int hash ;
2005-04-16 15:20:36 -07:00
DRM_DEBUG ( " %d \n " , magic ) ;
hash = drm_hash_magic ( magic ) ;
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( pt = dev - > magiclist [ hash ] . head ; pt ; prev = pt , pt = pt - > next ) {
if ( pt - > magic = = magic ) {
if ( dev - > magiclist [ hash ] . head = = pt ) {
dev - > magiclist [ hash ] . head = pt - > next ;
}
if ( dev - > magiclist [ hash ] . tail = = pt ) {
dev - > magiclist [ hash ] . tail = prev ;
}
if ( prev ) {
prev - > next = pt - > next ;
}
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
}
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
drm_free ( pt , sizeof ( * pt ) , DRM_MEM_MAGIC ) ;
return - EINVAL ;
}
/**
* Get a unique magic number ( ioctl ) .
*
* \ param inode device inode .
* \ param filp file pointer .
* \ param cmd command .
* \ param arg pointer to a resulting drm_auth structure .
* \ return zero on success , or a negative number on failure .
*
* If there is a magic number in drm_file : : magic then use it , otherwise
* searches an unique non - zero magic number and add it associating it with \ p
* filp .
*/
int drm_getmagic ( struct inode * inode , struct file * filp ,
2005-09-25 14:28:13 +10:00
unsigned int cmd , unsigned long arg )
2005-04-16 15:20:36 -07:00
{
static drm_magic_t sequence = 0 ;
static DEFINE_SPINLOCK ( lock ) ;
2005-09-25 14:28:13 +10:00
drm_file_t * priv = filp - > private_data ;
drm_device_t * dev = priv - > head - > dev ;
drm_auth_t auth ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
/* Find unique magic */
2005-04-16 15:20:36 -07:00
if ( priv - > magic ) {
auth . magic = priv - > magic ;
} else {
do {
spin_lock ( & lock ) ;
2005-09-25 14:28:13 +10:00
if ( ! sequence )
+ + sequence ; /* reserve 0 */
2005-04-16 15:20:36 -07:00
auth . magic = sequence + + ;
spin_unlock ( & lock ) ;
} while ( drm_find_file ( dev , auth . magic ) ) ;
priv - > magic = auth . magic ;
drm_add_magic ( dev , priv , auth . magic ) ;
}
DRM_DEBUG ( " %u \n " , auth . magic ) ;
2005-09-25 14:28:13 +10:00
if ( copy_to_user ( ( drm_auth_t __user * ) arg , & auth , sizeof ( auth ) ) )
2005-04-16 15:20:36 -07:00
return - EFAULT ;
return 0 ;
}
/**
* Authenticate with a magic .
*
* \ param inode device inode .
* \ param filp file pointer .
* \ param cmd command .
* \ param arg pointer to a drm_auth structure .
* \ return zero if authentication successed , or a negative number otherwise .
*
* Checks if \ p filp is associated with the magic number passed in \ arg .
*/
int drm_authmagic ( struct inode * inode , struct file * filp ,
2005-09-25 14:28:13 +10:00
unsigned int cmd , unsigned long arg )
2005-04-16 15:20:36 -07:00
{
2005-09-25 14:28:13 +10:00
drm_file_t * priv = filp - > private_data ;
drm_device_t * dev = priv - > head - > dev ;
drm_auth_t auth ;
drm_file_t * file ;
2005-04-16 15:20:36 -07:00
2005-09-25 14:28:13 +10:00
if ( copy_from_user ( & auth , ( drm_auth_t __user * ) arg , sizeof ( auth ) ) )
2005-04-16 15:20:36 -07:00
return - EFAULT ;
DRM_DEBUG ( " %u \n " , auth . magic ) ;
if ( ( file = drm_find_file ( dev , auth . magic ) ) ) {
file - > authenticated = 1 ;
drm_remove_magic ( dev , auth . magic ) ;
return 0 ;
}
return - EINVAL ;
}