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 18 void 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 27 static 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 32 static 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 46 static 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 90 err1: 91 nft_data_release(&priv->data, desc.type); 92 return err; 93 } 94 95 static 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 128 static 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 142 static 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 186 static 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); 225 break; 226 default: 227 break; 228 } 229 } 230 231 static 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 242 nla_put_failure: 243 return -1; 244 } 245 246 static int nft_immediate_validate(const struct nft_ctx *ctx, 247 const struct nft_expr *expr) 248 { 249 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 250 struct nft_ctx *pctx = (struct nft_ctx *)ctx; 251 const struct nft_data *data; 252 int err; 253 254 if (priv->dreg != NFT_REG_VERDICT) 255 return 0; 256 257 data = &priv->data; 258 259 switch (data->verdict.code) { 260 case NFT_JUMP: 261 case NFT_GOTO: 262 pctx->level++; 263 err = nft_chain_validate(ctx, data->verdict.chain); 264 if (err < 0) 265 return err; 266 pctx->level--; 267 break; 268 default: 269 break; 270 } 271 272 return 0; 273 } 274 275 static int nft_immediate_offload_verdict(struct nft_offload_ctx *ctx, 276 struct nft_flow_rule *flow, 277 const struct nft_immediate_expr *priv) 278 { 279 struct flow_action_entry *entry; 280 const struct nft_data *data; 281 282 entry = &flow->rule->action.entries[ctx->num_actions++]; 283 284 data = &priv->data; 285 switch (data->verdict.code) { 286 case NF_ACCEPT: 287 entry->id = FLOW_ACTION_ACCEPT; 288 break; 289 case NF_DROP: 290 entry->id = FLOW_ACTION_DROP; 291 break; 292 default: 293 return -EOPNOTSUPP; 294 } 295 296 return 0; 297 } 298 299 static int nft_immediate_offload(struct nft_offload_ctx *ctx, 300 struct nft_flow_rule *flow, 301 const struct nft_expr *expr) 302 { 303 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 304 305 if (priv->dreg == NFT_REG_VERDICT) 306 return nft_immediate_offload_verdict(ctx, flow, priv); 307 308 memcpy(&ctx->regs[priv->dreg].data, &priv->data, sizeof(priv->data)); 309 310 return 0; 311 } 312 313 static bool nft_immediate_offload_action(const struct nft_expr *expr) 314 { 315 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 316 317 if (priv->dreg == NFT_REG_VERDICT) 318 return true; 319 320 return false; 321 } 322 323 static bool nft_immediate_reduce(struct nft_regs_track *track, 324 const struct nft_expr *expr) 325 { 326 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 327 328 if (priv->dreg != NFT_REG_VERDICT) 329 nft_reg_track_cancel(track, priv->dreg, priv->dlen); 330 331 return false; 332 } 333 334 static const struct nft_expr_ops nft_imm_ops = { 335 .type = &nft_imm_type, 336 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), 337 .eval = nft_immediate_eval, 338 .init = nft_immediate_init, 339 .activate = nft_immediate_activate, 340 .deactivate = nft_immediate_deactivate, 341 .destroy = nft_immediate_destroy, 342 .dump = nft_immediate_dump, 343 .validate = nft_immediate_validate, 344 .reduce = nft_immediate_reduce, 345 .offload = nft_immediate_offload, 346 .offload_action = nft_immediate_offload_action, 347 }; 348 349 struct nft_expr_type nft_imm_type __read_mostly = { 350 .name = "immediate", 351 .ops = &nft_imm_ops, 352 .policy = nft_immediate_policy, 353 .maxattr = NFTA_IMMEDIATE_MAX, 354 .owner = THIS_MODULE, 355 }; 356