1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 2f08c3bdfSopenharmony_ci/* 3f08c3bdfSopenharmony_ci * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com> 4f08c3bdfSopenharmony_ci */ 5f08c3bdfSopenharmony_ci 6f08c3bdfSopenharmony_ci#ifndef WQUEUE_COMMON_H__ 7f08c3bdfSopenharmony_ci#define WQUEUE_COMMON_H__ 8f08c3bdfSopenharmony_ci 9f08c3bdfSopenharmony_ci#include <unistd.h> 10f08c3bdfSopenharmony_ci#include "tst_test.h" 11f08c3bdfSopenharmony_ci#include "lapi/watch_queue.h" 12f08c3bdfSopenharmony_ci#include "lapi/keyctl.h" 13f08c3bdfSopenharmony_ci 14f08c3bdfSopenharmony_cistatic struct watch_notification_filter wqueue_filter = { 15f08c3bdfSopenharmony_ci .nr_filters = 2, 16f08c3bdfSopenharmony_ci .filters = { 17f08c3bdfSopenharmony_ci [0] = { 18f08c3bdfSopenharmony_ci .type = WATCH_TYPE_META, 19f08c3bdfSopenharmony_ci .subtype_filter[0] = UINT_MAX, 20f08c3bdfSopenharmony_ci }, 21f08c3bdfSopenharmony_ci [1] = { 22f08c3bdfSopenharmony_ci .type = WATCH_TYPE_KEY_NOTIFY, 23f08c3bdfSopenharmony_ci .subtype_filter[0] = UINT_MAX, 24f08c3bdfSopenharmony_ci }, 25f08c3bdfSopenharmony_ci }, 26f08c3bdfSopenharmony_ci}; 27f08c3bdfSopenharmony_ci 28f08c3bdfSopenharmony_cistatic inline int wqueue_key_event(struct watch_notification *n, size_t len, 29f08c3bdfSopenharmony_ci unsigned int wtype, int type) 30f08c3bdfSopenharmony_ci{ 31f08c3bdfSopenharmony_ci struct key_notification *k; 32f08c3bdfSopenharmony_ci const char *msg; 33f08c3bdfSopenharmony_ci 34f08c3bdfSopenharmony_ci if (wtype != WATCH_TYPE_KEY_NOTIFY) 35f08c3bdfSopenharmony_ci return 0; 36f08c3bdfSopenharmony_ci 37f08c3bdfSopenharmony_ci if (len != sizeof(struct key_notification)) 38f08c3bdfSopenharmony_ci tst_brk(TBROK, "Incorrect key message length"); 39f08c3bdfSopenharmony_ci 40f08c3bdfSopenharmony_ci switch (n->subtype) { 41f08c3bdfSopenharmony_ci case NOTIFY_KEY_INSTANTIATED: 42f08c3bdfSopenharmony_ci msg = "instantiated"; 43f08c3bdfSopenharmony_ci break; 44f08c3bdfSopenharmony_ci case NOTIFY_KEY_UPDATED: 45f08c3bdfSopenharmony_ci msg = "updated"; 46f08c3bdfSopenharmony_ci break; 47f08c3bdfSopenharmony_ci case NOTIFY_KEY_LINKED: 48f08c3bdfSopenharmony_ci msg = "linked"; 49f08c3bdfSopenharmony_ci break; 50f08c3bdfSopenharmony_ci case NOTIFY_KEY_UNLINKED: 51f08c3bdfSopenharmony_ci msg = "unlinked"; 52f08c3bdfSopenharmony_ci break; 53f08c3bdfSopenharmony_ci case NOTIFY_KEY_CLEARED: 54f08c3bdfSopenharmony_ci msg = "cleared"; 55f08c3bdfSopenharmony_ci break; 56f08c3bdfSopenharmony_ci case NOTIFY_KEY_REVOKED: 57f08c3bdfSopenharmony_ci msg = "revoked"; 58f08c3bdfSopenharmony_ci break; 59f08c3bdfSopenharmony_ci case NOTIFY_KEY_INVALIDATED: 60f08c3bdfSopenharmony_ci msg = "invalidated"; 61f08c3bdfSopenharmony_ci break; 62f08c3bdfSopenharmony_ci case NOTIFY_KEY_SETATTR: 63f08c3bdfSopenharmony_ci msg = "setattr"; 64f08c3bdfSopenharmony_ci break; 65f08c3bdfSopenharmony_ci default: 66f08c3bdfSopenharmony_ci msg = "Invalid notification"; 67f08c3bdfSopenharmony_ci break; 68f08c3bdfSopenharmony_ci }; 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_ci k = (struct key_notification *)n; 71f08c3bdfSopenharmony_ci tst_res(TINFO, "KEY %08x change=%u[%s] aux=%u", k->key_id, n->subtype, msg, 72f08c3bdfSopenharmony_ci k->aux); 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_ci if (n->subtype == type) 75f08c3bdfSopenharmony_ci return 1; 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_ci return 0; 78f08c3bdfSopenharmony_ci} 79f08c3bdfSopenharmony_ci 80f08c3bdfSopenharmony_cistatic inline key_serial_t wqueue_add_key(int fd) 81f08c3bdfSopenharmony_ci{ 82f08c3bdfSopenharmony_ci key_serial_t key; 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci key = add_key("user", "ltptestkey", "a", 1, KEY_SPEC_SESSION_KEYRING); 85f08c3bdfSopenharmony_ci if (key == -1) 86f08c3bdfSopenharmony_ci tst_brk(TBROK, "add_key error: %s", tst_strerrno(errno)); 87f08c3bdfSopenharmony_ci 88f08c3bdfSopenharmony_ci keyctl(KEYCTL_WATCH_KEY, key, fd, 0x01); 89f08c3bdfSopenharmony_ci keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fd, 0x02); 90f08c3bdfSopenharmony_ci 91f08c3bdfSopenharmony_ci return key; 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_cistatic inline int wqueue_watch(int buf_size, 95f08c3bdfSopenharmony_ci struct watch_notification_filter *filter) 96f08c3bdfSopenharmony_ci{ 97f08c3bdfSopenharmony_ci int pipefd[2]; 98f08c3bdfSopenharmony_ci int fd; 99f08c3bdfSopenharmony_ci 100f08c3bdfSopenharmony_ci TEST(pipe2(pipefd, O_NOTIFICATION_PIPE)); 101f08c3bdfSopenharmony_ci if (TST_RET) { 102f08c3bdfSopenharmony_ci switch (TST_ERR) { 103f08c3bdfSopenharmony_ci case ENOPKG: 104f08c3bdfSopenharmony_ci tst_brk(TCONF | TTERRNO, "CONFIG_WATCH_QUEUE is not set"); 105f08c3bdfSopenharmony_ci break; 106f08c3bdfSopenharmony_ci case EINVAL: 107f08c3bdfSopenharmony_ci tst_brk(TCONF | TTERRNO, "O_NOTIFICATION_PIPE is not supported"); 108f08c3bdfSopenharmony_ci break; 109f08c3bdfSopenharmony_ci default: 110f08c3bdfSopenharmony_ci tst_brk(TBROK | TTERRNO, "pipe2() returned %ld", TST_RET); 111f08c3bdfSopenharmony_ci } 112f08c3bdfSopenharmony_ci } 113f08c3bdfSopenharmony_ci 114f08c3bdfSopenharmony_ci fd = pipefd[0]; 115f08c3bdfSopenharmony_ci 116f08c3bdfSopenharmony_ci SAFE_IOCTL(fd, IOC_WATCH_QUEUE_SET_SIZE, buf_size); 117f08c3bdfSopenharmony_ci SAFE_IOCTL(fd, IOC_WATCH_QUEUE_SET_FILTER, filter); 118f08c3bdfSopenharmony_ci 119f08c3bdfSopenharmony_ci return fd; 120f08c3bdfSopenharmony_ci} 121f08c3bdfSopenharmony_ci 122f08c3bdfSopenharmony_citypedef void (*wqueue_callback)(struct watch_notification *n, size_t len, 123f08c3bdfSopenharmony_ci unsigned int wtype); 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_cistatic void wqueue_consumer(int fd, wqueue_callback cb) 126f08c3bdfSopenharmony_ci{ 127f08c3bdfSopenharmony_ci unsigned char buffer[433], *p, *end; 128f08c3bdfSopenharmony_ci union { 129f08c3bdfSopenharmony_ci struct watch_notification n; 130f08c3bdfSopenharmony_ci unsigned char buf1[128]; 131f08c3bdfSopenharmony_ci } n; 132f08c3bdfSopenharmony_ci ssize_t buf_len; 133f08c3bdfSopenharmony_ci 134f08c3bdfSopenharmony_ci tst_res(TINFO, "Reading watch queue events"); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci buf_len = SAFE_READ(0, fd, buffer, sizeof(buffer)); 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci p = buffer; 139f08c3bdfSopenharmony_ci end = buffer + buf_len; 140f08c3bdfSopenharmony_ci while (p < end) { 141f08c3bdfSopenharmony_ci size_t largest, len; 142f08c3bdfSopenharmony_ci 143f08c3bdfSopenharmony_ci largest = end - p; 144f08c3bdfSopenharmony_ci if (largest > 128) 145f08c3bdfSopenharmony_ci largest = 128; 146f08c3bdfSopenharmony_ci 147f08c3bdfSopenharmony_ci if (largest < sizeof(struct watch_notification)) 148f08c3bdfSopenharmony_ci tst_brk(TBROK, "Short message header: %zu", largest); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci memcpy(&n, p, largest); 151f08c3bdfSopenharmony_ci 152f08c3bdfSopenharmony_ci tst_res(TINFO, "NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x", p - buffer, 153f08c3bdfSopenharmony_ci n.n.type, n.n.subtype, n.n.info); 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci len = n.n.info & WATCH_INFO_LENGTH; 156f08c3bdfSopenharmony_ci if (len < sizeof(n.n) || len > largest) 157f08c3bdfSopenharmony_ci tst_brk(TBROK, "Bad message length: %zu/%zu", len, largest); 158f08c3bdfSopenharmony_ci 159f08c3bdfSopenharmony_ci cb(&n.n, len, n.n.type); 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci p += len; 162f08c3bdfSopenharmony_ci } 163f08c3bdfSopenharmony_ci} 164f08c3bdfSopenharmony_ci 165f08c3bdfSopenharmony_ci#endif 166