1/* 2 * Copyright (c) 2014 Intel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 * 8 */ 9 10#include <linux/kernel.h> 11#include <linux/init.h> 12#include <linux/module.h> 13#include <linux/netlink.h> 14#include <linux/netfilter.h> 15#include <linux/netfilter/nf_tables.h> 16#include <net/netfilter/nf_tables.h> 17#include <net/netfilter/nft_meta.h> 18 19#include "../br_private.h" 20 21static void nft_meta_bridge_get_eval(const struct nft_expr *expr, 22 struct nft_data data[NFT_REG_MAX + 1], 23 const struct nft_pktinfo *pkt) 24{ 25 const struct nft_meta *priv = nft_expr_priv(expr); 26 const struct net_device *in = pkt->in, *out = pkt->out; 27 struct nft_data *dest = &data[priv->dreg]; 28 const struct net_bridge_port *p; 29 30 switch (priv->key) { 31 case NFT_META_BRI_IIFNAME: 32 if (in == NULL || (p = br_port_get_rcu(in)) == NULL) 33 goto err; 34 break; 35 case NFT_META_BRI_OIFNAME: 36 if (out == NULL || (p = br_port_get_rcu(out)) == NULL) 37 goto err; 38 break; 39 default: 40 goto out; 41 } 42 43 strncpy((char *)dest->data, p->br->dev->name, sizeof(dest->data)); 44 return; 45out: 46 return nft_meta_get_eval(expr, data, pkt); 47err: 48 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 49} 50 51static int nft_meta_bridge_get_init(const struct nft_ctx *ctx, 52 const struct nft_expr *expr, 53 const struct nlattr * const tb[]) 54{ 55 struct nft_meta *priv = nft_expr_priv(expr); 56 int err; 57 58 priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); 59 switch (priv->key) { 60 case NFT_META_BRI_IIFNAME: 61 case NFT_META_BRI_OIFNAME: 62 break; 63 default: 64 return nft_meta_get_init(ctx, expr, tb); 65 } 66 67 priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); 68 err = nft_validate_output_register(priv->dreg); 69 if (err < 0) 70 return err; 71 72 err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE); 73 if (err < 0) 74 return err; 75 76 return 0; 77} 78 79static struct nft_expr_type nft_meta_bridge_type; 80static const struct nft_expr_ops nft_meta_bridge_get_ops = { 81 .type = &nft_meta_bridge_type, 82 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 83 .eval = nft_meta_bridge_get_eval, 84 .init = nft_meta_bridge_get_init, 85 .dump = nft_meta_get_dump, 86}; 87 88static const struct nft_expr_ops nft_meta_bridge_set_ops = { 89 .type = &nft_meta_bridge_type, 90 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 91 .eval = nft_meta_set_eval, 92 .init = nft_meta_set_init, 93 .dump = nft_meta_set_dump, 94}; 95 96static const struct nft_expr_ops * 97nft_meta_bridge_select_ops(const struct nft_ctx *ctx, 98 const struct nlattr * const tb[]) 99{ 100 if (tb[NFTA_META_KEY] == NULL) 101 return ERR_PTR(-EINVAL); 102 103 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 104 return ERR_PTR(-EINVAL); 105 106 if (tb[NFTA_META_DREG]) 107 return &nft_meta_bridge_get_ops; 108 109 if (tb[NFTA_META_SREG]) 110 return &nft_meta_bridge_set_ops; 111 112 return ERR_PTR(-EINVAL); 113} 114 115static struct nft_expr_type nft_meta_bridge_type __read_mostly = { 116 .family = NFPROTO_BRIDGE, 117 .name = "meta", 118 .select_ops = &nft_meta_bridge_select_ops, 119 .policy = nft_meta_policy, 120 .maxattr = NFTA_META_MAX, 121 .owner = THIS_MODULE, 122}; 123 124static int __init nft_meta_bridge_module_init(void) 125{ 126 return nft_register_expr(&nft_meta_bridge_type); 127} 128 129static void __exit nft_meta_bridge_module_exit(void) 130{ 131 nft_unregister_expr(&nft_meta_bridge_type); 132} 133 134module_init(nft_meta_bridge_module_init); 135module_exit(nft_meta_bridge_module_exit); 136 137MODULE_LICENSE("GPL"); 138MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>"); 139MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "meta"); 140