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 if (nft_chain_is_bound(chain)) { 80 err = -EBUSY; 81 goto err1; 82 } 83 chain->bound = true; 84 break; 85 default: 86 break; 87 } 88 } 89 90 return 0; 91 92 err1: 93 nft_data_release(&priv->data, desc.type); 94 return err; 95 } 96 97 static void nft_immediate_activate(const struct nft_ctx *ctx, 98 const struct nft_expr *expr) 99 { 100 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 101 102 return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); 103 } 104 105 static void nft_immediate_deactivate(const struct nft_ctx *ctx, 106 const struct nft_expr *expr, 107 enum nft_trans_phase phase) 108 { 109 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 110 111 if (phase == NFT_TRANS_COMMIT) 112 return; 113 114 return nft_data_release(&priv->data, nft_dreg_to_type(priv->dreg)); 115 } 116 117 static void nft_immediate_destroy(const struct nft_ctx *ctx, 118 const struct nft_expr *expr) 119 { 120 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 121 const struct nft_data *data = &priv->data; 122 struct nft_rule *rule, *n; 123 struct nft_ctx chain_ctx; 124 struct nft_chain *chain; 125 126 if (priv->dreg != NFT_REG_VERDICT) 127 return; 128 129 switch (data->verdict.code) { 130 case NFT_JUMP: 131 case NFT_GOTO: 132 chain = data->verdict.chain; 133 134 if (!nft_chain_is_bound(chain)) 135 break; 136 137 chain_ctx = *ctx; 138 chain_ctx.chain = chain; 139 140 list_for_each_entry_safe(rule, n, &chain->rules, list) 141 nf_tables_rule_release(&chain_ctx, rule); 142 143 nf_tables_chain_destroy(&chain_ctx); 144 break; 145 default: 146 break; 147 } 148 } 149 150 static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr) 151 { 152 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 153 154 if (nft_dump_register(skb, NFTA_IMMEDIATE_DREG, priv->dreg)) 155 goto nla_put_failure; 156 157 return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data, 158 nft_dreg_to_type(priv->dreg), priv->dlen); 159 160 nla_put_failure: 161 return -1; 162 } 163 164 static int nft_immediate_validate(const struct nft_ctx *ctx, 165 const struct nft_expr *expr, 166 const struct nft_data **d) 167 { 168 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 169 struct nft_ctx *pctx = (struct nft_ctx *)ctx; 170 const struct nft_data *data; 171 int err; 172 173 if (priv->dreg != NFT_REG_VERDICT) 174 return 0; 175 176 data = &priv->data; 177 178 switch (data->verdict.code) { 179 case NFT_JUMP: 180 case NFT_GOTO: 181 pctx->level++; 182 err = nft_chain_validate(ctx, data->verdict.chain); 183 if (err < 0) 184 return err; 185 pctx->level--; 186 break; 187 default: 188 break; 189 } 190 191 return 0; 192 } 193 194 static int nft_immediate_offload_verdict(struct nft_offload_ctx *ctx, 195 struct nft_flow_rule *flow, 196 const struct nft_immediate_expr *priv) 197 { 198 struct flow_action_entry *entry; 199 const struct nft_data *data; 200 201 entry = &flow->rule->action.entries[ctx->num_actions++]; 202 203 data = &priv->data; 204 switch (data->verdict.code) { 205 case NF_ACCEPT: 206 entry->id = FLOW_ACTION_ACCEPT; 207 break; 208 case NF_DROP: 209 entry->id = FLOW_ACTION_DROP; 210 break; 211 default: 212 return -EOPNOTSUPP; 213 } 214 215 return 0; 216 } 217 218 static int nft_immediate_offload(struct nft_offload_ctx *ctx, 219 struct nft_flow_rule *flow, 220 const struct nft_expr *expr) 221 { 222 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 223 224 if (priv->dreg == NFT_REG_VERDICT) 225 return nft_immediate_offload_verdict(ctx, flow, priv); 226 227 memcpy(&ctx->regs[priv->dreg].data, &priv->data, sizeof(priv->data)); 228 229 return 0; 230 } 231 232 static bool nft_immediate_offload_action(const struct nft_expr *expr) 233 { 234 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 235 236 if (priv->dreg == NFT_REG_VERDICT) 237 return true; 238 239 return false; 240 } 241 242 static bool nft_immediate_reduce(struct nft_regs_track *track, 243 const struct nft_expr *expr) 244 { 245 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 246 247 if (priv->dreg != NFT_REG_VERDICT) 248 nft_reg_track_cancel(track, priv->dreg, priv->dlen); 249 250 return false; 251 } 252 253 static const struct nft_expr_ops nft_imm_ops = { 254 .type = &nft_imm_type, 255 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), 256 .eval = nft_immediate_eval, 257 .init = nft_immediate_init, 258 .activate = nft_immediate_activate, 259 .deactivate = nft_immediate_deactivate, 260 .destroy = nft_immediate_destroy, 261 .dump = nft_immediate_dump, 262 .validate = nft_immediate_validate, 263 .reduce = nft_immediate_reduce, 264 .offload = nft_immediate_offload, 265 .offload_action = nft_immediate_offload_action, 266 }; 267 268 struct nft_expr_type nft_imm_type __read_mostly = { 269 .name = "immediate", 270 .ops = &nft_imm_ops, 271 .policy = nft_immediate_policy, 272 .maxattr = NFTA_IMMEDIATE_MAX, 273 .owner = THIS_MODULE, 274 }; 275