1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net> 4 * 5 * Development of this code funded by Astaro AG (http://www.astaro.com/) 6 */ 7 8#include <linux/kernel.h> 9#include <linux/init.h> 10#include <linux/module.h> 11#include <linux/netlink.h> 12#include <linux/netfilter.h> 13#include <linux/netfilter/nf_tables.h> 14#include <net/netfilter/nf_tables_core.h> 15#include <net/netfilter/nf_tables.h> 16#include <net/netfilter/nf_tables_offload.h> 17 18void nft_immediate_eval(const struct nft_expr *expr, 19 struct nft_regs *regs, 20 const struct nft_pktinfo *pkt) 21{ 22 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 23 24 nft_data_copy(®s->data[priv->dreg], &priv->data, priv->dlen); 25} 26 27static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = { 28 [NFTA_IMMEDIATE_DREG] = { .type = NLA_U32 }, 29 [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED }, 30}; 31 32static enum nft_data_types nft_reg_to_type(const struct nlattr *nla) 33{ 34 enum nft_data_types type; 35 u8 reg; 36 37 reg = ntohl(nla_get_be32(nla)); 38 if (reg == NFT_REG_VERDICT) 39 type = NFT_DATA_VERDICT; 40 else 41 type = NFT_DATA_VALUE; 42 43 return type; 44} 45 46static int nft_immediate_init(const struct nft_ctx *ctx, 47 const struct nft_expr *expr, 48 const struct nlattr * const tb[]) 49{ 50 struct nft_immediate_expr *priv = nft_expr_priv(expr); 51 struct nft_data_desc desc = { 52 .size = sizeof(priv->data), 53 }; 54 int err; 55 56 if (tb[NFTA_IMMEDIATE_DREG] == NULL || 57 tb[NFTA_IMMEDIATE_DATA] == NULL) 58 return -EINVAL; 59 60 desc.type = nft_reg_to_type(tb[NFTA_IMMEDIATE_DREG]); 61 err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]); 62 if (err < 0) 63 return err; 64 65 priv->dlen = desc.len; 66 67 err = nft_parse_register_store(ctx, tb[NFTA_IMMEDIATE_DREG], 68 &priv->dreg, &priv->data, desc.type, 69 desc.len); 70 if (err < 0) 71 goto err1; 72 73 if (priv->dreg == NFT_REG_VERDICT) { 74 struct nft_chain *chain = priv->data.verdict.chain; 75 76 switch (priv->data.verdict.code) { 77 case NFT_JUMP: 78 case NFT_GOTO: 79 err = nf_tables_bind_chain(ctx, chain); 80 if (err < 0) 81 goto err1; 82 break; 83 default: 84 break; 85 } 86 } 87 88 return 0; 89 90err1: 91 nft_data_release(&priv->data, desc.type); 92 return err; 93} 94 95static void nft_immediate_activate(const struct nft_ctx *ctx, 96 const struct nft_expr *expr) 97{ 98 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 99 const struct nft_data *data = &priv->data; 100 struct nft_ctx chain_ctx; 101 struct nft_chain *chain; 102 struct nft_rule *rule; 103 104 if (priv->dreg == NFT_REG_VERDICT) { 105 switch (data->verdict.code) { 106 case NFT_JUMP: 107 case NFT_GOTO: 108 chain = data->verdict.chain; 109 if (!nft_chain_binding(chain)) 110 break; 111 112 chain_ctx = *ctx; 113 chain_ctx.chain = chain; 114 115 list_for_each_entry(rule, &chain->rules, list) 116 nft_rule_expr_activate(&chain_ctx, rule); 117 118 nft_clear(ctx->net, chain); 119 break; 120 default: 121 break; 122 } 123 } 124 125 return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); 126} 127 128static void nft_immediate_chain_deactivate(const struct nft_ctx *ctx, 129 struct nft_chain *chain, 130 enum nft_trans_phase phase) 131{ 132 struct nft_ctx chain_ctx; 133 struct nft_rule *rule; 134 135 chain_ctx = *ctx; 136 chain_ctx.chain = chain; 137 138 list_for_each_entry(rule, &chain->rules, list) 139 nft_rule_expr_deactivate(&chain_ctx, rule, phase); 140} 141 142static void nft_immediate_deactivate(const struct nft_ctx *ctx, 143 const struct nft_expr *expr, 144 enum nft_trans_phase phase) 145{ 146 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 147 const struct nft_data *data = &priv->data; 148 struct nft_chain *chain; 149 150 if (priv->dreg == NFT_REG_VERDICT) { 151 switch (data->verdict.code) { 152 case NFT_JUMP: 153 case NFT_GOTO: 154 chain = data->verdict.chain; 155 if (!nft_chain_binding(chain)) 156 break; 157 158 switch (phase) { 159 case NFT_TRANS_PREPARE_ERROR: 160 nf_tables_unbind_chain(ctx, chain); 161 nft_deactivate_next(ctx->net, chain); 162 break; 163 case NFT_TRANS_PREPARE: 164 nft_immediate_chain_deactivate(ctx, chain, phase); 165 nft_deactivate_next(ctx->net, chain); 166 break; 167 default: 168 nft_immediate_chain_deactivate(ctx, chain, phase); 169 nft_chain_del(chain); 170 chain->bound = false; 171 nft_use_dec(&chain->table->use); 172 break; 173 } 174 break; 175 default: 176 break; 177 } 178 } 179 180 if (phase == NFT_TRANS_COMMIT) 181 return; 182 183 return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg)); 184} 185 186static void nft_immediate_destroy(const struct nft_ctx *ctx, 187 const struct nft_expr *expr) 188{ 189 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 190 const struct nft_data *data = &priv->data; 191 struct nft_rule *rule, *n; 192 struct nft_ctx chain_ctx; 193 struct nft_chain *chain; 194 195 if (priv->dreg != NFT_REG_VERDICT) 196 return; 197 198 switch (data->verdict.code) { 199 case NFT_JUMP: 200 case NFT_GOTO: 201 chain = data->verdict.chain; 202 203 if (!nft_chain_binding(chain)) 204 break; 205 206 /* Rule construction failed, but chain is already bound: 207 * let the transaction records release this chain and its rules. 208 */ 209 if (chain->bound) { 210 nft_use_dec(&chain->use); 211 break; 212 } 213 214 /* Rule has been deleted, release chain and its rules. */ 215 chain_ctx = *ctx; 216 chain_ctx.chain = chain; 217 218 nft_use_dec(&chain->use); 219 list_for_each_entry_safe(rule, n, &chain->rules, list) { 220 nft_use_dec(&chain->use); 221 list_del(&rule->list); 222 nf_tables_rule_destroy(&chain_ctx, rule); 223 } 224 nf_tables_chain_destroy(&chain_ctx); 225 break; 226 default: 227 break; 228 } 229} 230 231static int nft_immediate_dump(struct sk_buff *skb, 232 const struct nft_expr *expr, bool reset) 233{ 234 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 235 236 if (nft_dump_register(skb, NFTA_IMMEDIATE_DREG, priv->dreg)) 237 goto nla_put_failure; 238 239 return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data, 240 nft_dreg_to_type(priv->dreg), priv->dlen); 241 242nla_put_failure: 243 return -1; 244} 245 246static int nft_immediate_validate(const struct nft_ctx *ctx, 247 const struct nft_expr *expr, 248 const struct nft_data **d) 249{ 250 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 251 struct nft_ctx *pctx = (struct nft_ctx *)ctx; 252 const struct nft_data *data; 253 int err; 254 255 if (priv->dreg != NFT_REG_VERDICT) 256 return 0; 257 258 data = &priv->data; 259 260 switch (data->verdict.code) { 261 case NFT_JUMP: 262 case NFT_GOTO: 263 pctx->level++; 264 err = nft_chain_validate(ctx, data->verdict.chain); 265 if (err < 0) 266 return err; 267 pctx->level--; 268 break; 269 default: 270 break; 271 } 272 273 return 0; 274} 275 276static int nft_immediate_offload_verdict(struct nft_offload_ctx *ctx, 277 struct nft_flow_rule *flow, 278 const struct nft_immediate_expr *priv) 279{ 280 struct flow_action_entry *entry; 281 const struct nft_data *data; 282 283 entry = &flow->rule->action.entries[ctx->num_actions++]; 284 285 data = &priv->data; 286 switch (data->verdict.code) { 287 case NF_ACCEPT: 288 entry->id = FLOW_ACTION_ACCEPT; 289 break; 290 case NF_DROP: 291 entry->id = FLOW_ACTION_DROP; 292 break; 293 default: 294 return -EOPNOTSUPP; 295 } 296 297 return 0; 298} 299 300static int nft_immediate_offload(struct nft_offload_ctx *ctx, 301 struct nft_flow_rule *flow, 302 const struct nft_expr *expr) 303{ 304 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 305 306 if (priv->dreg == NFT_REG_VERDICT) 307 return nft_immediate_offload_verdict(ctx, flow, priv); 308 309 memcpy(&ctx->regs[priv->dreg].data, &priv->data, sizeof(priv->data)); 310 311 return 0; 312} 313 314static bool nft_immediate_offload_action(const struct nft_expr *expr) 315{ 316 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 317 318 if (priv->dreg == NFT_REG_VERDICT) 319 return true; 320 321 return false; 322} 323 324static bool nft_immediate_reduce(struct nft_regs_track *track, 325 const struct nft_expr *expr) 326{ 327 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 328 329 if (priv->dreg != NFT_REG_VERDICT) 330 nft_reg_track_cancel(track, priv->dreg, priv->dlen); 331 332 return false; 333} 334 335static const struct nft_expr_ops nft_imm_ops = { 336 .type = &nft_imm_type, 337 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), 338 .eval = nft_immediate_eval, 339 .init = nft_immediate_init, 340 .activate = nft_immediate_activate, 341 .deactivate = nft_immediate_deactivate, 342 .destroy = nft_immediate_destroy, 343 .dump = nft_immediate_dump, 344 .validate = nft_immediate_validate, 345 .reduce = nft_immediate_reduce, 346 .offload = nft_immediate_offload, 347 .offload_action = nft_immediate_offload_action, 348}; 349 350struct nft_expr_type nft_imm_type __read_mostly = { 351 .name = "immediate", 352 .ops = &nft_imm_ops, 353 .policy = nft_immediate_policy, 354 .maxattr = NFTA_IMMEDIATE_MAX, 355 .owner = THIS_MODULE, 356}; 357