1 /*
2  * Copyright © 2019 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 
26 #include "config.h"
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <libweston/libweston.h>
34 #include <libweston/weston-log.h>
35 #include "compositor/weston.h"
36 #include "weston-content-protection-server-protocol.h"
37 #include "shared/helpers.h"
38 #include "shared/timespec-util.h"
39 
40 #define content_protection_log(cp, ...) \
41 	weston_log_scope_printf((cp)->debug, __VA_ARGS__)
42 
43 static const char * const content_type_name [] = {
44 	[WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED] = "UNPROTECTED",
45 	[WESTON_PROTECTED_SURFACE_TYPE_HDCP_0] = "TYPE-0",
46 	[WESTON_PROTECTED_SURFACE_TYPE_HDCP_1] = "TYPE-1",
47 };
48 
49 void
weston_protected_surface_send_event(struct protected_surface * psurface,enum weston_hdcp_protection protection)50 weston_protected_surface_send_event(struct protected_surface *psurface,
51 				       enum weston_hdcp_protection protection)
52 {
53 	struct wl_resource *p_resource;
54 	enum weston_protected_surface_type protection_type;
55 	struct content_protection *cp;
56 	struct wl_resource *surface_resource;
57 
58 	p_resource = psurface->protection_resource;
59 	if (!p_resource)
60 		return;
61 	/* No event to be sent to client, in case of enforced mode */
62 	if (psurface->surface->protection_mode == WESTON_SURFACE_PROTECTION_MODE_ENFORCED)
63 		return;
64 	protection_type = (enum weston_protected_surface_type) protection;
65 	weston_protected_surface_send_status(p_resource, protection_type);
66 
67 	cp = psurface->cp_backptr;
68 	surface_resource = psurface->surface->resource;
69 	content_protection_log(cp, "wl_surface@%"PRIu32" Protection type set to %s\n",
70 			       wl_resource_get_id(surface_resource),
71 			       content_type_name[protection_type]);
72 }
73 
74 static void
set_type(struct wl_client * client,struct wl_resource * resource,enum weston_protected_surface_type content_type)75 set_type(struct wl_client *client, struct wl_resource *resource,
76 	 enum weston_protected_surface_type content_type)
77 {
78 	struct content_protection *cp;
79 	struct protected_surface *psurface;
80 	enum weston_hdcp_protection weston_cp;
81 	struct wl_resource *surface_resource;
82 
83 	psurface = wl_resource_get_user_data(resource);
84 	if (!psurface)
85 		return;
86 	cp = psurface->cp_backptr;
87 	surface_resource = psurface->surface->resource;
88 
89 	if (content_type < WESTON_PROTECTED_SURFACE_TYPE_UNPROTECTED ||
90 	    content_type > WESTON_PROTECTED_SURFACE_TYPE_HDCP_1) {
91 		wl_resource_post_error(resource,
92 				       WESTON_PROTECTED_SURFACE_ERROR_INVALID_TYPE,
93 				       "wl_surface@%"PRIu32" Invalid content-type %d for request:set_type\n",
94 				       wl_resource_get_id(surface_resource), content_type);
95 
96 		content_protection_log(cp, "wl_surface@%"PRIu32" Invalid content-type %d for resquest:set_type\n",
97 				       wl_resource_get_id(surface_resource), content_type);
98 		return;
99 	}
100 
101 	content_protection_log(cp, "wl_surface@%"PRIu32" Request: Enable Content-Protection Type: %s\n",
102 			       wl_resource_get_id(surface_resource),
103 			       content_type_name[content_type]);
104 
105 	weston_cp = (enum weston_hdcp_protection) content_type;
106 	psurface->surface->pending.desired_protection = weston_cp;
107 }
108 
109 static void
protected_surface_destroy(struct wl_client * client,struct wl_resource * resource)110 protected_surface_destroy(struct wl_client *client, struct wl_resource *resource)
111 {
112 	struct protected_surface *psurface;
113 
114 	psurface = wl_resource_get_user_data(resource);
115 	if (!psurface)
116 		return;
117 	psurface->surface->pending.desired_protection = WESTON_HDCP_DISABLE;
118 }
119 
120 static void
set_enforce_mode(struct wl_client * client,struct wl_resource * resource)121 set_enforce_mode(struct wl_client *client, struct wl_resource *resource)
122 {
123 	/*
124 	 * Enforce Censored-Visibility. Compositor censors the protected
125 	 * surface on an unsecured output.
126 	 * In case of a surface, being shown on an unprotected output, the
127 	 * compositor hides the surface, not allowing it to be displayed on
128 	 * the unprotected output, without bothering the client. No difference
129 	 * for the protected outputs.
130 	 *
131 	 * The member 'protection_mode' is "double-buffered", so setting it in
132 	 * pending_state will cause the setting of the corresponding
133 	 * 'protection_mode' in weston_surface, after the commit.
134 	 *
135 	 * This function sets the 'protection_mode' of the weston_surface_state
136 	 * to 'enfoced'. The renderers inspect the flag and compare the
137 	 * desired_protection of the surface, to the current_protection of the
138 	 * output, based on that the real surface or a place-holder content,
139 	 * (e.g. solid color) are shown.
140 	 */
141 
142 	struct protected_surface *psurface;
143 
144 	psurface = wl_resource_get_user_data(resource);
145 	if (!psurface)
146 		return;
147 
148 	psurface->surface->pending.protection_mode =
149 		WESTON_SURFACE_PROTECTION_MODE_ENFORCED;
150 }
151 
152 static void
set_relax_mode(struct wl_client * client,struct wl_resource * resource)153 set_relax_mode(struct wl_client *client, struct wl_resource *resource)
154 {
155 	/*
156 	 * Relaxed mode. By default this mode will be activated.
157 	 * In case of a surface, being shown in unprotected output,
158 	 * compositor just sends the event for protection status changed.
159 	 *
160 	 * On setting the relaxed mode, the 'protection_mode' member is queued
161 	 * to be set to 'relax' from the existing 'enforce' mode.
162 	 */
163 
164 	struct protected_surface *psurface;
165 
166 	psurface = wl_resource_get_user_data(resource);
167 	if (!psurface)
168 		return;
169 
170 	psurface->surface->pending.protection_mode =
171 		WESTON_SURFACE_PROTECTION_MODE_RELAXED;
172 }
173 
174 static const struct weston_protected_surface_interface protected_surface_implementation = {
175 	protected_surface_destroy,
176 	set_type,
177 	set_enforce_mode,
178 	set_relax_mode,
179 };
180 
181 static void
cp_destroy_listener(struct wl_listener * listener,void * data)182 cp_destroy_listener(struct wl_listener *listener, void *data)
183 {
184 	struct content_protection *cp;
185 
186 	cp = container_of(listener, struct content_protection,
187 			  destroy_listener);
188 	wl_list_remove(&cp->destroy_listener.link);
189 	wl_list_remove(&cp->protected_list);
190 	weston_compositor_log_scope_destroy(cp->debug);
191 	cp->debug = NULL;
192 	cp->surface_protection_update = NULL;
193 	free(cp);
194 }
195 
196 static void
free_protected_surface(struct protected_surface * psurface)197 free_protected_surface(struct protected_surface *psurface)
198 {
199 	psurface->surface->pending.desired_protection = WESTON_HDCP_DISABLE;
200 	wl_resource_set_user_data(psurface->protection_resource, NULL);
201 	wl_list_remove(&psurface->surface_destroy_listener.link);
202 	wl_list_remove(&psurface->link);
203 	free(psurface);
204 }
205 
206 static void
surface_destroyed(struct wl_listener * listener,void * data)207 surface_destroyed(struct wl_listener *listener, void *data)
208 {
209 	struct protected_surface *psurface;
210 
211 	psurface = container_of(listener, struct protected_surface,
212 				surface_destroy_listener);
213 	free_protected_surface(psurface);
214 }
215 
216 static void
destroy_protected_surface(struct wl_resource * resource)217 destroy_protected_surface(struct wl_resource *resource)
218 {
219 	struct protected_surface *psurface;
220 
221 	psurface = wl_resource_get_user_data(resource);
222 	if (!psurface)
223 		return;
224 	free_protected_surface(psurface);
225 }
226 
227 static void
get_protection(struct wl_client * client,struct wl_resource * cp_resource,uint32_t id,struct wl_resource * surface_resource)228 get_protection(struct wl_client *client, struct wl_resource *cp_resource,
229 	     uint32_t id, struct wl_resource *surface_resource)
230 {
231 	struct wl_resource *resource;
232 	struct weston_surface *surface;
233 	struct content_protection *cp;
234 	struct protected_surface *psurface;
235 	struct wl_listener *listener;
236 
237 	surface = wl_resource_get_user_data(surface_resource);
238 	assert(surface);
239 	cp = wl_resource_get_user_data(cp_resource);
240 	assert(cp);
241 
242 	/*
243 	 * Check if this client has a corresponding protected-surface
244 	 */
245 
246 	listener = wl_resource_get_destroy_listener(surface->resource,
247 						    surface_destroyed);
248 
249 	if (listener) {
250 		wl_resource_post_error(cp_resource,
251 				       WESTON_CONTENT_PROTECTION_ERROR_SURFACE_EXISTS,
252 				       "wl_surface@%"PRIu32" Protection already exists",
253 				       wl_resource_get_id(surface_resource));
254 		return;
255 	}
256 
257 	psurface = zalloc(sizeof(struct protected_surface));
258 	if (!psurface) {
259 		wl_client_post_no_memory(client);
260 		return;
261 	}
262 	psurface->cp_backptr = cp;
263 	resource = wl_resource_create(client, &weston_protected_surface_interface,
264 				      1, id);
265 	if (!resource) {
266 		free(psurface);
267 		wl_client_post_no_memory(client);
268 		return;
269 	}
270 
271 	wl_list_insert(&cp->protected_list, &psurface->link);
272 	wl_resource_set_implementation(resource, &protected_surface_implementation,
273 				       psurface,
274 				       destroy_protected_surface);
275 
276 	psurface->protection_resource = resource;
277 	psurface->surface = surface;
278 	psurface->surface_destroy_listener.notify = surface_destroyed;
279 	wl_resource_add_destroy_listener(surface->resource,
280 					 &psurface->surface_destroy_listener);
281 	weston_protected_surface_send_event(psurface,
282 					    psurface->surface->current_protection);
283 }
284 
285 static void
destroy_protection(struct wl_client * client,struct wl_resource * cp_resource)286 destroy_protection(struct wl_client *client, struct wl_resource *cp_resource)
287 {
288 	wl_resource_destroy(cp_resource);
289 }
290 
291 static const
292 struct weston_content_protection_interface content_protection_implementation = {
293 	destroy_protection,
294 	get_protection,
295 };
296 
297 static void
bind_weston_content_protection(struct wl_client * client,void * data,uint32_t version,uint32_t id)298 bind_weston_content_protection(struct wl_client *client, void *data,
299 			       uint32_t version, uint32_t id)
300 {
301 	struct content_protection *cp = data;
302 	struct wl_resource *resource;
303 
304 	resource = wl_resource_create(client,
305 				      &weston_content_protection_interface,
306 				      1, id);
307 	if (!resource) {
308 		wl_client_post_no_memory(client);
309 		return;
310 	}
311 
312 	wl_resource_set_implementation(resource,
313 				       &content_protection_implementation,
314 				       cp, NULL);
315 }
316 /* Advertise the content-protection support.
317  *
318  * Calling this function sets up the content-protection support via HDCP.
319  * This exposes the global interface, visible to the client, enabling them to
320  * request for content-protection for their surfaces according to the type of
321  * content.
322  */
323 
324 WL_EXPORT int
weston_compositor_enable_content_protection(struct weston_compositor * compositor)325 weston_compositor_enable_content_protection(struct weston_compositor *compositor)
326 {
327 	struct content_protection *cp;
328 
329 	cp = zalloc(sizeof(*cp));
330 	if (cp == NULL)
331 		return -1;
332 	cp->compositor = compositor;
333 
334 	compositor->content_protection = cp;
335 	wl_list_init(&cp->protected_list);
336 	if (wl_global_create(compositor->wl_display,
337 			     &weston_content_protection_interface, 1, cp,
338 			     bind_weston_content_protection) == NULL)
339 		return -1;
340 
341 	cp->destroy_listener.notify = cp_destroy_listener;
342 	wl_signal_add(&compositor->destroy_signal, &cp->destroy_listener);
343 	cp->debug = weston_compositor_add_log_scope(compositor->weston_log_ctx,
344 						    "content-protection-debug",
345 						    "debug-logs for content-protection",
346 						    NULL, NULL);
347 	return 0;
348 }
349