14e592132Srmind /*-
24e592132Srmind * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
34e592132Srmind * All rights reserved.
44e592132Srmind *
54e592132Srmind * This material is based upon work partially supported by The
64e592132Srmind * NetBSD Foundation under a contract with Mindaugas Rasiukevicius.
74e592132Srmind *
84e592132Srmind * Redistribution and use in source and binary forms, with or without
94e592132Srmind * modification, are permitted provided that the following conditions
104e592132Srmind * are met:
114e592132Srmind * 1. Redistributions of source code must retain the above copyright
124e592132Srmind * notice, this list of conditions and the following disclaimer.
134e592132Srmind * 2. Redistributions in binary form must reproduce the above copyright
144e592132Srmind * notice, this list of conditions and the following disclaimer in the
154e592132Srmind * documentation and/or other materials provided with the distribution.
164e592132Srmind *
174e592132Srmind * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
184e592132Srmind * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
194e592132Srmind * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
204e592132Srmind * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
214e592132Srmind * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
224e592132Srmind * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
234e592132Srmind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
244e592132Srmind * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
254e592132Srmind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
264e592132Srmind * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
274e592132Srmind * POSSIBILITY OF SUCH DAMAGE.
284e592132Srmind */
294e592132Srmind
304e592132Srmind /*
314e592132Srmind * NPF byte-code processing.
324e592132Srmind */
334e592132Srmind
34f75d79ebSchristos #ifdef _KERNEL
354e592132Srmind #include <sys/cdefs.h>
36*39013e66Srmind __KERNEL_RCSID(0, "$NetBSD: npf_bpf.c,v 1.14 2018/09/29 14:41:36 rmind Exp $");
374e592132Srmind
384e592132Srmind #include <sys/types.h>
394e592132Srmind #include <sys/param.h>
404e592132Srmind
41263d30c4Srmind #include <sys/bitops.h>
424e592132Srmind #include <sys/mbuf.h>
43c782c888Srmind #include <net/bpf.h>
44f75d79ebSchristos #endif
454e592132Srmind
464e592132Srmind #define NPF_BPFCOP
474e592132Srmind #include "npf_impl.h"
484e592132Srmind
49f75d79ebSchristos #if defined(_NPF_STANDALONE)
50f75d79ebSchristos #define m_length(m) (nbuf)->nb_mops->getchainlen(m)
51f75d79ebSchristos #endif
52f75d79ebSchristos
534e592132Srmind /*
544e592132Srmind * BPF context and the coprocessor.
554e592132Srmind */
564e592132Srmind
574e592132Srmind static bpf_ctx_t *npf_bpfctx __read_mostly;
584e592132Srmind
59f9dc8d88Salnsn static uint32_t npf_cop_l3(const bpf_ctx_t *, bpf_args_t *, uint32_t);
60f9dc8d88Salnsn static uint32_t npf_cop_table(const bpf_ctx_t *, bpf_args_t *, uint32_t);
614e592132Srmind
624e592132Srmind static const bpf_copfunc_t npf_bpfcop[] = {
634e592132Srmind [NPF_COP_L3] = npf_cop_l3,
644e592132Srmind [NPF_COP_TABLE] = npf_cop_table,
654e592132Srmind };
664e592132Srmind
67263d30c4Srmind #define BPF_MW_ALLMASK \
68263d30c4Srmind ((1U << BPF_MW_IPVER) | (1U << BPF_MW_L4OFF) | (1U << BPF_MW_L4PROTO))
69263d30c4Srmind
704e592132Srmind void
npf_bpf_sysinit(void)714e592132Srmind npf_bpf_sysinit(void)
724e592132Srmind {
734e592132Srmind npf_bpfctx = bpf_create();
744e592132Srmind bpf_set_cop(npf_bpfctx, npf_bpfcop, __arraycount(npf_bpfcop));
75263d30c4Srmind bpf_set_extmem(npf_bpfctx, NPF_BPF_NWORDS, BPF_MW_ALLMASK);
764e592132Srmind }
774e592132Srmind
784e592132Srmind void
npf_bpf_sysfini(void)794e592132Srmind npf_bpf_sysfini(void)
804e592132Srmind {
814e592132Srmind bpf_destroy(npf_bpfctx);
824e592132Srmind }
834e592132Srmind
84263d30c4Srmind void
npf_bpf_prepare(npf_cache_t * npc,bpf_args_t * args,uint32_t * M)85a7d2a608Srmind npf_bpf_prepare(npf_cache_t *npc, bpf_args_t *args, uint32_t *M)
86263d30c4Srmind {
87f75d79ebSchristos nbuf_t *nbuf = npc->npc_nbuf;
88f75d79ebSchristos const struct mbuf *mbuf = nbuf_head_mbuf(nbuf);
89263d30c4Srmind const size_t pktlen = m_length(mbuf);
90263d30c4Srmind
91263d30c4Srmind /* Prepare the arguments for the BPF programs. */
92f75d79ebSchristos #ifdef _NPF_STANDALONE
93f75d79ebSchristos args->pkt = (const uint8_t *)nbuf_dataptr(nbuf);
94f75d79ebSchristos args->wirelen = args->buflen = pktlen;
95f75d79ebSchristos #else
96263d30c4Srmind args->pkt = (const uint8_t *)mbuf;
97263d30c4Srmind args->wirelen = pktlen;
98263d30c4Srmind args->buflen = 0;
99f75d79ebSchristos #endif
1009c7a886eSrmind args->mem = M;
101263d30c4Srmind args->arg = npc;
1029c7a886eSrmind
1039c7a886eSrmind /*
1049c7a886eSrmind * Convert address length to IP version. Just mask out
1059c7a886eSrmind * number 4 or set 6 if higher bits set, such that:
1069c7a886eSrmind *
1079c7a886eSrmind * 0 => 0
1089c7a886eSrmind * 4 => 4 (IPVERSION)
1099c7a886eSrmind * 16 => 6 (IPV6_VERSION >> 4)
1109c7a886eSrmind */
1119c7a886eSrmind const u_int alen = npc->npc_alen;
1129c7a886eSrmind const uint32_t ver = (alen & 4) | ((alen >> 4) * 6);
1139c7a886eSrmind
1149c7a886eSrmind /*
1159c7a886eSrmind * Output words in the memory store:
1169c7a886eSrmind * BPF_MW_IPVER IP version (4 or 6).
1179c7a886eSrmind * BPF_MW_L4OFF L4 header offset.
1189c7a886eSrmind * BPF_MW_L4PROTO L4 protocol.
1199c7a886eSrmind */
1209c7a886eSrmind M[BPF_MW_IPVER] = ver;
1219c7a886eSrmind M[BPF_MW_L4OFF] = npc->npc_hlen;
1229c7a886eSrmind M[BPF_MW_L4PROTO] = npc->npc_proto;
123263d30c4Srmind }
124263d30c4Srmind
1254e592132Srmind int
npf_bpf_filter(bpf_args_t * args,const void * code,bpfjit_func_t jcode)126c4d05d45Srmind npf_bpf_filter(bpf_args_t *args, const void *code, bpfjit_func_t jcode)
1274e592132Srmind {
128c4d05d45Srmind /* Execute JIT-compiled code. */
1294e592132Srmind if (__predict_true(jcode)) {
130c4d05d45Srmind return jcode(npf_bpfctx, args);
1314e592132Srmind }
1329c7a886eSrmind
1334e592132Srmind /* Execute BPF byte-code. */
134c4d05d45Srmind return bpf_filter_ext(npf_bpfctx, code, args);
1354e592132Srmind }
1364e592132Srmind
137c782c888Srmind void *
npf_bpf_compile(void * code,size_t size)138c782c888Srmind npf_bpf_compile(void *code, size_t size)
139c782c888Srmind {
140c782c888Srmind return bpf_jit_generate(npf_bpfctx, code, size);
141c782c888Srmind }
142c782c888Srmind
1434e592132Srmind bool
npf_bpf_validate(const void * code,size_t len)1444e592132Srmind npf_bpf_validate(const void *code, size_t len)
1454e592132Srmind {
1464e592132Srmind const size_t icount = len / sizeof(struct bpf_insn);
1474e592132Srmind return bpf_validate_ext(npf_bpfctx, code, icount) != 0;
1484e592132Srmind }
1494e592132Srmind
1504e592132Srmind /*
1514e592132Srmind * NPF_COP_L3: fetches layer 3 information.
1524e592132Srmind */
1534e592132Srmind static uint32_t
npf_cop_l3(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)154f9dc8d88Salnsn npf_cop_l3(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
1554e592132Srmind {
156d0748eb9Srmind const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
1579c7a886eSrmind const uint32_t ver = (npc->npc_alen & 4) | ((npc->npc_alen >> 4) * 6);
158d0748eb9Srmind uint32_t * const M = args->mem;
1594e592132Srmind
1604e592132Srmind M[BPF_MW_IPVER] = ver;
1614e592132Srmind M[BPF_MW_L4OFF] = npc->npc_hlen;
1624e592132Srmind M[BPF_MW_L4PROTO] = npc->npc_proto;
1639c7a886eSrmind return ver; /* A <- IP version */
1644e592132Srmind }
1654e592132Srmind
1664e592132Srmind #define SRC_FLAG_BIT (1U << 31)
1674e592132Srmind
1684e592132Srmind /*
1694e592132Srmind * NPF_COP_TABLE: perform NPF table lookup.
1704e592132Srmind *
1714e592132Srmind * A <- non-zero (true) if found and zero (false) otherwise
1724e592132Srmind */
1734e592132Srmind static uint32_t
npf_cop_table(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)174f9dc8d88Salnsn npf_cop_table(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
1754e592132Srmind {
176d0748eb9Srmind const npf_cache_t * const npc = (const npf_cache_t *)args->arg;
177f75d79ebSchristos npf_tableset_t *tblset = npf_config_tableset(npc->npc_ctx);
1784e592132Srmind const uint32_t tid = A & (SRC_FLAG_BIT - 1);
1794e592132Srmind const npf_addr_t *addr;
1801e7342c1Srmind npf_table_t *t;
1814e592132Srmind
1820def1972Srmind if (!npf_iscached(npc, NPC_IP46)) {
1830def1972Srmind return 0;
1840def1972Srmind }
1850def1972Srmind t = npf_tableset_getbyid(tblset, tid);
1860def1972Srmind if (__predict_false(!t)) {
1871e7342c1Srmind return 0;
1881e7342c1Srmind }
1898a8347bdSrmind addr = npc->npc_ips[(A & SRC_FLAG_BIT) ? NPF_SRC : NPF_DST];
1901e7342c1Srmind return npf_table_lookup(t, npc->npc_alen, addr) == 0;
1914e592132Srmind }
192