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 0 : static int _bf_matcher_generate_icmp_fields(struct bf_program *program,
19 : const struct bf_matcher *matcher,
20 : const size_t offset)
21 : {
22 0 : const uint8_t value = *(uint8_t *)bf_matcher_payload(matcher);
23 :
24 0 : EMIT(program, BPF_LDX_MEM(BPF_B, BPF_REG_1, BPF_REG_6, offset));
25 :
26 0 : switch (bf_matcher_get_op(matcher)) {
27 0 : case BF_MATCHER_EQ:
28 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
29 : BPF_JMP_IMM(BPF_JNE, BPF_REG_1, value, 0));
30 0 : break;
31 0 : case BF_MATCHER_NE:
32 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
33 : BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, value, 0));
34 0 : 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 0 : static int _bf_matcher_generate_icmp6_fields(struct bf_program *program,
45 : const struct bf_matcher *matcher)
46 : {
47 0 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_ICMPV6_TYPE ?
48 0 : offsetof(struct icmp6hdr, icmp6_type) :
49 : offsetof(struct icmp6hdr, icmp6_code);
50 :
51 0 : EMIT_FIXUP_JMP_NEXT_RULE(
52 : program, BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMPV6, 0));
53 0 : EMIT(program,
54 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
55 :
56 0 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
57 : }
58 :
59 0 : static int _bf_matcher_generate_icmp4_fields(struct bf_program *program,
60 : const struct bf_matcher *matcher)
61 : {
62 0 : size_t offset = bf_matcher_get_type(matcher) == BF_MATCHER_ICMP_TYPE ?
63 0 : offsetof(struct icmphdr, type) :
64 : offsetof(struct icmphdr, code);
65 :
66 0 : EMIT_FIXUP_JMP_NEXT_RULE(program,
67 : BPF_JMP_IMM(BPF_JNE, BPF_REG_8, IPPROTO_ICMP, 0));
68 0 : EMIT(program,
69 : BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_10, BF_PROG_CTX_OFF(l4_hdr)));
70 :
71 0 : return _bf_matcher_generate_icmp_fields(program, matcher, offset);
72 : }
73 :
74 0 : int bf_matcher_generate_icmp(struct bf_program *program,
75 : const struct bf_matcher *matcher)
76 : {
77 : int r;
78 :
79 0 : switch (bf_matcher_get_type(matcher)) {
80 0 : case BF_MATCHER_ICMP_TYPE:
81 : case BF_MATCHER_ICMP_CODE:
82 0 : r = _bf_matcher_generate_icmp4_fields(program, matcher);
83 0 : break;
84 0 : case BF_MATCHER_ICMPV6_TYPE:
85 : case BF_MATCHER_ICMPV6_CODE:
86 0 : r = _bf_matcher_generate_icmp6_fields(program, matcher);
87 0 : 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 : }
|