111243735Srmind /*-
211243735Srmind * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
311243735Srmind * All rights reserved.
411243735Srmind *
511243735Srmind * This material is based upon work partially supported by The
611243735Srmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
711243735Srmind *
811243735Srmind * Redistribution and use in source and binary forms, with or without
911243735Srmind * modification, are permitted provided that the following conditions
1011243735Srmind * are met:
1111243735Srmind * 1. Redistributions of source code must retain the above copyright
1211243735Srmind * notice, this list of conditions and the following disclaimer.
1311243735Srmind * 2. Redistributions in binary form must reproduce the above copyright
1411243735Srmind * notice, this list of conditions and the following disclaimer in the
1511243735Srmind * documentation and/or other materials provided with the distribution.
1611243735Srmind *
1711243735Srmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1811243735Srmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1911243735Srmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2011243735Srmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2111243735Srmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2211243735Srmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2311243735Srmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2411243735Srmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2511243735Srmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2611243735Srmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2711243735Srmind * POSSIBILITY OF SUCH DAMAGE.
2811243735Srmind */
2911243735Srmind
3011243735Srmind /*
3111243735Srmind * NPF byte-code processing.
3211243735Srmind */
3311243735Srmind
340473fe8bSchristos #ifdef _KERNEL
3511243735Srmind #include <sys/cdefs.h>
36*94550a6dSrmind __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.14 2018/09/29 14:41:36 rmind Exp $");
3711243735Srmind
3811243735Srmind #include <sys/types.h>
3911243735Srmind #include <sys/param.h>
4011243735Srmind
415cd3adceSrmind #include <sys/bitops.h>
4211243735Srmind #include <sys/mbuf.h>
43c9e2fc6cSrmind #include <net/bpf.h>
440473fe8bSchristos #endif
4511243735Srmind
4611243735Srmind #define NPF_BPFCOP
4711243735Srmind #include "npf_impl.h"
4811243735Srmind
490473fe8bSchristos #if defined(_NPF_STANDALONE)
500473fe8bSchristos #define m_length(m) (nbuf)->nb_mops->getchainlen(m)
510473fe8bSchristos #endif
520473fe8bSchristos
5311243735Srmind /*
5411243735Srmind * BPF context and the coprocessor.
5511243735Srmind */
5611243735Srmind
5711243735Srmind static bpf_ctx_t *npf_bpfctx __read_mostly;
5811243735Srmind
59066eedd6Salnsn static uint32_t npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
60066eedd6Salnsn static uint32_t npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
6111243735Srmind
6211243735Srmind static const bpf_copfunc_t npf_bpfcop[] = {
6311243735Srmind [NPF_COP_L3] = npf_cop_l3,
6411243735Srmind [NPF_COP_TABLE] = npf_cop_table,
6511243735Srmind };
6611243735Srmind
675cd3adceSrmind #define BPF_MW_ALLMASK \
685cd3adceSrmind ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
695cd3adceSrmind
7011243735Srmind void
npf_bpf_sysinit(void)7111243735Srmind npf_bpf_sysinit(void)
7211243735Srmind {
7311243735Srmind npf_bpfctx = bpf_create();
7411243735Srmind bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
755cd3adceSrmind bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
7611243735Srmind }
7711243735Srmind
7811243735Srmind void
npf_bpf_sysfini(void)7911243735Srmind npf_bpf_sysfini(void)
8011243735Srmind {
8111243735Srmind bpf_destroy(npf_bpfctx);
8211243735Srmind }
8311243735Srmind
845cd3adceSrmind void
npf_bpf_prepare(npf_cache_t * npc,bpf_args_t * args,uint32_t * M)85d5cb4211Srmind npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
865cd3adceSrmind {
870473fe8bSchristos nbuf_t *nbuf = npc->npc_nbuf;
880473fe8bSchristos const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
895cd3adceSrmind const size_t pktlen = m_length(mbuf);
905cd3adceSrmind
915cd3adceSrmind /* Prepare the arguments for the BPF programs. */
920473fe8bSchristos #ifdef _NPF_STANDALONE
930473fe8bSchristos args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
940473fe8bSchristos args->wirelen = args->buflen = pktlen;
950473fe8bSchristos #else
965cd3adceSrmind args->pkt = (const uint8_t *)mbuf;
975cd3adceSrmind args->wirelen = pktlen;
985cd3adceSrmind args->buflen = 0;
990473fe8bSchristos #endif
100471a4a00Srmind args->mem = M;
1015cd3adceSrmind args->arg = npc;
102471a4a00Srmind
103471a4a00Srmind /*
104471a4a00Srmind * Convert address length to IP version. Just mask out
105471a4a00Srmind * number 4 or set 6 if higher bits set, such that:
106471a4a00Srmind *
107471a4a00Srmind * 0 => 0
108471a4a00Srmind * 4 => 4 (IPVERSION)
109471a4a00Srmind * 16 => 6 (IPV6_VERSION >> 4)
110471a4a00Srmind */
111471a4a00Srmind const u_int alen = npc->npc_alen;
112471a4a00Srmind const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
113471a4a00Srmind
114471a4a00Srmind /*
115471a4a00Srmind * Output words in the memory store:
116471a4a00Srmind * BPF_MW_IPVER IP version (4 or 6).
117471a4a00Srmind * BPF_MW_L4OFF L4 header offset.
118471a4a00Srmind * BPF_MW_L4PROTO L4 protocol.
119471a4a00Srmind */
120471a4a00Srmind M[BPF_MW_IPVER] = ver;
121471a4a00Srmind M[BPF_MW_L4OFF] = npc->npc_hlen;
122471a4a00Srmind M[BPF_MW_L4PROTO] = npc->npc_proto;
1235cd3adceSrmind }
1245cd3adceSrmind
12511243735Srmind int
npf_bpf_filter(bpf_args_t * args,const void * code,bpfjit_func_t jcode)1264659660dSrmind npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
12711243735Srmind {
1284659660dSrmind /* Execute JIT-compiled code. */
12911243735Srmind if (__predict_true(jcode)) {
1304659660dSrmind return jcode(npf_bpfctx, args);
13111243735Srmind }
132471a4a00Srmind
13311243735Srmind /* Execute BPF byte-code. */
1344659660dSrmind return bpf_filter_ext(npf_bpfctx, code, args);
13511243735Srmind }
13611243735Srmind
137c9e2fc6cSrmind void *
npf_bpf_compile(void * code,size_t size)138c9e2fc6cSrmind npf_bpf_compile(void *code, size_t size)
139c9e2fc6cSrmind {
140c9e2fc6cSrmind return bpf_jit_generate(npf_bpfctx, code, size);
141c9e2fc6cSrmind }
142c9e2fc6cSrmind
14311243735Srmind bool
npf_bpf_validate(const void * code,size_t len)14411243735Srmind npf_bpf_validate(const void *code, size_t len)
14511243735Srmind {
14611243735Srmind const size_t icount = len / sizeof(struct bpf_insn);
14711243735Srmind return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
14811243735Srmind }
14911243735Srmind
15011243735Srmind /*
15111243735Srmind * NPF_COP_L3: fetches layer 3 information.
15211243735Srmind */
15311243735Srmind static uint32_t
npf_cop_l3(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)154066eedd6Salnsn npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
15511243735Srmind {
156cd89282eSrmind const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
157471a4a00Srmind const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
158cd89282eSrmind uint32_t * const M = args->mem;
15911243735Srmind
16011243735Srmind M[BPF_MW_IPVER] = ver;
16111243735Srmind M[BPF_MW_L4OFF] = npc->npc_hlen;
16211243735Srmind M[BPF_MW_L4PROTO] = npc->npc_proto;
163471a4a00Srmind return ver; /* A <- IP version */
16411243735Srmind }
16511243735Srmind
16611243735Srmind #define SRC_FLAG_BIT (1U << 31)
16711243735Srmind
16811243735Srmind /*
16911243735Srmind * NPF_COP_TABLE: perform NPF table lookup.
17011243735Srmind *
17111243735Srmind * A <- non-zero (true) if found and zero (false) otherwise
17211243735Srmind */
17311243735Srmind static uint32_t
npf_cop_table(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)174066eedd6Salnsn npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
17511243735Srmind {
176cd89282eSrmind const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
1770473fe8bSchristos npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
17811243735Srmind const uint32_t tid = A & (SRC_FLAG_BIT - 1);
17911243735Srmind const npf_addr_t *addr;
180def81fffSrmind npf_table_t *t;
18111243735Srmind
18211c8297cSrmind if (!npf_iscached(npc, NPC_IP46)) {
18311c8297cSrmind return 0;
18411c8297cSrmind }
18511c8297cSrmind t = npf_tableset_getbyid(tblset, tid);
18611c8297cSrmind if (__predict_false(!t)) {
187def81fffSrmind return 0;
188def81fffSrmind }
18924c949d4Srmind addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
190def81fffSrmind return npf_table_lookup(t, npc->npc_alen, addr) == 0;
19111243735Srmind }
192