~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to net/bridge/netfilter/ebt_stp.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
19
struct 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
 
 
28
struct 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
 
 
43
static 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
 
 
122
static bool
 
123
ebt_stp_mt(const struct sk_buff *skb, struct xt_action_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
 
 
156
static int 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 -EINVAL;
 
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 -EINVAL;
 
170
 
 
171
        return 0;
 
172
}
 
173
 
 
174
static 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      = sizeof(struct ebt_stp_info),
 
181
        .me             = THIS_MODULE,
 
182
};
 
183
 
 
184
static int __init ebt_stp_init(void)
 
185
{
 
186
        return xt_register_match(&ebt_stp_mt_reg);
 
187
}
 
188
 
 
189
static void __exit ebt_stp_fini(void)
 
190
{
 
191
        xt_unregister_match(&ebt_stp_mt_reg);
 
192
}
 
193
 
 
194
module_init(ebt_stp_init);
 
195
module_exit(ebt_stp_fini);
 
196
MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match");
 
197
MODULE_LICENSE("GPL");