xref: /dflybsd-src/sys/dev/drm/drm_auth.c (revision b3705d716ab5621c5cac8741394ad6cab7e5c99b)
17f3c3d6fSHasso Tepper /*-
27f3c3d6fSHasso Tepper  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
37f3c3d6fSHasso Tepper  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
47f3c3d6fSHasso Tepper  * All Rights Reserved.
57f3c3d6fSHasso Tepper  *
67f3c3d6fSHasso Tepper  * Permission is hereby granted, free of charge, to any person obtaining a
77f3c3d6fSHasso Tepper  * copy of this software and associated documentation files (the "Software"),
87f3c3d6fSHasso Tepper  * to deal in the Software without restriction, including without limitation
97f3c3d6fSHasso Tepper  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107f3c3d6fSHasso Tepper  * and/or sell copies of the Software, and to permit persons to whom the
117f3c3d6fSHasso Tepper  * Software is furnished to do so, subject to the following conditions:
127f3c3d6fSHasso Tepper  *
137f3c3d6fSHasso Tepper  * The above copyright notice and this permission notice (including the next
147f3c3d6fSHasso Tepper  * paragraph) shall be included in all copies or substantial portions of the
157f3c3d6fSHasso Tepper  * Software.
167f3c3d6fSHasso Tepper  *
177f3c3d6fSHasso Tepper  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
187f3c3d6fSHasso Tepper  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197f3c3d6fSHasso Tepper  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207f3c3d6fSHasso Tepper  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
217f3c3d6fSHasso Tepper  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
227f3c3d6fSHasso Tepper  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
237f3c3d6fSHasso Tepper  * OTHER DEALINGS IN THE SOFTWARE.
247f3c3d6fSHasso Tepper  *
257f3c3d6fSHasso Tepper  * Authors:
267f3c3d6fSHasso Tepper  *    Rickard E. (Rik) Faith <faith@valinux.com>
277f3c3d6fSHasso Tepper  *    Gareth Hughes <gareth@valinux.com>
287f3c3d6fSHasso Tepper  *
297f3c3d6fSHasso Tepper  */
307f3c3d6fSHasso Tepper 
317f3c3d6fSHasso Tepper /** @file drm_auth.c
327f3c3d6fSHasso Tepper  * Implementation of the get/authmagic ioctls implementing the authentication
337f3c3d6fSHasso Tepper  * scheme between the master and clients.
347f3c3d6fSHasso Tepper  */
357f3c3d6fSHasso Tepper 
36*b3705d71SHasso Tepper #include "dev/drm/drmP.h"
377f3c3d6fSHasso Tepper 
387f3c3d6fSHasso Tepper static int drm_hash_magic(drm_magic_t magic)
397f3c3d6fSHasso Tepper {
407f3c3d6fSHasso Tepper 	return magic & (DRM_HASH_SIZE-1);
417f3c3d6fSHasso Tepper }
427f3c3d6fSHasso Tepper 
437f3c3d6fSHasso Tepper /**
447f3c3d6fSHasso Tepper  * Returns the file private associated with the given magic number.
457f3c3d6fSHasso Tepper  */
46*b3705d71SHasso Tepper static struct drm_file *drm_find_file(struct drm_device *dev, drm_magic_t magic)
477f3c3d6fSHasso Tepper {
487f3c3d6fSHasso Tepper 	drm_magic_entry_t *pt;
497f3c3d6fSHasso Tepper 	int hash = drm_hash_magic(magic);
507f3c3d6fSHasso Tepper 
517f3c3d6fSHasso Tepper 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
527f3c3d6fSHasso Tepper 
537f3c3d6fSHasso Tepper 	for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
547f3c3d6fSHasso Tepper 		if (pt->magic == magic) {
557f3c3d6fSHasso Tepper 			return pt->priv;
567f3c3d6fSHasso Tepper 		}
577f3c3d6fSHasso Tepper 	}
587f3c3d6fSHasso Tepper 
597f3c3d6fSHasso Tepper 	return NULL;
607f3c3d6fSHasso Tepper }
617f3c3d6fSHasso Tepper 
627f3c3d6fSHasso Tepper /**
637f3c3d6fSHasso Tepper  * Inserts the given magic number into the hash table of used magic number
647f3c3d6fSHasso Tepper  * lists.
657f3c3d6fSHasso Tepper  */
66*b3705d71SHasso Tepper static int drm_add_magic(struct drm_device *dev, struct drm_file *priv,
67*b3705d71SHasso Tepper 			 drm_magic_t magic)
687f3c3d6fSHasso Tepper {
697f3c3d6fSHasso Tepper 	int		  hash;
707f3c3d6fSHasso Tepper 	drm_magic_entry_t *entry;
717f3c3d6fSHasso Tepper 
727f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", magic);
737f3c3d6fSHasso Tepper 
747f3c3d6fSHasso Tepper 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
757f3c3d6fSHasso Tepper 
767f3c3d6fSHasso Tepper 	hash = drm_hash_magic(magic);
77*b3705d71SHasso Tepper 	entry = malloc(sizeof(*entry), DRM_MEM_MAGIC, M_ZERO | M_NOWAIT);
78*b3705d71SHasso Tepper 	if (!entry)
79*b3705d71SHasso Tepper 		return ENOMEM;
807f3c3d6fSHasso Tepper 	entry->magic = magic;
817f3c3d6fSHasso Tepper 	entry->priv  = priv;
827f3c3d6fSHasso Tepper 	entry->next  = NULL;
837f3c3d6fSHasso Tepper 
847f3c3d6fSHasso Tepper 	if (dev->magiclist[hash].tail) {
857f3c3d6fSHasso Tepper 		dev->magiclist[hash].tail->next = entry;
867f3c3d6fSHasso Tepper 		dev->magiclist[hash].tail	= entry;
877f3c3d6fSHasso Tepper 	} else {
887f3c3d6fSHasso Tepper 		dev->magiclist[hash].head	= entry;
897f3c3d6fSHasso Tepper 		dev->magiclist[hash].tail	= entry;
907f3c3d6fSHasso Tepper 	}
917f3c3d6fSHasso Tepper 
927f3c3d6fSHasso Tepper 	return 0;
937f3c3d6fSHasso Tepper }
947f3c3d6fSHasso Tepper 
957f3c3d6fSHasso Tepper /**
967f3c3d6fSHasso Tepper  * Removes the given magic number from the hash table of used magic number
977f3c3d6fSHasso Tepper  * lists.
987f3c3d6fSHasso Tepper  */
99*b3705d71SHasso Tepper static int drm_remove_magic(struct drm_device *dev, drm_magic_t magic)
1007f3c3d6fSHasso Tepper {
1017f3c3d6fSHasso Tepper 	drm_magic_entry_t *prev = NULL;
1027f3c3d6fSHasso Tepper 	drm_magic_entry_t *pt;
1037f3c3d6fSHasso Tepper 	int		  hash;
1047f3c3d6fSHasso Tepper 
1057f3c3d6fSHasso Tepper 	DRM_SPINLOCK_ASSERT(&dev->dev_lock);
1067f3c3d6fSHasso Tepper 
1077f3c3d6fSHasso Tepper 	DRM_DEBUG("%d\n", magic);
1087f3c3d6fSHasso Tepper 	hash = drm_hash_magic(magic);
1097f3c3d6fSHasso Tepper 
1107f3c3d6fSHasso Tepper 	for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
1117f3c3d6fSHasso Tepper 		if (pt->magic == magic) {
1127f3c3d6fSHasso Tepper 			if (dev->magiclist[hash].head == pt) {
1137f3c3d6fSHasso Tepper 				dev->magiclist[hash].head = pt->next;
1147f3c3d6fSHasso Tepper 			}
1157f3c3d6fSHasso Tepper 			if (dev->magiclist[hash].tail == pt) {
1167f3c3d6fSHasso Tepper 				dev->magiclist[hash].tail = prev;
1177f3c3d6fSHasso Tepper 			}
1187f3c3d6fSHasso Tepper 			if (prev) {
1197f3c3d6fSHasso Tepper 				prev->next = pt->next;
1207f3c3d6fSHasso Tepper 			}
121*b3705d71SHasso Tepper 			free(pt, DRM_MEM_MAGIC);
1227f3c3d6fSHasso Tepper 			return 0;
1237f3c3d6fSHasso Tepper 		}
1247f3c3d6fSHasso Tepper 	}
1257f3c3d6fSHasso Tepper 
1267f3c3d6fSHasso Tepper 	return EINVAL;
1277f3c3d6fSHasso Tepper }
1287f3c3d6fSHasso Tepper 
1297f3c3d6fSHasso Tepper /**
1307f3c3d6fSHasso Tepper  * Called by the client, this returns a unique magic number to be authorized
1317f3c3d6fSHasso Tepper  * by the master.
1327f3c3d6fSHasso Tepper  *
1337f3c3d6fSHasso Tepper  * The master may use its own knowledge of the client (such as the X
1347f3c3d6fSHasso Tepper  * connection that the magic is passed over) to determine if the magic number
1357f3c3d6fSHasso Tepper  * should be authenticated.
1367f3c3d6fSHasso Tepper  */
137*b3705d71SHasso Tepper int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv)
1387f3c3d6fSHasso Tepper {
1397f3c3d6fSHasso Tepper 	static drm_magic_t sequence = 0;
140*b3705d71SHasso Tepper 	struct drm_auth *auth = data;
1417f3c3d6fSHasso Tepper 
1427f3c3d6fSHasso Tepper 	/* Find unique magic */
1437f3c3d6fSHasso Tepper 	if (file_priv->magic) {
1447f3c3d6fSHasso Tepper 		auth->magic = file_priv->magic;
1457f3c3d6fSHasso Tepper 	} else {
1467f3c3d6fSHasso Tepper 		DRM_LOCK();
1477f3c3d6fSHasso Tepper 		do {
1487f3c3d6fSHasso Tepper 			int old = sequence;
1497f3c3d6fSHasso Tepper 
1507f3c3d6fSHasso Tepper 			auth->magic = old+1;
1517f3c3d6fSHasso Tepper 
1527f3c3d6fSHasso Tepper 			if (!atomic_cmpset_int(&sequence, old, auth->magic))
1537f3c3d6fSHasso Tepper 				continue;
1547f3c3d6fSHasso Tepper 		} while (drm_find_file(dev, auth->magic));
1557f3c3d6fSHasso Tepper 		file_priv->magic = auth->magic;
1567f3c3d6fSHasso Tepper 		drm_add_magic(dev, file_priv, auth->magic);
1577f3c3d6fSHasso Tepper 		DRM_UNLOCK();
1587f3c3d6fSHasso Tepper 	}
1597f3c3d6fSHasso Tepper 
1607f3c3d6fSHasso Tepper 	DRM_DEBUG("%u\n", auth->magic);
1617f3c3d6fSHasso Tepper 
1627f3c3d6fSHasso Tepper 	return 0;
1637f3c3d6fSHasso Tepper }
1647f3c3d6fSHasso Tepper 
1657f3c3d6fSHasso Tepper /**
1667f3c3d6fSHasso Tepper  * Marks the client associated with the given magic number as authenticated.
1677f3c3d6fSHasso Tepper  */
168*b3705d71SHasso Tepper int drm_authmagic(struct drm_device *dev, void *data,
169*b3705d71SHasso Tepper 		  struct drm_file *file_priv)
1707f3c3d6fSHasso Tepper {
171*b3705d71SHasso Tepper 	struct drm_auth *auth = data;
172*b3705d71SHasso Tepper 	struct drm_file *priv;
1737f3c3d6fSHasso Tepper 
1747f3c3d6fSHasso Tepper 	DRM_DEBUG("%u\n", auth->magic);
1757f3c3d6fSHasso Tepper 
1767f3c3d6fSHasso Tepper 	DRM_LOCK();
1777f3c3d6fSHasso Tepper 	priv = drm_find_file(dev, auth->magic);
1787f3c3d6fSHasso Tepper 	if (priv != NULL) {
1797f3c3d6fSHasso Tepper 		priv->authenticated = 1;
1807f3c3d6fSHasso Tepper 		drm_remove_magic(dev, auth->magic);
1817f3c3d6fSHasso Tepper 		DRM_UNLOCK();
1827f3c3d6fSHasso Tepper 		return 0;
1837f3c3d6fSHasso Tepper 	} else {
1847f3c3d6fSHasso Tepper 		DRM_UNLOCK();
1857f3c3d6fSHasso Tepper 		return EINVAL;
1867f3c3d6fSHasso Tepper 	}
1877f3c3d6fSHasso Tepper }
188