1 // SPDX-License-Identifier: GPL-2.0-only
6 * Bart De Schuymer <bdschuym@pandora.be>
7 * Stephen Hemminger <shemminger@osdl.org>
11 #include <linux/etherdevice.h>
12 #include <linux/module.h>
13 #include <linux/netfilter/x_tables.h>
14 #include <linux/netfilter_bridge/ebtables.h>
15 #include <linux/netfilter_bridge/ebt_stp.h>
17 #define BPDU_TYPE_CONFIG 0
28 struct stp_config_pdu
{
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
;
51 if ((info
->bitmask
& EBT_STP_FLAGS
) &&
52 NF_INVF(info
, EBT_STP_FLAGS
, c
->flags
!= stpc
->flags
))
54 if (info
->bitmask
& EBT_STP_ROOTPRIO
) {
55 v16
= NR16(stpc
->root
);
56 if (NF_INVF(info
, EBT_STP_ROOTPRIO
,
57 v16
< c
->root_priol
|| v16
> c
->root_priou
))
60 if (info
->bitmask
& EBT_STP_ROOTADDR
) {
61 if (NF_INVF(info
, EBT_STP_ROOTADDR
,
62 !ether_addr_equal_masked(&stpc
->root
[2],
67 if (info
->bitmask
& EBT_STP_ROOTCOST
) {
68 v32
= NR32(stpc
->root_cost
);
69 if (NF_INVF(info
, EBT_STP_ROOTCOST
,
70 v32
< c
->root_costl
|| v32
> c
->root_costu
))
73 if (info
->bitmask
& EBT_STP_SENDERPRIO
) {
74 v16
= NR16(stpc
->sender
);
75 if (NF_INVF(info
, EBT_STP_SENDERPRIO
,
76 v16
< c
->sender_priol
|| v16
> c
->sender_priou
))
79 if (info
->bitmask
& EBT_STP_SENDERADDR
) {
80 if (NF_INVF(info
, EBT_STP_SENDERADDR
,
81 !ether_addr_equal_masked(&stpc
->sender
[2],
86 if (info
->bitmask
& EBT_STP_PORT
) {
87 v16
= NR16(stpc
->port
);
88 if (NF_INVF(info
, EBT_STP_PORT
,
89 v16
< c
->portl
|| v16
> c
->portu
))
92 if (info
->bitmask
& EBT_STP_MSGAGE
) {
93 v16
= NR16(stpc
->msg_age
);
94 if (NF_INVF(info
, EBT_STP_MSGAGE
,
95 v16
< c
->msg_agel
|| v16
> c
->msg_ageu
))
98 if (info
->bitmask
& EBT_STP_MAXAGE
) {
99 v16
= NR16(stpc
->max_age
);
100 if (NF_INVF(info
, EBT_STP_MAXAGE
,
101 v16
< c
->max_agel
|| v16
> c
->max_ageu
))
104 if (info
->bitmask
& EBT_STP_HELLOTIME
) {
105 v16
= NR16(stpc
->hello_time
);
106 if (NF_INVF(info
, EBT_STP_HELLOTIME
,
107 v16
< c
->hello_timel
|| v16
> c
->hello_timeu
))
110 if (info
->bitmask
& EBT_STP_FWDD
) {
111 v16
= NR16(stpc
->forward_delay
);
112 if (NF_INVF(info
, EBT_STP_FWDD
,
113 v16
< c
->forward_delayl
|| v16
> c
->forward_delayu
))
120 ebt_stp_mt(const struct sk_buff
*skb
, struct xt_action_param
*par
)
122 const struct ebt_stp_info
*info
= par
->matchinfo
;
123 const struct stp_header
*sp
;
124 struct stp_header _stph
;
125 const u8 header
[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
127 sp
= skb_header_pointer(skb
, 0, sizeof(_stph
), &_stph
);
131 /* The stp code only considers these */
132 if (memcmp(sp
, header
, sizeof(header
)))
135 if ((info
->bitmask
& EBT_STP_TYPE
) &&
136 NF_INVF(info
, EBT_STP_TYPE
, info
->type
!= sp
->type
))
139 if (sp
->type
== BPDU_TYPE_CONFIG
&&
140 info
->bitmask
& EBT_STP_CONFIG_MASK
) {
141 const struct stp_config_pdu
*st
;
142 struct stp_config_pdu _stpc
;
144 st
= skb_header_pointer(skb
, sizeof(_stph
),
145 sizeof(_stpc
), &_stpc
);
148 return ebt_filter_config(info
, st
);
153 static int ebt_stp_mt_check(const struct xt_mtchk_param
*par
)
155 const struct ebt_stp_info
*info
= par
->matchinfo
;
156 const struct ebt_entry
*e
= par
->entryinfo
;
158 if (info
->bitmask
& ~EBT_STP_MASK
|| info
->invflags
& ~EBT_STP_MASK
||
159 !(info
->bitmask
& EBT_STP_MASK
))
161 /* Make sure the match only receives stp frames */
162 if (!par
->nft_compat
&&
163 (!ether_addr_equal(e
->destmac
, eth_stp_addr
) ||
164 !(e
->bitmask
& EBT_DESTMAC
) ||
165 !is_broadcast_ether_addr(e
->destmsk
)))
171 static struct xt_match ebt_stp_mt_reg __read_mostly
= {
174 .family
= NFPROTO_BRIDGE
,
176 .checkentry
= ebt_stp_mt_check
,
177 .matchsize
= sizeof(struct ebt_stp_info
),
181 static int __init
ebt_stp_init(void)
183 return xt_register_match(&ebt_stp_mt_reg
);
186 static void __exit
ebt_stp_fini(void)
188 xt_unregister_match(&ebt_stp_mt_reg
);
191 module_init(ebt_stp_init
);
192 module_exit(ebt_stp_fini
);
193 MODULE_DESCRIPTION("Ebtables: Spanning Tree Protocol packet match");
194 MODULE_LICENSE("GPL");