1c1839039SAlexander V. Chernikov /*-
2c1839039SAlexander V. Chernikov * SPDX-License-Identifier: BSD-2-Clause
3c1839039SAlexander V. Chernikov *
4c1839039SAlexander V. Chernikov * Copyright (c) 2023 Alexander V. Chernikov
5c1839039SAlexander V. Chernikov *
6c1839039SAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without
7c1839039SAlexander V. Chernikov * modification, are permitted provided that the following conditions
8c1839039SAlexander V. Chernikov * are met:
9c1839039SAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright
10c1839039SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer.
11c1839039SAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright
12c1839039SAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the
13c1839039SAlexander V. Chernikov * documentation and/or other materials provided with the distribution.
14c1839039SAlexander V. Chernikov *
15c1839039SAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c1839039SAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c1839039SAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c1839039SAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c1839039SAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c1839039SAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c1839039SAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c1839039SAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c1839039SAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c1839039SAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c1839039SAlexander V. Chernikov * SUCH DAMAGE.
26c1839039SAlexander V. Chernikov */
27c1839039SAlexander V. Chernikov
28c1839039SAlexander V. Chernikov #include <tests/ktest.h>
29c1839039SAlexander V. Chernikov #include <sys/cdefs.h>
30c1839039SAlexander V. Chernikov #include <sys/systm.h>
31c1839039SAlexander V. Chernikov #include <sys/malloc.h>
32c1839039SAlexander V. Chernikov #include <netlink/netlink.h>
33c1839039SAlexander V. Chernikov #include <netlink/netlink_ctl.h>
34*17083b94SGleb Smirnoff #include <netlink/netlink_var.h>
35c1839039SAlexander V. Chernikov #include <netlink/netlink_message_writer.h>
36c1839039SAlexander V. Chernikov
37c1839039SAlexander V. Chernikov #define KTEST_CALLER
38c1839039SAlexander V. Chernikov #include <netlink/ktest_netlink_message_writer.h>
39c1839039SAlexander V. Chernikov
40c1839039SAlexander V. Chernikov #ifdef INVARIANTS
41c1839039SAlexander V. Chernikov
42*17083b94SGleb Smirnoff struct test_nlbuf_attrs {
43c1839039SAlexander V. Chernikov uint32_t size;
44c1839039SAlexander V. Chernikov uint32_t expected_avail;
45c1839039SAlexander V. Chernikov int waitok;
46c1839039SAlexander V. Chernikov };
47c1839039SAlexander V. Chernikov
48*17083b94SGleb Smirnoff #define _OUT(_field) offsetof(struct test_nlbuf_attrs, _field)
49*17083b94SGleb Smirnoff static const struct nlattr_parser nla_p_nlbuf_w[] = {
50c1839039SAlexander V. Chernikov { .type = 1, .off = _OUT(size), .cb = nlattr_get_uint32 },
51c1839039SAlexander V. Chernikov { .type = 2, .off = _OUT(expected_avail), .cb = nlattr_get_uint32 },
52*17083b94SGleb Smirnoff { .type = 3, .off = _OUT(waitok), .cb = nlattr_get_uint32 },
53c1839039SAlexander V. Chernikov };
54c1839039SAlexander V. Chernikov #undef _OUT
55*17083b94SGleb Smirnoff NL_DECLARE_ATTR_PARSER(nlbuf_w_parser, nla_p_nlbuf_w);
56c1839039SAlexander V. Chernikov
57c1839039SAlexander V. Chernikov static int
test_nlbuf_parser(struct ktest_test_context * ctx,struct nlattr * nla)58*17083b94SGleb Smirnoff test_nlbuf_parser(struct ktest_test_context *ctx, struct nlattr *nla)
59c1839039SAlexander V. Chernikov {
60*17083b94SGleb Smirnoff struct test_nlbuf_attrs *attrs = npt_alloc(ctx->npt, sizeof(*attrs));
61c1839039SAlexander V. Chernikov
62c1839039SAlexander V. Chernikov ctx->arg = attrs;
63c1839039SAlexander V. Chernikov if (attrs != NULL)
64*17083b94SGleb Smirnoff return (nl_parse_nested(nla, &nlbuf_w_parser, ctx->npt, attrs));
65c1839039SAlexander V. Chernikov return (ENOMEM);
66c1839039SAlexander V. Chernikov }
67c1839039SAlexander V. Chernikov
68c1839039SAlexander V. Chernikov static int
test_nlbuf_writer_allocation(struct ktest_test_context * ctx)69*17083b94SGleb Smirnoff test_nlbuf_writer_allocation(struct ktest_test_context *ctx)
70c1839039SAlexander V. Chernikov {
71*17083b94SGleb Smirnoff struct test_nlbuf_attrs *attrs = ctx->arg;
72c1839039SAlexander V. Chernikov struct nl_writer nw = {};
73*17083b94SGleb Smirnoff u_int alloc_len;
74*17083b94SGleb Smirnoff bool ret;
75c1839039SAlexander V. Chernikov
76*17083b94SGleb Smirnoff ret = nlmsg_get_buf_wrapper(&nw, attrs->size, attrs->waitok);
77c1839039SAlexander V. Chernikov if (!ret)
78c1839039SAlexander V. Chernikov return (EINVAL);
79c1839039SAlexander V. Chernikov
80*17083b94SGleb Smirnoff alloc_len = nw.buf->buflen;
81c1839039SAlexander V. Chernikov KTEST_LOG(ctx, "requested %u, allocated %d", attrs->size, alloc_len);
82c1839039SAlexander V. Chernikov
83c1839039SAlexander V. Chernikov /* Mark enomem to avoid reallocation */
84c1839039SAlexander V. Chernikov nw.enomem = true;
85c1839039SAlexander V. Chernikov
86c1839039SAlexander V. Chernikov if (nlmsg_reserve_data(&nw, alloc_len, void *) == NULL) {
87c1839039SAlexander V. Chernikov KTEST_LOG(ctx, "unable to get %d bytes from the writer", alloc_len);
88c1839039SAlexander V. Chernikov return (EINVAL);
89c1839039SAlexander V. Chernikov }
90c1839039SAlexander V. Chernikov
91*17083b94SGleb Smirnoff nl_buf_free(nw.buf);
92c1839039SAlexander V. Chernikov
93c1839039SAlexander V. Chernikov if (alloc_len < attrs->expected_avail) {
94c1839039SAlexander V. Chernikov KTEST_LOG(ctx, "alloc_len %d, expected %u",
95c1839039SAlexander V. Chernikov alloc_len, attrs->expected_avail);
96c1839039SAlexander V. Chernikov return (EINVAL);
97c1839039SAlexander V. Chernikov }
98c1839039SAlexander V. Chernikov
99c1839039SAlexander V. Chernikov return (0);
100c1839039SAlexander V. Chernikov }
101c1839039SAlexander V. Chernikov #endif
102c1839039SAlexander V. Chernikov
103c1839039SAlexander V. Chernikov static const struct ktest_test_info tests[] = {
104c1839039SAlexander V. Chernikov #ifdef INVARIANTS
105c1839039SAlexander V. Chernikov {
106*17083b94SGleb Smirnoff .name = "test_nlbuf_writer_allocation",
107*17083b94SGleb Smirnoff .desc = "test different buffer sizes in the netlink writer",
108*17083b94SGleb Smirnoff .func = &test_nlbuf_writer_allocation,
109*17083b94SGleb Smirnoff .parse = &test_nlbuf_parser,
110c1839039SAlexander V. Chernikov },
111c1839039SAlexander V. Chernikov #endif
112c1839039SAlexander V. Chernikov };
113c1839039SAlexander V. Chernikov KTEST_MODULE_DECLARE(ktest_netlink_message_writer, tests);
114