Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0
  2/* Check what features does the kernel support (where the selftest is running).
  3 * Somewhat inspired by CRIU kerndat/kdat kernel features detector.
  4 */
  5#include <pthread.h>
  6#include "aolib.h"
  7
  8struct kconfig_t {
  9	int _errno;		/* the returned error if not supported */
 10	int (*check_kconfig)(int *error);
 11};
 12
 13static int has_net_ns(int *err)
 14{
 15	if (access("/proc/self/ns/net", F_OK) < 0) {
 16		*err = errno;
 17		if (errno == ENOENT)
 18			return 0;
 19		test_print("Unable to access /proc/self/ns/net: %m");
 20		return -errno;
 21	}
 22	return *err = errno = 0;
 23}
 24
 25static int has_veth(int *err)
 26{
 27	int orig_netns, ns_a, ns_b;
 28
 29	orig_netns = open_netns();
 30	ns_a = unshare_open_netns();
 31	ns_b = unshare_open_netns();
 32
 33	*err = add_veth("check_veth", ns_a, ns_b);
 34
 35	switch_ns(orig_netns);
 36	close(orig_netns);
 37	close(ns_a);
 38	close(ns_b);
 39	return 0;
 40}
 41
 42static int has_tcp_ao(int *err)
 43{
 44	struct sockaddr_in addr = {
 45		.sin_family = test_family,
 46	};
 47	struct tcp_ao_add tmp = {};
 48	const char *password = DEFAULT_TEST_PASSWORD;
 49	int sk, ret = 0;
 50
 51	sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
 52	if (sk < 0) {
 53		test_print("socket(): %m");
 54		return -errno;
 55	}
 56
 57	tmp.sndid = 100;
 58	tmp.rcvid = 100;
 59	tmp.keylen = strlen(password);
 60	memcpy(tmp.key, password, strlen(password));
 61	strcpy(tmp.alg_name, "hmac(sha1)");
 62	memcpy(&tmp.addr, &addr, sizeof(addr));
 63	*err = 0;
 64	if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0) {
 65		*err = errno;
 66		if (errno != ENOPROTOOPT)
 67			ret = -errno;
 68	}
 69	close(sk);
 70	return ret;
 71}
 72
 73static int has_tcp_md5(int *err)
 74{
 75	union tcp_addr addr_any = {};
 76	int sk, ret = 0;
 77
 78	sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
 79	if (sk < 0) {
 80		test_print("socket(): %m");
 81		return -errno;
 82	}
 83
 84	/*
 85	 * Under CONFIG_CRYPTO_FIPS=y it fails with ENOMEM, rather with
 86	 * anything more descriptive. Oh well.
 87	 */
 88	*err = 0;
 89	if (test_set_md5(sk, addr_any, 0, -1, DEFAULT_TEST_PASSWORD)) {
 90		*err = errno;
 91		if (errno != ENOPROTOOPT && errno == ENOMEM) {
 92			test_print("setsockopt(TCP_MD5SIG_EXT): %m");
 93			ret = -errno;
 94		}
 95	}
 96	close(sk);
 97	return ret;
 98}
 99
100static int has_vrfs(int *err)
101{
102	int orig_netns, ns_test, ret = 0;
103
104	orig_netns = open_netns();
105	ns_test = unshare_open_netns();
106
107	*err = add_vrf("ksft-check", 55, 101, ns_test);
108	if (*err && *err != -EOPNOTSUPP) {
109		test_print("Failed to add a VRF: %d", *err);
110		ret = *err;
111	}
112
113	switch_ns(orig_netns);
114	close(orig_netns);
115	close(ns_test);
116	return ret;
117}
118
119static pthread_mutex_t kconfig_lock = PTHREAD_MUTEX_INITIALIZER;
120static struct kconfig_t kconfig[__KCONFIG_LAST__] = {
121	{ -1, has_net_ns },
122	{ -1, has_veth },
123	{ -1, has_tcp_ao },
124	{ -1, has_tcp_md5 },
125	{ -1, has_vrfs },
126};
127
128const char *tests_skip_reason[__KCONFIG_LAST__] = {
129	"Tests require network namespaces support (CONFIG_NET_NS)",
130	"Tests require veth support (CONFIG_VETH)",
131	"Tests require TCP-AO support (CONFIG_TCP_AO)",
132	"setsockopt(TCP_MD5SIG_EXT) is not supported (CONFIG_TCP_MD5)",
133	"VRFs are not supported (CONFIG_NET_VRF)",
134};
135
136bool kernel_config_has(enum test_needs_kconfig k)
137{
138	bool ret;
139
140	pthread_mutex_lock(&kconfig_lock);
141	if (kconfig[k]._errno == -1) {
142		if (kconfig[k].check_kconfig(&kconfig[k]._errno))
143			test_error("Failed to initialize kconfig %u", k);
144	}
145	ret = kconfig[k]._errno == 0;
146	pthread_mutex_unlock(&kconfig_lock);
147	return ret;
148}