1280183Sdumbbell/** 2280183Sdumbbell * \file drm_auth.c 3280183Sdumbbell * IOCTLs for authentication 4280183Sdumbbell * 5280183Sdumbbell * \author Rickard E. (Rik) Faith <faith@valinux.com> 6280183Sdumbbell * \author Gareth Hughes <gareth@valinux.com> 7280183Sdumbbell */ 8280183Sdumbbell 9280183Sdumbbell/* 10280183Sdumbbell * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com 11280183Sdumbbell * 12235783Skib * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 13235783Skib * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 14235783Skib * All Rights Reserved. 15235783Skib * 16235783Skib * Permission is hereby granted, free of charge, to any person obtaining a 17235783Skib * copy of this software and associated documentation files (the "Software"), 18235783Skib * to deal in the Software without restriction, including without limitation 19235783Skib * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20235783Skib * and/or sell copies of the Software, and to permit persons to whom the 21235783Skib * Software is furnished to do so, subject to the following conditions: 22235783Skib * 23235783Skib * The above copyright notice and this permission notice (including the next 24235783Skib * paragraph) shall be included in all copies or substantial portions of the 25235783Skib * Software. 26235783Skib * 27235783Skib * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28235783Skib * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29235783Skib * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30235783Skib * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31235783Skib * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32235783Skib * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33235783Skib * OTHER DEALINGS IN THE SOFTWARE. 34235783Skib */ 35235783Skib 36235783Skib#include <sys/cdefs.h> 37235783Skib__FBSDID("$FreeBSD$"); 38235783Skib 39235783Skib#include <dev/drm2/drmP.h> 40235783Skib 41280183Sdumbbellstatic struct mtx drm_magic_lock; 42235783Skib 43235783Skib/** 44280183Sdumbbell * Find the file with the given magic number. 45280183Sdumbbell * 46280183Sdumbbell * \param dev DRM device. 47280183Sdumbbell * \param magic magic number. 48280183Sdumbbell * 49280183Sdumbbell * Searches in drm_device::magiclist within all files with the same hash key 50280183Sdumbbell * the one with matching magic number, while holding the drm_device::struct_mutex 51280183Sdumbbell * lock. 52235783Skib */ 53280183Sdumbbellstatic struct drm_file *drm_find_file(struct drm_master *master, drm_magic_t magic) 54235783Skib{ 55280183Sdumbbell struct drm_file *retval = NULL; 56280183Sdumbbell struct drm_magic_entry *pt; 57280183Sdumbbell struct drm_hash_item *hash; 58280183Sdumbbell struct drm_device *dev = master->minor->dev; 59235783Skib 60280183Sdumbbell DRM_LOCK(dev); 61280183Sdumbbell if (!drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { 62280183Sdumbbell pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); 63280183Sdumbbell retval = pt->priv; 64235783Skib } 65280183Sdumbbell DRM_UNLOCK(dev); 66280183Sdumbbell return retval; 67235783Skib} 68235783Skib 69235783Skib/** 70280183Sdumbbell * Adds a magic number. 71280183Sdumbbell * 72280183Sdumbbell * \param dev DRM device. 73280183Sdumbbell * \param priv file private data. 74280183Sdumbbell * \param magic magic number. 75280183Sdumbbell * 76280183Sdumbbell * Creates a drm_magic_entry structure and appends to the linked list 77280183Sdumbbell * associated the magic number hash key in drm_device::magiclist, while holding 78280183Sdumbbell * the drm_device::struct_mutex lock. 79235783Skib */ 80280183Sdumbbellstatic int drm_add_magic(struct drm_master *master, struct drm_file *priv, 81235783Skib drm_magic_t magic) 82235783Skib{ 83280183Sdumbbell struct drm_magic_entry *entry; 84280183Sdumbbell struct drm_device *dev = master->minor->dev; 85235783Skib DRM_DEBUG("%d\n", magic); 86235783Skib 87235783Skib entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT); 88235783Skib if (!entry) 89280183Sdumbbell return -ENOMEM; 90280183Sdumbbell entry->priv = priv; 91280183Sdumbbell entry->hash_item.key = (unsigned long)magic; 92280183Sdumbbell DRM_LOCK(dev); 93280183Sdumbbell drm_ht_insert_item(&master->magiclist, &entry->hash_item); 94280183Sdumbbell list_add_tail(&entry->head, &master->magicfree); 95280183Sdumbbell DRM_UNLOCK(dev); 96235783Skib 97235783Skib return 0; 98235783Skib} 99235783Skib 100235783Skib/** 101280183Sdumbbell * Remove a magic number. 102280183Sdumbbell * 103280183Sdumbbell * \param dev DRM device. 104280183Sdumbbell * \param magic magic number. 105280183Sdumbbell * 106280183Sdumbbell * Searches and unlinks the entry in drm_device::magiclist with the magic 107280183Sdumbbell * number hash key, while holding the drm_device::struct_mutex lock. 108235783Skib */ 109280183Sdumbbellint drm_remove_magic(struct drm_master *master, drm_magic_t magic) 110235783Skib{ 111280183Sdumbbell struct drm_magic_entry *pt; 112280183Sdumbbell struct drm_hash_item *hash; 113280183Sdumbbell struct drm_device *dev = master->minor->dev; 114235783Skib 115235783Skib DRM_DEBUG("%d\n", magic); 116235783Skib 117280183Sdumbbell DRM_LOCK(dev); 118280183Sdumbbell if (drm_ht_find_item(&master->magiclist, (unsigned long)magic, &hash)) { 119280183Sdumbbell DRM_UNLOCK(dev); 120280183Sdumbbell return -EINVAL; 121235783Skib } 122280183Sdumbbell pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item); 123280183Sdumbbell drm_ht_remove_item(&master->magiclist, hash); 124280183Sdumbbell list_del(&pt->head); 125280183Sdumbbell DRM_UNLOCK(dev); 126235783Skib 127280183Sdumbbell free(pt, DRM_MEM_MAGIC); 128280183Sdumbbell 129280183Sdumbbell return 0; 130235783Skib} 131235783Skib 132235783Skib/** 133280183Sdumbbell * Get a unique magic number (ioctl). 134235783Skib * 135280183Sdumbbell * \param inode device inode. 136280183Sdumbbell * \param file_priv DRM file private. 137280183Sdumbbell * \param cmd command. 138280183Sdumbbell * \param arg pointer to a resulting drm_auth structure. 139280183Sdumbbell * \return zero on success, or a negative number on failure. 140280183Sdumbbell * 141280183Sdumbbell * If there is a magic number in drm_file::magic then use it, otherwise 142280183Sdumbbell * searches an unique non-zero magic number and add it associating it with \p 143280183Sdumbbell * file_priv. 144280183Sdumbbell * This ioctl needs protection by the drm_global_mutex, which protects 145280183Sdumbbell * struct drm_file::magic and struct drm_magic_entry::priv. 146235783Skib */ 147235783Skibint drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) 148235783Skib{ 149235783Skib static drm_magic_t sequence = 0; 150235783Skib struct drm_auth *auth = data; 151235783Skib 152235783Skib /* Find unique magic */ 153235783Skib if (file_priv->magic) { 154235783Skib auth->magic = file_priv->magic; 155235783Skib } else { 156235783Skib do { 157280183Sdumbbell mtx_lock(&drm_magic_lock); 158280183Sdumbbell if (!sequence) 159280183Sdumbbell ++sequence; /* reserve 0 */ 160280183Sdumbbell auth->magic = sequence++; 161280183Sdumbbell mtx_unlock(&drm_magic_lock); 162280183Sdumbbell } while (drm_find_file(file_priv->master, auth->magic)); 163235783Skib file_priv->magic = auth->magic; 164280183Sdumbbell drm_add_magic(file_priv->master, file_priv, auth->magic); 165235783Skib } 166235783Skib 167235783Skib DRM_DEBUG("%u\n", auth->magic); 168235783Skib 169235783Skib return 0; 170235783Skib} 171235783Skib 172235783Skib/** 173280183Sdumbbell * Authenticate with a magic. 174280183Sdumbbell * 175280183Sdumbbell * \param inode device inode. 176280183Sdumbbell * \param file_priv DRM file private. 177280183Sdumbbell * \param cmd command. 178280183Sdumbbell * \param arg pointer to a drm_auth structure. 179280183Sdumbbell * \return zero if authentication successed, or a negative number otherwise. 180280183Sdumbbell * 181280183Sdumbbell * Checks if \p file_priv is associated with the magic number passed in \arg. 182280183Sdumbbell * This ioctl needs protection by the drm_global_mutex, which protects 183280183Sdumbbell * struct drm_file::magic and struct drm_magic_entry::priv. 184235783Skib */ 185235783Skibint drm_authmagic(struct drm_device *dev, void *data, 186235783Skib struct drm_file *file_priv) 187235783Skib{ 188235783Skib struct drm_auth *auth = data; 189280183Sdumbbell struct drm_file *file; 190235783Skib 191235783Skib DRM_DEBUG("%u\n", auth->magic); 192280183Sdumbbell if ((file = drm_find_file(file_priv->master, auth->magic))) { 193280183Sdumbbell file->authenticated = 1; 194280183Sdumbbell drm_remove_magic(file_priv->master, auth->magic); 195235783Skib return 0; 196235783Skib } 197280183Sdumbbell return -EINVAL; 198235783Skib} 199280183Sdumbbell 200280183Sdumbbellstatic int 201280183Sdumbbelldrm_magic_init(void *arg) 202280183Sdumbbell{ 203280183Sdumbbell 204280183Sdumbbell mtx_init(&drm_magic_lock, "drm_getmagic__lock", NULL, MTX_DEF); 205280183Sdumbbell return (0); 206280183Sdumbbell} 207280183Sdumbbell 208280183Sdumbbellstatic void 209280183Sdumbbelldrm_magic_fini(void *arg) 210280183Sdumbbell{ 211280183Sdumbbell 212280183Sdumbbell mtx_destroy(&drm_magic_lock); 213280183Sdumbbell} 214280183Sdumbbell 215280183SdumbbellSYSINIT(drm_magic_init, SI_SUB_KLD, SI_ORDER_MIDDLE, drm_magic_init, NULL); 216280183SdumbbellSYSUNINIT(drm_magic_fini, SI_SUB_KLD, SI_ORDER_MIDDLE, drm_magic_fini, NULL); 217