Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2022 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include <linux/bpf.h>
7 : : #include <linux/bpf_common.h>
8 : : #include <linux/icmp.h>
9 : : #include <linux/icmpv6.h>
10 : : #include <linux/in.h>
11 : :
12 : : #include <errno.h>
13 : :
14 : : #include <bpfilter/matcher.h>
15 : :
16 : : #include "cgen/program.h"
17 : :
18 : 204 : static int _bf_matcher_generate_icmp_fields(struct bf_program *program,
19 : : const struct bf_matcher *matcher,
20 : : const size_t offset)
21 : : {
22 : 204 : const uint8_t value = *(uint8_t *)bf_matcher_payload(matcher);
23 : :
24 [ - + ]: 204 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, offset));
25 : :
26 [ + + - ]: 204 : switch (bf_matcher_get_op(matcher)) {
27 : 104 : case BF_MATCHER_EQ:
28 [ - + ]: 104 : EMIT_FIXUP_JMP_NEXT_RULE(program,
29 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, value, 0));
30 : 104 : break;
31 : 100 : case BF_MATCHER_NE:
32 [ - + ]: 100 : EMIT_FIXUP_JMP_NEXT_RULE(program,
33 : : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, value, 0));
34 : 100 : break;
35 : 0 : default:
36 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher operator '%s' (%d)",
37 : : bf_matcher_op_to_str(bf_matcher_get_op(matcher)),
38 : : bf_matcher_get_op(matcher));
39 : : }
40 : :
41 : : return 0;
42 : : }
43 : :
44 : 100 : static int _bf_matcher_generate_icmp6_fields(struct bf_program *program,
45 : : const struct bf_matcher *matcher)
46 : : {
47 : 100 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_ICMPV6_TYPE ?
48 : 100 : offsetof(struct icmp6hdr, icmp6_type) :
49 : : offsetof(struct icmp6hdr, icmp6_code);
50 : :
51 [ - + ]: 100 : EMIT_FIXUP_JMP_NEXT_RULE(
52 : : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMPV6, 0));
53 [ - + ]: 100 : EMIT(program,
54 : : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
55 : :
56 : 100 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
57 : : }
58 : :
59 : 104 : static int _bf_matcher_generate_icmp4_fields(struct bf_program *program,
60 : : const struct bf_matcher *matcher)
61 : : {
62 : 104 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_ICMP_TYPE ?
63 : 104 : offsetof(struct icmphdr, type) :
64 : : offsetof(struct icmphdr, code);
65 : :
66 [ - + ]: 104 : EMIT_FIXUP_JMP_NEXT_RULE(program,
67 : : BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMP, 0));
68 [ - + ]: 104 : EMIT(program,
69 : : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
70 : :
71 : 104 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
72 : : }
73 : :
74 : 204 : int bf_matcher_generate_icmp(struct bf_program *program,
75 : : const struct bf_matcher *matcher)
76 : : {
77 : : int r;
78 : :
79 [ + + - ]: 204 : switch (bf_matcher_get_type(matcher)) {
80 : 104 : case BF_MATCHER_ICMP_TYPE:
81 : : case BF_MATCHER_ICMP_CODE:
82 : 104 : r = _bf_matcher_generate_icmp4_fields(program, matcher);
83 : 104 : break;
84 : 100 : case BF_MATCHER_ICMPV6_TYPE:
85 : : case BF_MATCHER_ICMPV6_CODE:
86 : 100 : r = _bf_matcher_generate_icmp6_fields(program, matcher);
87 : 100 : break;
88 : 0 : default:
89 [ # # ]: 0 : return bf_err_r(-EINVAL, "unknown matcher type %d",
90 : : bf_matcher_get_type(matcher));
91 : : };
92 : :
93 : : return r;
94 : : }
|