1/*	$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $ */
2
3/*-
4 * Copyright (c) 2013-2014 Alexander Nasonov.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__RCSID("$NetBSD: t_cop.c,v 1.4 2014/07/13 21:35:33 alnsn Exp $");
34
35#include <atf-c.h>
36#include <stdint.h>
37#include <string.h>
38
39#define __BPF_PRIVATE
40#include <net/bpf.h>
41#include <net/bpfjit.h>
42
43static uint32_t retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44static uint32_t retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
45static uint32_t retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
46static uint32_t retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
47static uint32_t setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
48
49static const bpf_copfunc_t copfuncs[] = {
50	&retA,
51	&retBL,
52	&retWL,
53	&retNF,
54	&setARG
55};
56
57static const bpf_ctx_t ctx = {
58	.copfuncs = copfuncs,
59	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
60	.extwords = 0
61};
62
63static uint32_t
64retA(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
65{
66
67	return A;
68}
69
70static uint32_t
71retBL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
72{
73
74	return args->buflen;
75}
76
77static uint32_t
78retWL(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
79{
80
81	return args->wirelen;
82}
83
84static uint32_t
85retNF(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
86{
87
88	return bc->nfuncs;
89}
90
91/*
92 * COP function with a side effect.
93 */
94static uint32_t
95setARG(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
96{
97	bool *arg = (bool *)args->arg;
98	bool old = *arg;
99
100	*arg = true;
101	return old;
102}
103
104ATF_TC(libbpfjit_cop_no_ctx);
105ATF_TC_HEAD(libbpfjit_cop_no_ctx, tc)
106{
107	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COP "
108	    "instruction isn't valid without a context");
109}
110
111ATF_TC_BODY(libbpfjit_cop_no_ctx, tc)
112{
113	static struct bpf_insn insns[] = {
114		BPF_STMT(BPF_MISC+BPF_COP, 0),
115		BPF_STMT(BPF_RET+BPF_K, 7)
116	};
117
118	bpfjit_func_t code;
119
120	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
121
122	ATF_CHECK(!bpf_validate(insns, insn_count));
123
124	code = bpfjit_generate_code(NULL, insns, insn_count);
125	ATF_CHECK(code == NULL);
126}
127
128ATF_TC(libbpfjit_cop_ret_A);
129ATF_TC_HEAD(libbpfjit_cop_ret_A, tc)
130{
131	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
132	    "that returns a content of the A register");
133}
134
135ATF_TC_BODY(libbpfjit_cop_ret_A, tc)
136{
137	static struct bpf_insn insns[] = {
138		BPF_STMT(BPF_LD+BPF_IMM, 13),
139		BPF_STMT(BPF_MISC+BPF_COP, 0), // retA
140		BPF_STMT(BPF_RET+BPF_A, 0)
141	};
142
143	bpfjit_func_t code;
144	uint8_t pkt[1] = { 0 };
145	bpf_args_t args = {
146		.pkt = pkt,
147		.buflen = sizeof(pkt),
148		.wirelen = sizeof(pkt),
149	};
150
151	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
152
153	code = bpfjit_generate_code(&ctx, insns, insn_count);
154	ATF_REQUIRE(code != NULL);
155
156	ATF_CHECK(code(&ctx, &args) == 13);
157
158	bpfjit_free_code(code);
159}
160
161ATF_TC(libbpfjit_cop_ret_buflen);
162ATF_TC_HEAD(libbpfjit_cop_ret_buflen, tc)
163{
164	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
165	    "that returns the buflen argument");
166}
167
168ATF_TC_BODY(libbpfjit_cop_ret_buflen, tc)
169{
170	static struct bpf_insn insns[] = {
171		BPF_STMT(BPF_LD+BPF_IMM, 13),
172		BPF_STMT(BPF_MISC+BPF_COP, 1), // retBL
173		BPF_STMT(BPF_RET+BPF_A, 0)
174	};
175
176	bpfjit_func_t code;
177	uint8_t pkt[1] = { 0 };
178	bpf_args_t args = {
179		.pkt = pkt,
180		.buflen = sizeof(pkt),
181		.wirelen = sizeof(pkt)
182	};
183
184	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
185
186	code = bpfjit_generate_code(&ctx, insns, insn_count);
187	ATF_REQUIRE(code != NULL);
188
189	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
190
191	bpfjit_free_code(code);
192}
193
194ATF_TC(libbpfjit_cop_ret_wirelen);
195ATF_TC_HEAD(libbpfjit_cop_ret_wirelen, tc)
196{
197	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
198	    "that returns the wirelen argument");
199}
200
201ATF_TC_BODY(libbpfjit_cop_ret_wirelen, tc)
202{
203	static struct bpf_insn insns[] = {
204		BPF_STMT(BPF_LD+BPF_IMM, 13),
205		BPF_STMT(BPF_MISC+BPF_COP, 2), // retWL
206		BPF_STMT(BPF_RET+BPF_A, 0)
207	};
208
209	bpfjit_func_t code;
210	uint8_t pkt[1] = { 0 };
211	bpf_args_t args = {
212		.pkt = pkt,
213		.buflen = sizeof(pkt),
214		.wirelen = sizeof(pkt)
215	};
216
217	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
218
219	code = bpfjit_generate_code(&ctx, insns, insn_count);
220	ATF_REQUIRE(code != NULL);
221
222	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
223
224	bpfjit_free_code(code);
225}
226
227ATF_TC(libbpfjit_cop_ret_nfuncs);
228ATF_TC_HEAD(libbpfjit_cop_ret_nfuncs, tc)
229{
230	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
231	    "that returns nfuncs member of the context argument");
232}
233
234ATF_TC_BODY(libbpfjit_cop_ret_nfuncs, tc)
235{
236	static struct bpf_insn insns[] = {
237		BPF_STMT(BPF_LD+BPF_IMM, 13),
238		BPF_STMT(BPF_MISC+BPF_COP, 3), // retNF
239		BPF_STMT(BPF_RET+BPF_A, 0)
240	};
241
242	bpfjit_func_t code;
243	uint8_t pkt[1] = { 0 };
244	bpf_args_t args = {
245		.pkt = pkt,
246		.buflen = sizeof(pkt),
247		.wirelen = sizeof(pkt)
248	};
249
250	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
251
252	code = bpfjit_generate_code(&ctx, insns, insn_count);
253	ATF_REQUIRE(code != NULL);
254
255	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
256
257	bpfjit_free_code(code);
258}
259
260ATF_TC(libbpfjit_cop_side_effect);
261ATF_TC_HEAD(libbpfjit_cop_side_effect, tc)
262{
263	atf_tc_set_md_var(tc, "descr",
264	    "Test that ABC optimization doesn't skip BPF_COP call");
265}
266
267ATF_TC_BODY(libbpfjit_cop_side_effect, tc)
268{
269	static struct bpf_insn insns[] = {
270		BPF_STMT(BPF_LD+BPF_IMM, 13),
271		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
272		BPF_STMT(BPF_MISC+BPF_COP, 4), // setARG
273		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
274		BPF_STMT(BPF_RET+BPF_A, 0)
275	};
276
277	bpfjit_func_t code;
278	bool arg = false;
279	uint8_t pkt[1] = { 0 };
280	bpf_args_t args = {
281		.pkt = pkt,
282		.buflen = sizeof(pkt),
283		.wirelen = sizeof(pkt),
284		.mem = NULL,
285		.arg = &arg
286	};
287
288	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
289
290	code = bpfjit_generate_code(&ctx, insns, insn_count);
291	ATF_REQUIRE(code != NULL);
292
293	ATF_CHECK(code(&ctx, &args) == 0);
294	ATF_CHECK(arg == true);
295
296	bpfjit_free_code(code);
297}
298
299ATF_TC(libbpfjit_cop_copx);
300ATF_TC_HEAD(libbpfjit_cop_copx, tc)
301{
302	atf_tc_set_md_var(tc, "descr",
303	    "Test BPF_COP call followed by BPF_COPX call");
304}
305
306ATF_TC_BODY(libbpfjit_cop_copx, tc)
307{
308	static struct bpf_insn insns[] = {
309		BPF_STMT(BPF_LD+BPF_IMM, 1),         /* A <- 1    */
310		BPF_STMT(BPF_MISC+BPF_COP, 0),       /* retA      */
311		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
312		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
313		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
314		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
315		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retNF     */
316		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
317		BPF_STMT(BPF_RET+BPF_A, 0)
318	};
319
320	bpfjit_func_t code;
321	uint8_t pkt[1] = { 2 };
322	bpf_args_t args = {
323		.pkt = pkt,
324		.buflen = sizeof(pkt),
325		.wirelen = sizeof(pkt),
326	};
327
328	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
329
330	code = bpfjit_generate_code(&ctx, insns, insn_count);
331	ATF_REQUIRE(code != NULL);
332
333	ATF_CHECK(code(&ctx, &args) == 3 + ctx.nfuncs);
334
335	bpfjit_free_code(code);
336}
337
338ATF_TC(libbpfjit_cop_invalid_index);
339ATF_TC_HEAD(libbpfjit_cop_invalid_index, tc)
340{
341	atf_tc_set_md_var(tc, "descr",
342	    "Test that out-of-range coprocessor function fails validation");
343}
344
345ATF_TC_BODY(libbpfjit_cop_invalid_index, tc)
346{
347	static struct bpf_insn insns[] = {
348		BPF_STMT(BPF_LD+BPF_IMM, 13),
349		BPF_STMT(BPF_MISC+BPF_COP, 6), // invalid index
350		BPF_STMT(BPF_RET+BPF_K, 27)
351	};
352
353	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
354
355	ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
356}
357
358ATF_TC(libbpfjit_copx_no_ctx);
359ATF_TC_HEAD(libbpfjit_copx_no_ctx, tc)
360{
361	atf_tc_set_md_var(tc, "descr", "Test that bpf program with BPF_COPX "
362	    "instruction isn't valid without a context");
363}
364
365ATF_TC_BODY(libbpfjit_copx_no_ctx, tc)
366{
367	static struct bpf_insn insns[] = {
368		BPF_STMT(BPF_MISC+BPF_COP, 0),
369		BPF_STMT(BPF_RET+BPF_K, 7)
370	};
371
372	bpfjit_func_t code;
373
374	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
375
376	ATF_CHECK(!bpf_validate(insns, insn_count));
377
378	code = bpfjit_generate_code(NULL, insns, insn_count);
379	ATF_CHECK(code == NULL);
380}
381
382ATF_TC(libbpfjit_copx_ret_A);
383ATF_TC_HEAD(libbpfjit_copx_ret_A, tc)
384{
385	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
386	    "that returns a content of the A register");
387}
388
389ATF_TC_BODY(libbpfjit_copx_ret_A, tc)
390{
391	static struct bpf_insn insns[] = {
392		BPF_STMT(BPF_LD+BPF_IMM, 13),
393		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retA
394		BPF_STMT(BPF_MISC+BPF_COPX, 0),
395		BPF_STMT(BPF_RET+BPF_A, 0)
396	};
397
398	bpfjit_func_t code;
399	uint8_t pkt[1] = { 0 };
400	bpf_args_t args = {
401		.pkt = pkt,
402		.buflen = sizeof(pkt),
403		.wirelen = sizeof(pkt),
404	};
405
406	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
407
408	code = bpfjit_generate_code(&ctx, insns, insn_count);
409	ATF_REQUIRE(code != NULL);
410
411	ATF_CHECK(code(&ctx, &args) == 13);
412
413	bpfjit_free_code(code);
414}
415
416ATF_TC(libbpfjit_copx_ret_buflen);
417ATF_TC_HEAD(libbpfjit_copx_ret_buflen, tc)
418{
419	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
420	    "that returns the buflen argument");
421}
422
423ATF_TC_BODY(libbpfjit_copx_ret_buflen, tc)
424{
425	static struct bpf_insn insns[] = {
426		BPF_STMT(BPF_LD+BPF_IMM, 13),
427		BPF_STMT(BPF_LDX+BPF_IMM, 1), // retBL
428		BPF_STMT(BPF_MISC+BPF_COPX, 0),
429		BPF_STMT(BPF_RET+BPF_A, 0)
430	};
431
432	bpfjit_func_t code;
433	uint8_t pkt[1] = { 0 };
434	bpf_args_t args = {
435		.pkt = pkt,
436		.buflen = sizeof(pkt),
437		.wirelen = sizeof(pkt)
438	};
439
440	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
441
442	code = bpfjit_generate_code(&ctx, insns, insn_count);
443	ATF_REQUIRE(code != NULL);
444
445	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
446
447	bpfjit_free_code(code);
448}
449
450ATF_TC(libbpfjit_copx_ret_wirelen);
451ATF_TC_HEAD(libbpfjit_copx_ret_wirelen, tc)
452{
453	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
454	    "that returns the wirelen argument");
455}
456
457ATF_TC_BODY(libbpfjit_copx_ret_wirelen, tc)
458{
459	static struct bpf_insn insns[] = {
460		BPF_STMT(BPF_LDX+BPF_IMM, 2), // retWL
461		BPF_STMT(BPF_LD+BPF_IMM, 13),
462		BPF_STMT(BPF_MISC+BPF_COPX, 0),
463		BPF_STMT(BPF_RET+BPF_A, 0)
464	};
465
466	bpfjit_func_t code;
467	uint8_t pkt[1] = { 0 };
468	bpf_args_t args = {
469		.pkt = pkt,
470		.buflen = sizeof(pkt),
471		.wirelen = sizeof(pkt)
472	};
473
474	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
475
476	code = bpfjit_generate_code(&ctx, insns, insn_count);
477	ATF_REQUIRE(code != NULL);
478
479	ATF_CHECK(code(&ctx, &args) == sizeof(pkt));
480
481	bpfjit_free_code(code);
482}
483
484ATF_TC(libbpfjit_copx_ret_nfuncs);
485ATF_TC_HEAD(libbpfjit_copx_ret_nfuncs, tc)
486{
487	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
488	    "that returns nfuncs member of the context argument");
489}
490
491ATF_TC_BODY(libbpfjit_copx_ret_nfuncs, tc)
492{
493	static struct bpf_insn insns[] = {
494		BPF_STMT(BPF_LD+BPF_IMM, 13),
495		BPF_STMT(BPF_LDX+BPF_IMM, 3), // retNF
496		BPF_STMT(BPF_MISC+BPF_COPX, 0),
497		BPF_STMT(BPF_RET+BPF_A, 0)
498	};
499
500	bpfjit_func_t code;
501	uint8_t pkt[1] = { 0 };
502	bpf_args_t args = {
503		.pkt = pkt,
504		.buflen = sizeof(pkt),
505		.wirelen = sizeof(pkt)
506	};
507
508	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
509
510	code = bpfjit_generate_code(&ctx, insns, insn_count);
511	ATF_REQUIRE(code != NULL);
512
513	ATF_CHECK(code(&ctx, &args) == ctx.nfuncs);
514
515	bpfjit_free_code(code);
516}
517
518ATF_TC(libbpfjit_copx_side_effect);
519ATF_TC_HEAD(libbpfjit_copx_side_effect, tc)
520{
521	atf_tc_set_md_var(tc, "descr",
522	    "Test that ABC optimization doesn't skip BPF_COPX call");
523}
524
525ATF_TC_BODY(libbpfjit_copx_side_effect, tc)
526{
527	static struct bpf_insn insns[] = {
528		BPF_STMT(BPF_LD+BPF_IMM, 13),
529		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),
530		BPF_STMT(BPF_LDX+BPF_IMM, 4), // setARG
531		BPF_STMT(BPF_MISC+BPF_COPX, 0),
532		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99999),
533		BPF_STMT(BPF_RET+BPF_A, 0)
534	};
535
536	bpfjit_func_t code;
537	bool arg = false;
538	uint8_t pkt[1] = { 0 };
539	bpf_args_t args = {
540		.pkt = pkt,
541		.buflen = sizeof(pkt),
542		.wirelen = sizeof(pkt),
543		.mem = NULL,
544		.arg = &arg
545	};
546
547	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
548
549	code = bpfjit_generate_code(&ctx, insns, insn_count);
550	ATF_REQUIRE(code != NULL);
551
552	ATF_CHECK(code(&ctx, &args) == 0);
553	ATF_CHECK(arg == true);
554
555	bpfjit_free_code(code);
556}
557
558ATF_TC(libbpfjit_copx_cop);
559ATF_TC_HEAD(libbpfjit_copx_cop, tc)
560{
561	atf_tc_set_md_var(tc, "descr",
562	    "Test BPF_COPX call followed by BPF_COP call");
563}
564
565ATF_TC_BODY(libbpfjit_copx_cop, tc)
566{
567	static struct bpf_insn insns[] = {
568		BPF_STMT(BPF_LDX+BPF_IMM, 2),        /* X <- 2    */
569		BPF_STMT(BPF_MISC+BPF_COPX, 0),      /* retWL     */
570		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
571		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
572		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),   /* A = P[0]  */
573		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
574		BPF_STMT(BPF_MISC+BPF_TAX, 0),       /* X <- A    */
575		BPF_STMT(BPF_MISC+BPF_COP, 3),      /* retNF     */
576		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 1),  /* A = A + X */
577		BPF_STMT(BPF_RET+BPF_A, 0)
578	};
579
580	bpfjit_func_t code;
581	uint8_t pkt[1] = { 2 };
582	bpf_args_t args = {
583		.pkt = pkt,
584		.buflen = sizeof(pkt),
585		.wirelen = sizeof(pkt),
586	};
587
588	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
589
590	code = bpfjit_generate_code(&ctx, insns, insn_count);
591	ATF_REQUIRE(code != NULL);
592
593	ATF_CHECK(code(&ctx, &args) == 5 + ctx.nfuncs);
594
595	bpfjit_free_code(code);
596}
597
598ATF_TC(libbpfjit_copx_invalid_index);
599ATF_TC_HEAD(libbpfjit_copx_invalid_index, tc)
600{
601	atf_tc_set_md_var(tc, "descr",
602	    "Test that out-of-range BPF_COPX call fails at runtime");
603}
604
605ATF_TC_BODY(libbpfjit_copx_invalid_index, tc)
606{
607	static struct bpf_insn insns[] = {
608		BPF_STMT(BPF_LDX+BPF_IMM, 5), // invalid index
609		BPF_STMT(BPF_MISC+BPF_COPX, 0),
610		BPF_STMT(BPF_RET+BPF_K, 27)
611	};
612
613	bpfjit_func_t code;
614	uint8_t pkt[1] = { 0 };
615	bpf_args_t args = {
616		.pkt = pkt,
617		.buflen = sizeof(pkt),
618		.wirelen = sizeof(pkt)
619	};
620
621	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
622
623	code = bpfjit_generate_code(&ctx, insns, insn_count);
624	ATF_REQUIRE(code != NULL);
625
626	ATF_CHECK(code(&ctx, &args) == 0);
627
628	bpfjit_free_code(code);
629}
630
631ATF_TP_ADD_TCS(tp)
632{
633
634	/*
635	 * For every new test please also add a similar test
636	 * to ../../net/bpfjit/t_cop.c
637	 */
638	ATF_TP_ADD_TC(tp, libbpfjit_cop_no_ctx);
639	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_A);
640	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_buflen);
641	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_wirelen);
642	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_nfuncs);
643	ATF_TP_ADD_TC(tp, libbpfjit_cop_side_effect);
644	ATF_TP_ADD_TC(tp, libbpfjit_cop_copx);
645	ATF_TP_ADD_TC(tp, libbpfjit_cop_invalid_index);
646
647	ATF_TP_ADD_TC(tp, libbpfjit_copx_no_ctx);
648	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_A);
649	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_buflen);
650	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_wirelen);
651	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_nfuncs);
652	ATF_TP_ADD_TC(tp, libbpfjit_copx_side_effect);
653	ATF_TP_ADD_TC(tp, libbpfjit_copx_cop);
654	ATF_TP_ADD_TC(tp, libbpfjit_copx_invalid_index);
655
656	return atf_no_error();
657}
658