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, 151 const struct nft_expr *expr, bool reset) 152 { 153 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 154 155 if (nft_dump_register(skb, NFTA_IMMEDIATE_DREG, priv->dreg)) 156 goto nla_put_failure; 157 158 return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data, 159 nft_dreg_to_type(priv->dreg), priv->dlen); 160 161 nla_put_failure: 162 return -1; 163 } 164 165 static int nft_immediate_validate(const struct nft_ctx *ctx, 166 const struct nft_expr *expr, 167 const struct nft_data **d) 168 { 169 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 170 struct nft_ctx *pctx = (struct nft_ctx *)ctx; 171 const struct nft_data *data; 172 int err; 173 174 if (priv->dreg != NFT_REG_VERDICT) 175 return 0; 176 177 data = &priv->data; 178 179 switch (data->verdict.code) { 180 case NFT_JUMP: 181 case NFT_GOTO: 182 pctx->level++; 183 err = nft_chain_validate(ctx, data->verdict.chain); 184 if (err < 0) 185 return err; 186 pctx->level--; 187 break; 188 default: 189 break; 190 } 191 192 return 0; 193 } 194 195 static int nft_immediate_offload_verdict(struct nft_offload_ctx *ctx, 196 struct nft_flow_rule *flow, 197 const struct nft_immediate_expr *priv) 198 { 199 struct flow_action_entry *entry; 200 const struct nft_data *data; 201 202 entry = &flow->rule->action.entries[ctx->num_actions++]; 203 204 data = &priv->data; 205 switch (data->verdict.code) { 206 case NF_ACCEPT: 207 entry->id = FLOW_ACTION_ACCEPT; 208 break; 209 case NF_DROP: 210 entry->id = FLOW_ACTION_DROP; 211 break; 212 default: 213 return -EOPNOTSUPP; 214 } 215 216 return 0; 217 } 218 219 static int nft_immediate_offload(struct nft_offload_ctx *ctx, 220 struct nft_flow_rule *flow, 221 const struct nft_expr *expr) 222 { 223 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 224 225 if (priv->dreg == NFT_REG_VERDICT) 226 return nft_immediate_offload_verdict(ctx, flow, priv); 227 228 memcpy(&ctx->regs[priv->dreg].data, &priv->data, sizeof(priv->data)); 229 230 return 0; 231 } 232 233 static bool nft_immediate_offload_action(const struct nft_expr *expr) 234 { 235 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 236 237 if (priv->dreg == NFT_REG_VERDICT) 238 return true; 239 240 return false; 241 } 242 243 static bool nft_immediate_reduce(struct nft_regs_track *track, 244 const struct nft_expr *expr) 245 { 246 const struct nft_immediate_expr *priv = nft_expr_priv(expr); 247 248 if (priv->dreg != NFT_REG_VERDICT) 249 nft_reg_track_cancel(track, priv->dreg, priv->dlen); 250 251 return false; 252 } 253 254 static const struct nft_expr_ops nft_imm_ops = { 255 .type = &nft_imm_type, 256 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), 257 .eval = nft_immediate_eval, 258 .init = nft_immediate_init, 259 .activate = nft_immediate_activate, 260 .deactivate = nft_immediate_deactivate, 261 .destroy = nft_immediate_destroy, 262 .dump = nft_immediate_dump, 263 .validate = nft_immediate_validate, 264 .reduce = nft_immediate_reduce, 265 .offload = nft_immediate_offload, 266 .offload_action = nft_immediate_offload_action, 267 }; 268 269 struct nft_expr_type nft_imm_type __read_mostly = { 270 .name = "immediate", 271 .ops = &nft_imm_ops, 272 .policy = nft_immediate_policy, 273 .maxattr = NFTA_IMMEDIATE_MAX, 274 .owner = THIS_MODULE, 275 }; 276