linux/net/bridge/netfilter/ebt_stp.c
<<
>>
Prefs
   1/*
   2 *  ebt_stp
   3 *
   4 *      Authors:
   5 *      Bart De Schuymer <bdschuym@pandora.be>
   6 *      Stephen Hemminger <shemminger@osdl.org>
   7 *
   8 *  July, 2003
   9 */
  10#include <linux/etherdevice.h>
  11#include <linux/module.h>
  12#include <linux/netfilter/x_tables.h>
  13#include <linux/netfilter_bridge/ebtables.h>
  14#include <linux/netfilter_bridge/ebt_stp.h>
  15
  16#define BPDU_TYPE_CONFIG 0
  17#define BPDU_TYPE_TCN 0x80
  18
  19struct stp_header {
  20        uint8_t dsap;
  21        uint8_t ssap;
  22        uint8_t ctrl;
  23        uint8_t pid;
  24        uint8_t vers;
  25        uint8_t type;
  26};
  27
  28struct stp_config_pdu {
  29        uint8_t flags;
  30        uint8_t root[8];
  31        uint8_t root_cost[4];
  32        uint8_t sender[8];
  33        uint8_t port[2];
  34        uint8_t msg_age[2];
  35        uint8_t max_age[2];
  36        uint8_t hello_time[2];
  37        uint8_t forward_delay[2];
  38};
  39
  40#define NR16(p) (p[0] << 8 | p[1])
  41#define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
  42
  43static bool ebt_filter_config(const struct ebt_stp_info *info,
  44   const struct stp_config_pdu *stpc)
  45{
  46        const struct ebt_stp_config_info *c;
  47        uint16_t v16;
  48        uint32_t v32;
  49        int verdict, i;
  50
  51        c = &info->config;
  52        if ((info->bitmask & EBT_STP_FLAGS) &&
  53            FWINV(c->flags != stpc->flags, EBT_STP_FLAGS))
  54                return false;
  55        if (info->bitmask & EBT_STP_ROOTPRIO) {
  56                v16 = NR16(stpc->root);
  57                if (FWINV(v16 < c->root_priol ||
  58                    v16 > c->root_priou, EBT_STP_ROOTPRIO))
  59                        return false;
  60        }
  61        if (info->bitmask & EBT_STP_ROOTADDR) {
  62                verdict = 0;
  63                for (i = 0; i < 6; i++)
  64                        verdict |= (stpc->root[2+i] ^ c->root_addr[i]) &
  65                                   c->root_addrmsk[i];
  66                if (FWINV(verdict != 0, EBT_STP_ROOTADDR))
  67                        return false;
  68        }
  69        if (info->bitmask & EBT_STP_ROOTCOST) {
  70                v32 = NR32(stpc->root_cost);
  71                if (FWINV(v32 < c->root_costl ||
  72                    v32 > c->root_costu, EBT_STP_ROOTCOST))
  73                        return false;
  74        }
  75        if (info->bitmask & EBT_STP_SENDERPRIO) {
  76                v16 = NR16(stpc->sender);
  77                if (FWINV(v16 < c->sender_priol ||
  78                    v16 > c->sender_priou, EBT_STP_SENDERPRIO))
  79                        return false;
  80        }
  81        if (info->bitmask & EBT_STP_SENDERADDR) {
  82                verdict = 0;
  83                for (i = 0; i < 6; i++)
  84                        verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) &
  85                                   c->sender_addrmsk[i];
  86                if (FWINV(verdict != 0, EBT_STP_SENDERADDR))
  87                        return false;
  88        }
  89        if (info->bitmask & EBT_STP_PORT) {
  90                v16 = NR16(stpc->port);
  91                if (FWINV(v16 < c->portl ||
  92                    v16 > c->portu, EBT_STP_PORT))
  93                        return false;
  94        }
  95        if (info->bitmask & EBT_STP_MSGAGE) {
  96                v16 = NR16(stpc->msg_age);
  97                if (FWINV(v16 < c->msg_agel ||
  98                    v16 > c->msg_ageu, EBT_STP_MSGAGE))
  99                        return false;
 100        }
 101        if (info->bitmask & EBT_STP_MAXAGE) {
 102                v16 = NR16(stpc->max_age);
 103                if (FWINV(v16 < c->max_agel ||
 104                    v16 > c->max_ageu, EBT_STP_MAXAGE))
 105                        return false;
 106        }
 107        if (info->bitmask & EBT_STP_HELLOTIME) {
 108                v16 = NR16(stpc->hello_time);
 109                if (FWINV(v16 < c->hello_timel ||
 110                    v16 > c->hello_timeu, EBT_STP_HELLOTIME))
 111                        return false;
 112        }
 113        if (info->bitmask & EBT_STP_FWDD) {
 114                v16 = NR16(stpc->forward_delay);
 115                if (FWINV(v16 < c->forward_delayl ||
 116                    v16 > c->forward_delayu, EBT_STP_FWDD))
 117                        return false;
 118        }
 119        return true;
 120}
 121
 122static bool
 123ebt_stp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
 124{
 125        const struct ebt_stp_info *info = par->matchinfo;
 126        const struct stp_header *sp;
 127        struct stp_header _stph;
 128        const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
 129
 130        sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
 131        if (sp == NULL)
 132                return false;
 133
 134        /* The stp code only considers these */
 135        if (memcmp(sp, header, sizeof(header)))
 136                return false;
 137
 138        if (info->bitmask & EBT_STP_TYPE
 139            && FWINV(info->type != sp->type, EBT_STP_TYPE))
 140                return false;
 141
 142        if (sp->type == BPDU_TYPE_CONFIG &&
 143            info->bitmask & EBT_STP_CONFIG_MASK) {
 144                const struct stp_config_pdu *st;
 145                struct stp_config_pdu _stpc;
 146
 147                st = skb_header_pointer(skb, sizeof(_stph),
 148                                        sizeof(_stpc), &_stpc);
 149                if (st == NULL)
 150                        return false;
 151                return ebt_filter_config(info, st);
 152        }
 153        return true;
 154}
 155
 156static bool ebt_stp_mt_check(const struct xt_mtchk_param *par)
 157{
 158        const struct ebt_stp_info *info = par->matchinfo;
 159        const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
 160        const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 161        const struct ebt_entry *e = par->entryinfo;
 162
 163        if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
 164            !(info->bitmask & EBT_STP_MASK))
 165                return false;
 166        /* Make sure the match only receives stp frames */
 167        if (compare_ether_addr(e->destmac, bridge_ula) ||
 168            compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC))
 169                return false;
 170
 171        return true;
 172}
 173
 174static struct xt_match ebt_stp_mt_reg __read_mostly = {
 175        .name           = "stp",
 176        .revision       = 0,
 177        .family         = NFPROTO_BRIDGE,
 178        .match          = ebt_stp_mt,
 179        .checkentry     = ebt_stp_mt_check,
 180        .matchsize      = XT_ALIGN(sizeof(struct ebt_stp_info)),
 181        .me             = THIS_MODULE,
 182};
 183
 184static int __init ebt_stp_init(void)
 185{
 186        return xt_register_match(&ebt_stp_mt_reg);
 187}
 188
 189static void __exit ebt_stp_fini(void)
 190{
 191        xt_unregister_match(&ebt_stp_mt_reg);
 192}
 193
 194module_init(ebt_stp_init);
 195module_exit(ebt_stp_fini);
 196MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match");
 197MODULE_LICENSE("GPL");
 198