kdbus: the driver, original and non-working
[platform/kernel/linux-rpi.git] / tools / testing / selftests / kdbus / test-match.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <fcntl.h>
4 #include <stdlib.h>
5 #include <stddef.h>
6 #include <unistd.h>
7 #include <stdint.h>
8 #include <errno.h>
9 #include <assert.h>
10 #include <stdbool.h>
11
12 #include "kdbus-api.h"
13 #include "kdbus-util.h"
14 #include "kdbus-enum.h"
15 #include "kdbus-test.h"
16
17 int kdbus_test_match_id_add(struct kdbus_test_env *env)
18 {
19         struct {
20                 struct kdbus_cmd_match cmd;
21                 struct {
22                         uint64_t size;
23                         uint64_t type;
24                         struct kdbus_notify_id_change chg;
25                 } item;
26         } buf;
27         struct kdbus_conn *conn;
28         struct kdbus_msg *msg;
29         int ret;
30
31         memset(&buf, 0, sizeof(buf));
32
33         buf.cmd.size = sizeof(buf);
34         buf.cmd.cookie = 0xdeafbeefdeaddead;
35         buf.item.size = sizeof(buf.item);
36         buf.item.type = KDBUS_ITEM_ID_ADD;
37         buf.item.chg.id = KDBUS_MATCH_ID_ANY;
38
39         /* match on id add */
40         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
41         ASSERT_RETURN(ret == 0);
42
43         /* create 2nd connection */
44         conn = kdbus_hello(env->buspath, 0, NULL, 0);
45         ASSERT_RETURN(conn != NULL);
46
47         /* 1st connection should have received a notification */
48         ret = kdbus_msg_recv(env->conn, &msg, NULL);
49         ASSERT_RETURN(ret == 0);
50
51         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_ADD);
52         ASSERT_RETURN(msg->items[0].id_change.id == conn->id);
53
54         kdbus_conn_free(conn);
55
56         return TEST_OK;
57 }
58
59 int kdbus_test_match_id_remove(struct kdbus_test_env *env)
60 {
61         struct {
62                 struct kdbus_cmd_match cmd;
63                 struct {
64                         uint64_t size;
65                         uint64_t type;
66                         struct kdbus_notify_id_change chg;
67                 } item;
68         } buf;
69         struct kdbus_conn *conn;
70         struct kdbus_msg *msg;
71         size_t id;
72         int ret;
73
74         /* create 2nd connection */
75         conn = kdbus_hello(env->buspath, 0, NULL, 0);
76         ASSERT_RETURN(conn != NULL);
77         id = conn->id;
78
79         memset(&buf, 0, sizeof(buf));
80         buf.cmd.size = sizeof(buf);
81         buf.cmd.cookie = 0xdeafbeefdeaddead;
82         buf.item.size = sizeof(buf.item);
83         buf.item.type = KDBUS_ITEM_ID_REMOVE;
84         buf.item.chg.id = id;
85
86         /* register match on 2nd connection */
87         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
88         ASSERT_RETURN(ret == 0);
89
90         /* remove 2nd connection again */
91         kdbus_conn_free(conn);
92
93         /* 1st connection should have received a notification */
94         ret = kdbus_msg_recv(env->conn, &msg, NULL);
95         ASSERT_RETURN(ret == 0);
96
97         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE);
98         ASSERT_RETURN(msg->items[0].id_change.id == id);
99
100         return TEST_OK;
101 }
102
103 int kdbus_test_match_replace(struct kdbus_test_env *env)
104 {
105         struct {
106                 struct kdbus_cmd_match cmd;
107                 struct {
108                         uint64_t size;
109                         uint64_t type;
110                         struct kdbus_notify_id_change chg;
111                 } item;
112         } buf;
113         struct kdbus_conn *conn;
114         struct kdbus_msg *msg;
115         size_t id;
116         int ret;
117
118         /* add a match to id_add */
119         ASSERT_RETURN(kdbus_test_match_id_add(env) == TEST_OK);
120
121         /* do a replace of the match from id_add to id_remove */
122         memset(&buf, 0, sizeof(buf));
123
124         buf.cmd.size = sizeof(buf);
125         buf.cmd.cookie = 0xdeafbeefdeaddead;
126         buf.cmd.flags = KDBUS_MATCH_REPLACE;
127         buf.item.size = sizeof(buf.item);
128         buf.item.type = KDBUS_ITEM_ID_REMOVE;
129         buf.item.chg.id = KDBUS_MATCH_ID_ANY;
130
131         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
132
133         /* create 2nd connection */
134         conn = kdbus_hello(env->buspath, 0, NULL, 0);
135         ASSERT_RETURN(conn != NULL);
136         id = conn->id;
137
138         /* 1st connection should _not_ have received a notification */
139         ret = kdbus_msg_recv(env->conn, &msg, NULL);
140         ASSERT_RETURN(ret != 0);
141
142         /* remove 2nd connection */
143         kdbus_conn_free(conn);
144
145         /* 1st connection should _now_ have received a notification */
146         ret = kdbus_msg_recv(env->conn, &msg, NULL);
147         ASSERT_RETURN(ret == 0);
148
149         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_ID_REMOVE);
150         ASSERT_RETURN(msg->items[0].id_change.id == id);
151
152         return TEST_OK;
153 }
154
155 int kdbus_test_match_name_add(struct kdbus_test_env *env)
156 {
157         struct {
158                 struct kdbus_cmd_match cmd;
159                 struct {
160                         uint64_t size;
161                         uint64_t type;
162                         struct kdbus_notify_name_change chg;
163                 } item;
164                 char name[64];
165         } buf;
166         struct kdbus_msg *msg;
167         char *name;
168         int ret;
169
170         name = "foo.bla.blaz";
171
172         /* install the match rule */
173         memset(&buf, 0, sizeof(buf));
174         buf.item.type = KDBUS_ITEM_NAME_ADD;
175         buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
176         buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
177         strncpy(buf.name, name, sizeof(buf.name) - 1);
178         buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
179         buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
180
181         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
182         ASSERT_RETURN(ret == 0);
183
184         /* acquire the name */
185         ret = kdbus_name_acquire(env->conn, name, NULL);
186         ASSERT_RETURN(ret == 0);
187
188         /* we should have received a notification */
189         ret = kdbus_msg_recv(env->conn, &msg, NULL);
190         ASSERT_RETURN(ret == 0);
191
192         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_ADD);
193         ASSERT_RETURN(msg->items[0].name_change.old_id.id == 0);
194         ASSERT_RETURN(msg->items[0].name_change.new_id.id == env->conn->id);
195         ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
196
197         return TEST_OK;
198 }
199
200 int kdbus_test_match_name_remove(struct kdbus_test_env *env)
201 {
202         struct {
203                 struct kdbus_cmd_match cmd;
204                 struct {
205                         uint64_t size;
206                         uint64_t type;
207                         struct kdbus_notify_name_change chg;
208                 } item;
209                 char name[64];
210         } buf;
211         struct kdbus_msg *msg;
212         char *name;
213         int ret;
214
215         name = "foo.bla.blaz";
216
217         /* acquire the name */
218         ret = kdbus_name_acquire(env->conn, name, NULL);
219         ASSERT_RETURN(ret == 0);
220
221         /* install the match rule */
222         memset(&buf, 0, sizeof(buf));
223         buf.item.type = KDBUS_ITEM_NAME_REMOVE;
224         buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
225         buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
226         strncpy(buf.name, name, sizeof(buf.name) - 1);
227         buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
228         buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
229
230         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
231         ASSERT_RETURN(ret == 0);
232
233         /* release the name again */
234         kdbus_name_release(env->conn, name);
235         ASSERT_RETURN(ret == 0);
236
237         /* we should have received a notification */
238         ret = kdbus_msg_recv(env->conn, &msg, NULL);
239         ASSERT_RETURN(ret == 0);
240
241         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_REMOVE);
242         ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id);
243         ASSERT_RETURN(msg->items[0].name_change.new_id.id == 0);
244         ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
245
246         return TEST_OK;
247 }
248
249 int kdbus_test_match_name_change(struct kdbus_test_env *env)
250 {
251         struct {
252                 struct kdbus_cmd_match cmd;
253                 struct {
254                         uint64_t size;
255                         uint64_t type;
256                         struct kdbus_notify_name_change chg;
257                 } item;
258                 char name[64];
259         } buf;
260         struct kdbus_conn *conn;
261         struct kdbus_msg *msg;
262         uint64_t flags;
263         char *name = "foo.bla.baz";
264         int ret;
265
266         /* acquire the name */
267         ret = kdbus_name_acquire(env->conn, name, NULL);
268         ASSERT_RETURN(ret == 0);
269
270         /* install the match rule */
271         memset(&buf, 0, sizeof(buf));
272         buf.item.type = KDBUS_ITEM_NAME_CHANGE;
273         buf.item.chg.old_id.id = KDBUS_MATCH_ID_ANY;
274         buf.item.chg.new_id.id = KDBUS_MATCH_ID_ANY;
275         strncpy(buf.name, name, sizeof(buf.name) - 1);
276         buf.item.size = sizeof(buf.item) + strlen(buf.name) + 1;
277         buf.cmd.size = sizeof(buf.cmd) + buf.item.size;
278
279         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
280         ASSERT_RETURN(ret == 0);
281
282         /* create a 2nd connection */
283         conn = kdbus_hello(env->buspath, 0, NULL, 0);
284         ASSERT_RETURN(conn != NULL);
285
286         /* allow the new connection to own the same name */
287         /* queue the 2nd connection as waiting owner */
288         flags = KDBUS_NAME_QUEUE;
289         ret = kdbus_name_acquire(conn, name, &flags);
290         ASSERT_RETURN(ret == 0);
291         ASSERT_RETURN(flags & KDBUS_NAME_IN_QUEUE);
292
293         /* release name from 1st connection */
294         ret = kdbus_name_release(env->conn, name);
295         ASSERT_RETURN(ret == 0);
296
297         /* we should have received a notification */
298         ret = kdbus_msg_recv(env->conn, &msg, NULL);
299         ASSERT_RETURN(ret == 0);
300
301         ASSERT_RETURN(msg->items[0].type == KDBUS_ITEM_NAME_CHANGE);
302         ASSERT_RETURN(msg->items[0].name_change.old_id.id == env->conn->id);
303         ASSERT_RETURN(msg->items[0].name_change.new_id.id == conn->id);
304         ASSERT_RETURN(strcmp(msg->items[0].name_change.name, name) == 0);
305
306         kdbus_conn_free(conn);
307
308         return TEST_OK;
309 }
310
311 static int send_bloom_filter(const struct kdbus_conn *conn,
312                              uint64_t cookie,
313                              const uint8_t *filter,
314                              size_t filter_size,
315                              uint64_t filter_generation)
316 {
317         struct kdbus_cmd_send cmd = {};
318         struct kdbus_msg *msg;
319         struct kdbus_item *item;
320         uint64_t size;
321         int ret;
322
323         size = sizeof(struct kdbus_msg);
324         size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) + filter_size;
325
326         msg = alloca(size);
327
328         memset(msg, 0, size);
329         msg->size = size;
330         msg->src_id = conn->id;
331         msg->dst_id = KDBUS_DST_ID_BROADCAST;
332         msg->flags = KDBUS_MSG_SIGNAL;
333         msg->payload_type = KDBUS_PAYLOAD_DBUS;
334         msg->cookie = cookie;
335
336         item = msg->items;
337         item->type = KDBUS_ITEM_BLOOM_FILTER;
338         item->size = KDBUS_ITEM_SIZE(sizeof(struct kdbus_bloom_filter)) +
339                                 filter_size;
340
341         item->bloom_filter.generation = filter_generation;
342         memcpy(item->bloom_filter.data, filter, filter_size);
343
344         cmd.size = sizeof(cmd);
345         cmd.msg_address = (uintptr_t)msg;
346
347         ret = kdbus_cmd_send(conn->fd, &cmd);
348         if (ret < 0) {
349                 kdbus_printf("error sending message: %d (%m)\n", ret);
350                 return ret;
351         }
352
353         return 0;
354 }
355
356 int kdbus_test_match_bloom(struct kdbus_test_env *env)
357 {
358         struct {
359                 struct kdbus_cmd_match cmd;
360                 struct {
361                         uint64_t size;
362                         uint64_t type;
363                         uint8_t data_gen0[64];
364                         uint8_t data_gen1[64];
365                 } item;
366         } buf;
367         struct kdbus_conn *conn;
368         struct kdbus_msg *msg;
369         uint64_t cookie = 0xf000f00f;
370         uint8_t filter[64];
371         int ret;
372
373         /* install the match rule */
374         memset(&buf, 0, sizeof(buf));
375         buf.cmd.size = sizeof(buf);
376
377         buf.item.size = sizeof(buf.item);
378         buf.item.type = KDBUS_ITEM_BLOOM_MASK;
379         buf.item.data_gen0[0] = 0x55;
380         buf.item.data_gen0[63] = 0x80;
381
382         buf.item.data_gen1[1] = 0xaa;
383         buf.item.data_gen1[9] = 0x02;
384
385         ret = kdbus_cmd_match_add(env->conn->fd, &buf.cmd);
386         ASSERT_RETURN(ret == 0);
387
388         /* create a 2nd connection */
389         conn = kdbus_hello(env->buspath, 0, NULL, 0);
390         ASSERT_RETURN(conn != NULL);
391
392         /* a message with a 0'ed out filter must not reach the other peer */
393         memset(filter, 0, sizeof(filter));
394         ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
395         ASSERT_RETURN(ret == 0);
396
397         ret = kdbus_msg_recv(env->conn, &msg, NULL);
398         ASSERT_RETURN(ret == -EAGAIN);
399
400         /* now set the filter to the connection's mask and expect success */
401         filter[0] = 0x55;
402         filter[63] = 0x80;
403         ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
404         ASSERT_RETURN(ret == 0);
405
406         ret = kdbus_msg_recv(env->conn, &msg, NULL);
407         ASSERT_RETURN(ret == 0);
408         ASSERT_RETURN(msg->cookie == cookie);
409
410         /* broaden the filter and try again. this should also succeed. */
411         filter[0] = 0xff;
412         filter[8] = 0xff;
413         filter[63] = 0xff;
414         ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 0);
415         ASSERT_RETURN(ret == 0);
416
417         ret = kdbus_msg_recv(env->conn, &msg, NULL);
418         ASSERT_RETURN(ret == 0);
419         ASSERT_RETURN(msg->cookie == cookie);
420
421         /* the same filter must not match against bloom generation 1 */
422         ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1);
423         ASSERT_RETURN(ret == 0);
424
425         ret = kdbus_msg_recv(env->conn, &msg, NULL);
426         ASSERT_RETURN(ret == -EAGAIN);
427
428         /* set a different filter and try again */
429         filter[1] = 0xaa;
430         filter[9] = 0x02;
431         ret = send_bloom_filter(conn, ++cookie, filter, sizeof(filter), 1);
432         ASSERT_RETURN(ret == 0);
433
434         ret = kdbus_msg_recv(env->conn, &msg, NULL);
435         ASSERT_RETURN(ret == 0);
436         ASSERT_RETURN(msg->cookie == cookie);
437
438         kdbus_conn_free(conn);
439
440         return TEST_OK;
441 }