misc cleanup patch from Adrian Bunk
[platform/upstream/libdrm.git] / linux-core / drm_auth.c
1 /**
2  * \file drm_auth.c
3  * IOCTLs for authentication
4  *
5  * \author Rickard E. (Rik) Faith <faith@valinux.com>
6  * \author Gareth Hughes <gareth@valinux.com>
7  */
8
9 /*
10  * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
11  *
12  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14  * All Rights Reserved.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining a
17  * copy of this software and associated documentation files (the "Software"),
18  * to deal in the Software without restriction, including without limitation
19  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20  * and/or sell copies of the Software, and to permit persons to whom the
21  * Software is furnished to do so, subject to the following conditions:
22  *
23  * The above copyright notice and this permission notice (including the next
24  * paragraph) shall be included in all copies or substantial portions of the
25  * Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
30  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33  * OTHER DEALINGS IN THE SOFTWARE.
34  */
35
36 #include "drmP.h"
37
38 /**
39  * Generate a hash key from a magic.
40  *
41  * \param magic magic.
42  * \return hash key.
43  *
44  * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
45  * a power of 2.
46  */
47 static int drm_hash_magic(drm_magic_t magic)
48 {
49         return magic & (DRM_HASH_SIZE - 1);
50 }
51
52 /**
53  * Find the file with the given magic number.
54  *
55  * \param dev DRM device.
56  * \param magic magic number.
57  *
58  * Searches in drm_device::magiclist within all files with the same hash key
59  * the one with matching magic number, while holding the drm_device::struct_sem
60  * lock.
61  */
62 static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
63 {
64         drm_file_t *retval = NULL;
65         drm_magic_entry_t *pt;
66         int hash = drm_hash_magic(magic);
67
68         down(&dev->struct_sem);
69         for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
70                 if (pt->magic == magic) {
71                         retval = pt->priv;
72                         break;
73                 }
74         }
75         up(&dev->struct_sem);
76         return retval;
77 }
78
79 /**
80  * Adds a magic number.
81  *
82  * \param dev DRM device.
83  * \param priv file private data.
84  * \param magic magic number.
85  *
86  * Creates a drm_magic_entry structure and appends to the linked list
87  * associated the magic number hash key in drm_device::magiclist, while holding
88  * the drm_device::struct_sem lock.
89  */
90 static int drm_add_magic(drm_device_t * dev, drm_file_t * priv, drm_magic_t magic)
91 {
92         int hash;
93         drm_magic_entry_t *entry;
94
95         DRM_DEBUG("%d\n", magic);
96
97         hash = drm_hash_magic(magic);
98         entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
99         if (!entry)
100                 return -ENOMEM;
101         memset(entry, 0, sizeof(*entry));
102         entry->magic = magic;
103         entry->priv = priv;
104         entry->next = NULL;
105
106         down(&dev->struct_sem);
107         if (dev->magiclist[hash].tail) {
108                 dev->magiclist[hash].tail->next = entry;
109                 dev->magiclist[hash].tail = entry;
110         } else {
111                 dev->magiclist[hash].head = entry;
112                 dev->magiclist[hash].tail = entry;
113         }
114         up(&dev->struct_sem);
115
116         return 0;
117 }
118
119 /**
120  * Remove a magic number.
121  *
122  * \param dev DRM device.
123  * \param magic magic number.
124  *
125  * Searches and unlinks the entry in drm_device::magiclist with the magic
126  * number hash key, while holding the drm_device::struct_sem lock.
127  */
128 static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
129 {
130         drm_magic_entry_t *prev = NULL;
131         drm_magic_entry_t *pt;
132         int hash;
133
134         DRM_DEBUG("%d\n", magic);
135         hash = drm_hash_magic(magic);
136
137         down(&dev->struct_sem);
138         for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
139                 if (pt->magic == magic) {
140                         if (dev->magiclist[hash].head == pt) {
141                                 dev->magiclist[hash].head = pt->next;
142                         }
143                         if (dev->magiclist[hash].tail == pt) {
144                                 dev->magiclist[hash].tail = prev;
145                         }
146                         if (prev) {
147                                 prev->next = pt->next;
148                         }
149                         up(&dev->struct_sem);
150                         return 0;
151                 }
152         }
153         up(&dev->struct_sem);
154
155         drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
156
157         return -EINVAL;
158 }
159
160 /**
161  * Get a unique magic number (ioctl).
162  *
163  * \param inode device inode.
164  * \param filp file pointer.
165  * \param cmd command.
166  * \param arg pointer to a resulting drm_auth structure.
167  * \return zero on success, or a negative number on failure.
168  *
169  * If there is a magic number in drm_file::magic then use it, otherwise
170  * searches an unique non-zero magic number and add it associating it with \p
171  * filp.
172  */
173 int drm_getmagic(struct inode *inode, struct file *filp,
174                  unsigned int cmd, unsigned long arg)
175 {
176         static drm_magic_t sequence = 0;
177         static spinlock_t lock = SPIN_LOCK_UNLOCKED;
178         drm_file_t *priv = filp->private_data;
179         drm_device_t *dev = priv->head->dev;
180         drm_auth_t auth;
181
182         /* Find unique magic */
183         if (priv->magic) {
184                 auth.magic = priv->magic;
185         } else {
186                 do {
187                         spin_lock(&lock);
188                         if (!sequence)
189                                 ++sequence;     /* reserve 0 */
190                         auth.magic = sequence++;
191                         spin_unlock(&lock);
192                 } while (drm_find_file(dev, auth.magic));
193                 priv->magic = auth.magic;
194                 drm_add_magic(dev, priv, auth.magic);
195         }
196
197         DRM_DEBUG("%u\n", auth.magic);
198         if (copy_to_user((drm_auth_t __user *) arg, &auth, sizeof(auth)))
199                 return -EFAULT;
200         return 0;
201 }
202
203 /**
204  * Authenticate with a magic.
205  *
206  * \param inode device inode.
207  * \param filp file pointer.
208  * \param cmd command.
209  * \param arg pointer to a drm_auth structure.
210  * \return zero if authentication successed, or a negative number otherwise.
211  *
212  * Checks if \p filp is associated with the magic number passed in \arg.
213  */
214 int drm_authmagic(struct inode *inode, struct file *filp,
215                   unsigned int cmd, unsigned long arg)
216 {
217         drm_file_t *priv = filp->private_data;
218         drm_device_t *dev = priv->head->dev;
219         drm_auth_t auth;
220         drm_file_t *file;
221
222         if (copy_from_user(&auth, (drm_auth_t __user *) arg, sizeof(auth)))
223                 return -EFAULT;
224         DRM_DEBUG("%u\n", auth.magic);
225         if ((file = drm_find_file(dev, auth.magic))) {
226                 file->authenticated = 1;
227                 drm_remove_magic(dev, auth.magic);
228                 return 0;
229         }
230         return -EINVAL;
231 }