5 * Bart De Schuymer <bdschuym@pandora.be>
6 * Stephen Hemminger <shemminger@osdl.org>
11 #include <linux/netfilter_bridge/ebtables.h>
12 #include <linux/netfilter_bridge/ebt_stp.h>
13 #include <linux/module.h>
15 #define BPDU_TYPE_CONFIG 0
16 #define BPDU_TYPE_TCN 0x80
27 struct stp_config_pdu
{
35 uint8_t hello_time
[2];
36 uint8_t forward_delay
[2];
39 #define NR16(p) (p[0] << 8 | p[1])
40 #define NR32(p) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
42 static int ebt_filter_config(struct ebt_stp_info
*info
,
43 struct stp_config_pdu
*stpc
)
45 struct ebt_stp_config_info
*c
;
51 if ((info
->bitmask
& EBT_STP_FLAGS
) &&
52 FWINV(c
->flags
!= stpc
->flags
, EBT_STP_FLAGS
))
54 if (info
->bitmask
& EBT_STP_ROOTPRIO
) {
55 v16
= NR16(stpc
->root
);
56 if (FWINV(v16
< c
->root_priol
||
57 v16
> c
->root_priou
, EBT_STP_ROOTPRIO
))
60 if (info
->bitmask
& EBT_STP_ROOTADDR
) {
62 for (i
= 0; i
< 6; i
++)
63 verdict
|= (stpc
->root
[2+i
] ^ c
->root_addr
[i
]) &
65 if (FWINV(verdict
!= 0, EBT_STP_ROOTADDR
))
68 if (info
->bitmask
& EBT_STP_ROOTCOST
) {
69 v32
= NR32(stpc
->root_cost
);
70 if (FWINV(v32
< c
->root_costl
||
71 v32
> c
->root_costu
, EBT_STP_ROOTCOST
))
74 if (info
->bitmask
& EBT_STP_SENDERPRIO
) {
75 v16
= NR16(stpc
->sender
);
76 if (FWINV(v16
< c
->sender_priol
||
77 v16
> c
->sender_priou
, EBT_STP_SENDERPRIO
))
80 if (info
->bitmask
& EBT_STP_SENDERADDR
) {
82 for (i
= 0; i
< 6; i
++)
83 verdict
|= (stpc
->sender
[2+i
] ^ c
->sender_addr
[i
]) &
85 if (FWINV(verdict
!= 0, EBT_STP_SENDERADDR
))
88 if (info
->bitmask
& EBT_STP_PORT
) {
89 v16
= NR16(stpc
->port
);
90 if (FWINV(v16
< c
->portl
||
91 v16
> c
->portu
, EBT_STP_PORT
))
94 if (info
->bitmask
& EBT_STP_MSGAGE
) {
95 v16
= NR16(stpc
->msg_age
);
96 if (FWINV(v16
< c
->msg_agel
||
97 v16
> c
->msg_ageu
, EBT_STP_MSGAGE
))
100 if (info
->bitmask
& EBT_STP_MAXAGE
) {
101 v16
= NR16(stpc
->max_age
);
102 if (FWINV(v16
< c
->max_agel
||
103 v16
> c
->max_ageu
, EBT_STP_MAXAGE
))
106 if (info
->bitmask
& EBT_STP_HELLOTIME
) {
107 v16
= NR16(stpc
->hello_time
);
108 if (FWINV(v16
< c
->hello_timel
||
109 v16
> c
->hello_timeu
, EBT_STP_HELLOTIME
))
112 if (info
->bitmask
& EBT_STP_FWDD
) {
113 v16
= NR16(stpc
->forward_delay
);
114 if (FWINV(v16
< c
->forward_delayl
||
115 v16
> c
->forward_delayu
, EBT_STP_FWDD
))
121 static int ebt_filter_stp(const struct sk_buff
*skb
, const struct net_device
*in
,
122 const struct net_device
*out
, const void *data
, unsigned int datalen
)
124 struct ebt_stp_info
*info
= (struct ebt_stp_info
*)data
;
125 struct stp_header _stph
, *sp
;
126 uint8_t header
[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
128 sp
= skb_header_pointer(skb
, 0, sizeof(_stph
), &_stph
);
132 /* The stp code only considers these */
133 if (memcmp(sp
, header
, sizeof(header
)))
136 if (info
->bitmask
& EBT_STP_TYPE
137 && FWINV(info
->type
!= sp
->type
, EBT_STP_TYPE
))
140 if (sp
->type
== BPDU_TYPE_CONFIG
&&
141 info
->bitmask
& EBT_STP_CONFIG_MASK
) {
142 struct stp_config_pdu _stpc
, *st
;
144 st
= skb_header_pointer(skb
, sizeof(_stph
),
145 sizeof(_stpc
), &_stpc
);
148 return ebt_filter_config(info
, st
);
153 static int ebt_stp_check(const char *tablename
, unsigned int hookmask
,
154 const struct ebt_entry
*e
, void *data
, unsigned int datalen
)
156 struct ebt_stp_info
*info
= (struct ebt_stp_info
*)data
;
157 int len
= EBT_ALIGN(sizeof(struct ebt_stp_info
));
158 uint8_t bridge_ula
[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
159 uint8_t msk
[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
161 if (info
->bitmask
& ~EBT_STP_MASK
|| info
->invflags
& ~EBT_STP_MASK
||
162 !(info
->bitmask
& EBT_STP_MASK
))
166 /* Make sure the match only receives stp frames */
167 if (memcmp(e
->destmac
, bridge_ula
, ETH_ALEN
) ||
168 memcmp(e
->destmsk
, msk
, ETH_ALEN
) || !(e
->bitmask
& EBT_DESTMAC
))
174 static struct ebt_match filter_stp
=
176 .name
= EBT_STP_MATCH
,
177 .match
= ebt_filter_stp
,
178 .check
= ebt_stp_check
,
182 static int __init
init(void)
184 return ebt_register_match(&filter_stp
);
187 static void __exit
fini(void)
189 ebt_unregister_match(&filter_stp
);
194 MODULE_LICENSE("GPL");