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 21 static void nft_meta_bridge_get_eval(const struct nft_expr *expr, 22 struct nft_regs *regs, 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 u32 *dest = ®s->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, p->br->dev->name, IFNAMSIZ); 44 return; 45 out: 46 return nft_meta_get_eval(expr, regs, pkt); 47 err: 48 regs->verdict.code = NFT_BREAK; 49 } 50 51 static 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 unsigned int len; 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 len = IFNAMSIZ; 63 break; 64 default: 65 return nft_meta_get_init(ctx, expr, tb); 66 } 67 68 priv->dreg = nft_parse_register(tb[NFTA_META_DREG]); 69 return nft_validate_register_store(ctx, priv->dreg, NULL, 70 NFT_DATA_VALUE, len); 71 } 72 73 static struct nft_expr_type nft_meta_bridge_type; 74 static const struct nft_expr_ops nft_meta_bridge_get_ops = { 75 .type = &nft_meta_bridge_type, 76 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 77 .eval = nft_meta_bridge_get_eval, 78 .init = nft_meta_bridge_get_init, 79 .dump = nft_meta_get_dump, 80 }; 81 82 static const struct nft_expr_ops nft_meta_bridge_set_ops = { 83 .type = &nft_meta_bridge_type, 84 .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), 85 .eval = nft_meta_set_eval, 86 .init = nft_meta_set_init, 87 .destroy = nft_meta_set_destroy, 88 .dump = nft_meta_set_dump, 89 }; 90 91 static const struct nft_expr_ops * 92 nft_meta_bridge_select_ops(const struct nft_ctx *ctx, 93 const struct nlattr * const tb[]) 94 { 95 if (tb[NFTA_META_KEY] == NULL) 96 return ERR_PTR(-EINVAL); 97 98 if (tb[NFTA_META_DREG] && tb[NFTA_META_SREG]) 99 return ERR_PTR(-EINVAL); 100 101 if (tb[NFTA_META_DREG]) 102 return &nft_meta_bridge_get_ops; 103 104 if (tb[NFTA_META_SREG]) 105 return &nft_meta_bridge_set_ops; 106 107 return ERR_PTR(-EINVAL); 108 } 109 110 static struct nft_expr_type nft_meta_bridge_type __read_mostly = { 111 .family = NFPROTO_BRIDGE, 112 .name = "meta", 113 .select_ops = &nft_meta_bridge_select_ops, 114 .policy = nft_meta_policy, 115 .maxattr = NFTA_META_MAX, 116 .owner = THIS_MODULE, 117 }; 118 119 static int __init nft_meta_bridge_module_init(void) 120 { 121 return nft_register_expr(&nft_meta_bridge_type); 122 } 123 124 static void __exit nft_meta_bridge_module_exit(void) 125 { 126 nft_unregister_expr(&nft_meta_bridge_type); 127 } 128 129 module_init(nft_meta_bridge_module_init); 130 module_exit(nft_meta_bridge_module_exit); 131 132 MODULE_LICENSE("GPL"); 133 MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>"); 134 MODULE_ALIAS_NFT_AF_EXPR(AF_BRIDGE, "meta"); 135