5 * Bart De Schuymer <bdschuym@pandora.be>
6 * Stephen Hemminger <shemminger@osdl.org>
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>
16 #define BPDU_TYPE_CONFIG 0
17 #define BPDU_TYPE_TCN 0x80
28 struct stp_config_pdu
{
36 uint8_t hello_time
[2];
37 uint8_t forward_delay
[2];
40 #define NR16(p) (p[0] << 8 | p[1])
41 #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
43 static bool ebt_filter_config(const struct ebt_stp_info
*info
,
44 const struct stp_config_pdu
*stpc
)
46 const struct ebt_stp_config_info
*c
;
52 if ((info
->bitmask
& EBT_STP_FLAGS
) &&
53 FWINV(c
->flags
!= stpc
->flags
, EBT_STP_FLAGS
))
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
))
61 if (info
->bitmask
& EBT_STP_ROOTADDR
) {
63 for (i
= 0; i
< 6; i
++)
64 verdict
|= (stpc
->root
[2+i
] ^ c
->root_addr
[i
]) &
66 if (FWINV(verdict
!= 0, EBT_STP_ROOTADDR
))
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
))
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
))
81 if (info
->bitmask
& EBT_STP_SENDERADDR
) {
83 for (i
= 0; i
< 6; i
++)
84 verdict
|= (stpc
->sender
[2+i
] ^ c
->sender_addr
[i
]) &
86 if (FWINV(verdict
!= 0, EBT_STP_SENDERADDR
))
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
))
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
))
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
))
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
))
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
))
123 ebt_stp_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
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};
130 sp
= skb_header_pointer(skb
, 0, sizeof(_stph
), &_stph
);
134 /* The stp code only considers these */
135 if (memcmp(sp
, header
, sizeof(header
)))
138 if (info
->bitmask
& EBT_STP_TYPE
&&
139 FWINV(info
->type
!= sp
->type
, EBT_STP_TYPE
))
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
;
147 st
= skb_header_pointer(skb
, sizeof(_stph
),
148 sizeof(_stpc
), &_stpc
);
151 return ebt_filter_config(info
, st
);
156 static int ebt_stp_mt_check(const struct xt_mtchk_param
*par
)
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
;
163 if (info
->bitmask
& ~EBT_STP_MASK
|| info
->invflags
& ~EBT_STP_MASK
||
164 !(info
->bitmask
& EBT_STP_MASK
))
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
))
174 static struct xt_match ebt_stp_mt_reg __read_mostly
= {
177 .family
= NFPROTO_BRIDGE
,
179 .checkentry
= ebt_stp_mt_check
,
180 .matchsize
= sizeof(struct ebt_stp_info
),
184 static int __init
ebt_stp_init(void)
186 return xt_register_match(&ebt_stp_mt_reg
);
189 static void __exit
ebt_stp_fini(void)
191 xt_unregister_match(&ebt_stp_mt_reg
);
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");