4 * Bart De Schuymer <bdschuym@pandora.be>
13 #include "../include/ebtables_u.h"
14 #include <linux/netfilter_bridge/ebt_stp.h>
18 #define STP_ROOTPRIO 'c'
19 #define STP_ROOTADDR 'd'
20 #define STP_ROOTCOST 'e'
21 #define STP_SENDERPRIO 'f'
22 #define STP_SENDERADDR 'g'
24 #define STP_MSGAGE 'i'
25 #define STP_MAXAGE 'j'
26 #define STP_HELLOTIME 'k'
30 static struct option opts
[] =
32 { "stp-type" , required_argument
, 0, STP_TYPE
},
33 { "stp-flags" , required_argument
, 0, STP_FLAGS
},
34 { "stp-root-prio" , required_argument
, 0, STP_ROOTPRIO
},
35 { "stp-root-addr" , required_argument
, 0, STP_ROOTADDR
},
36 { "stp-root-cost" , required_argument
, 0, STP_ROOTCOST
},
37 { "stp-sender-prio" , required_argument
, 0, STP_SENDERPRIO
},
38 { "stp-sender-addr" , required_argument
, 0, STP_SENDERADDR
},
39 { "stp-port" , required_argument
, 0, STP_PORT
},
40 { "stp-msg-age" , required_argument
, 0, STP_MSGAGE
},
41 { "stp-max-age" , required_argument
, 0, STP_MAXAGE
},
42 { "stp-hello-time" , required_argument
, 0, STP_HELLOTIME
},
43 { "stp-forward-delay", required_argument
, 0, STP_FWDD
},
47 #define BPDU_TYPE_CONFIG 0
48 #define BPDU_TYPE_TCN 0x80
49 #define BPDU_TYPE_CONFIG_STRING "config"
50 #define BPDU_TYPE_TCN_STRING "tcn"
53 #define FLAG_TC_ACK 0x80
54 #define FLAG_TC_STRING "topology-change"
55 #define FLAG_TC_ACK_STRING "topology-change-ack"
57 static void print_help()
61 "--stp-type type : BPDU type\n"
62 "--stp-flags flag : control flag\n"
63 "--stp-root-prio prio[:prio] : root priority (16-bit) range\n"
64 "--stp-root-addr address[/mask] : MAC address of root\n"
65 "--stp-root-cost cost[:cost] : root cost (32-bit) range\n"
66 "--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
67 "--stp-sender-addr address[/mask] : MAC address of sender\n"
68 "--stp-port port[:port] : port id (16-bit) range\n"
69 "--stp-msg-age age[:age] : message age timer (16-bit) range\n"
70 "--stp-max-age age[:age] : maximum age timer (16-bit) range\n"
71 "--stp-hello-time time[:time] : hello time timer (16-bit) range\n"
72 "--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
73 " Recognized BPDU type strings:\n"
74 " \"config\": configuration BPDU (=0)\n"
75 " \"tcn\" : topology change notification BPDU (=0x80)\n"
76 " Recognized control flag strings:\n"
77 " \"topology-change\" : topology change flag (0x01)\n"
78 " \"topology-change-ack\": topology change acknowledgement flag (0x80)");
81 static void init(struct ebt_entry_match
*match
)
83 struct ebt_stp_info
*stpinfo
= (struct ebt_stp_info
*)match
->data
;
85 stpinfo
->invflags
= 0;
89 static int parse_range(const char *portstring
, void *lower
, void *upper
,
90 int bits
, uint32_t min
, uint32_t max
)
94 uint32_t low_nr
, upp_nr
;
97 buffer
= strdup(portstring
);
98 if ((cp
= strchr(buffer
, ':')) == NULL
) {
99 low_nr
= strtoul(buffer
, &end
, 10);
100 if (*end
|| low_nr
< min
|| low_nr
> max
) {
105 *(uint16_t *)lower
= low_nr
;
106 *(uint16_t *)upper
= low_nr
;
108 *(uint32_t *)lower
= low_nr
;
109 *(uint32_t *)upper
= low_nr
;
117 low_nr
= strtoul(buffer
, &end
, 10);
118 if (*end
|| low_nr
< min
) {
126 upp_nr
= strtoul(cp
, &end
, 10);
127 if (*end
|| upp_nr
> max
) {
132 if (upp_nr
< low_nr
) {
137 *(uint16_t *)lower
= low_nr
;
138 *(uint16_t *)upper
= upp_nr
;
140 *(uint32_t *)lower
= low_nr
;
141 *(uint32_t *)upper
= upp_nr
;
149 static void print_range(unsigned int l
, unsigned int u
)
154 printf("%u:%u ", l
, u
);
157 static int parse(int c
, char **argv
, int argc
, const struct ebt_u_entry
*entry
,
158 unsigned int *flags
, struct ebt_entry_match
**match
)
160 struct ebt_stp_info
*stpinfo
= (struct ebt_stp_info
*)(*match
)->data
;
165 if (c
< 'a' || c
> ('a' + STP_NUMOPS
- 1))
167 flag
= 1 << (c
- 'a');
168 ebt_check_option2(flags
, flag
);
169 if (ebt_check_inverse2(optarg
))
170 stpinfo
->invflags
|= flag
;
171 stpinfo
->bitmask
|= flag
;
174 i
= strtol(optarg
, &end
, 0);
175 if (i
< 0 || i
> 255 || *end
!= '\0') {
176 if (!strcasecmp(optarg
, BPDU_TYPE_CONFIG_STRING
))
177 stpinfo
->type
= BPDU_TYPE_CONFIG
;
178 else if (!strcasecmp(optarg
, BPDU_TYPE_TCN_STRING
))
179 stpinfo
->type
= BPDU_TYPE_TCN
;
181 ebt_print_error2("Bad --stp-type argument");
186 i
= strtol(optarg
, &end
, 0);
187 if (i
< 0 || i
> 255 || *end
!= '\0') {
188 if (!strcasecmp(optarg
, FLAG_TC_STRING
))
189 stpinfo
->config
.flags
= FLAG_TC
;
190 else if (!strcasecmp(optarg
, FLAG_TC_ACK_STRING
))
191 stpinfo
->config
.flags
= FLAG_TC_ACK
;
193 ebt_print_error2("Bad --stp-flags argument");
195 stpinfo
->config
.flags
= i
;
197 case EBT_STP_ROOTPRIO
:
198 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.root_priol
),
199 &(stpinfo
->config
.root_priou
), 2, 0, 0xffff))
200 ebt_print_error("Bad --stp-root-prio range");
202 case EBT_STP_ROOTCOST
:
203 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.root_costl
),
204 &(stpinfo
->config
.root_costu
), 4, 0, 0xffffffff))
205 ebt_print_error("Bad --stp-root-cost range");
207 case EBT_STP_SENDERPRIO
:
208 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.sender_priol
),
209 &(stpinfo
->config
.sender_priou
), 2, 0, 0xffff))
210 ebt_print_error("Bad --stp-sender-prio range");
213 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.portl
),
214 &(stpinfo
->config
.portu
), 2, 0, 0xffff))
215 ebt_print_error("Bad --stp-port range");
218 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.msg_agel
),
219 &(stpinfo
->config
.msg_ageu
), 2, 0, 0xffff))
220 ebt_print_error("Bad --stp-msg-age range");
223 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.max_agel
),
224 &(stpinfo
->config
.max_ageu
), 2, 0, 0xffff))
225 ebt_print_error("Bad --stp-max-age range");
227 case EBT_STP_HELLOTIME
:
228 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.hello_timel
),
229 &(stpinfo
->config
.hello_timeu
), 2, 0, 0xffff))
230 ebt_print_error("Bad --stp-hello-time range");
233 if (parse_range(argv
[optind
-1], &(stpinfo
->config
.forward_delayl
),
234 &(stpinfo
->config
.forward_delayu
), 2, 0, 0xffff))
235 ebt_print_error("Bad --stp-forward-delay range");
237 case EBT_STP_ROOTADDR
:
238 if (ebt_get_mac_and_mask(argv
[optind
-1],
239 (unsigned char *)stpinfo
->config
.root_addr
,
240 (unsigned char *)stpinfo
->config
.root_addrmsk
))
241 ebt_print_error("Bad --stp-root-addr address");
243 case EBT_STP_SENDERADDR
:
244 if (ebt_get_mac_and_mask(argv
[optind
-1],
245 (unsigned char *)stpinfo
->config
.sender_addr
,
246 (unsigned char *)stpinfo
->config
.sender_addrmsk
))
247 ebt_print_error("Bad --stp-sender-addr address");
250 ebt_print_error("stp match: this shouldn't happen");
255 static void final_check(const struct ebt_u_entry
*entry
,
256 const struct ebt_entry_match
*match
, const char *name
,
257 unsigned int hookmask
, unsigned int time
)
259 uint8_t bridge_ula
[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
260 uint8_t msk
[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
262 if (memcmp(entry
->destmac
, bridge_ula
, 6) ||
263 memcmp(entry
->destmsk
, msk
, 6))
264 ebt_print_error("STP matching is only valid when the "
265 "destination MAC address is the bridge group "
266 "address (BGA) 01:80:c2:00:00:00");
269 static void print(const struct ebt_u_entry
*entry
,
270 const struct ebt_entry_match
*match
)
272 struct ebt_stp_info
*stpinfo
= (struct ebt_stp_info
*)match
->data
;
273 struct ebt_stp_config_info
*c
= &(stpinfo
->config
);
276 for (i
= 0; i
< STP_NUMOPS
; i
++) {
277 if (!(stpinfo
->bitmask
& (1 << i
)))
279 printf("--%s %s", opts
[i
].name
,
280 (stpinfo
->invflags
& (1 << i
)) ? "! " : "");
281 if (EBT_STP_TYPE
== (1 << i
)) {
282 if (stpinfo
->type
== BPDU_TYPE_CONFIG
)
283 printf("%s", BPDU_TYPE_CONFIG_STRING
);
284 else if (stpinfo
->type
== BPDU_TYPE_TCN
)
285 printf("%s", BPDU_TYPE_TCN_STRING
);
287 printf("%d", stpinfo
->type
);
288 } else if (EBT_STP_FLAGS
== (1 << i
)) {
289 if (c
->flags
== FLAG_TC
)
290 printf("%s", FLAG_TC_STRING
);
291 else if (c
->flags
== FLAG_TC_ACK
)
292 printf("%s", FLAG_TC_ACK_STRING
);
294 printf("%d", c
->flags
);
295 } else if (EBT_STP_ROOTPRIO
== (1 << i
))
296 print_range(c
->root_priol
, c
->root_priou
);
297 else if (EBT_STP_ROOTADDR
== (1 << i
))
298 ebt_print_mac_and_mask((unsigned char *)c
->root_addr
,
299 (unsigned char*)c
->root_addrmsk
);
300 else if (EBT_STP_ROOTCOST
== (1 << i
))
301 print_range(c
->root_costl
, c
->root_costu
);
302 else if (EBT_STP_SENDERPRIO
== (1 << i
))
303 print_range(c
->sender_priol
, c
->sender_priou
);
304 else if (EBT_STP_SENDERADDR
== (1 << i
))
305 ebt_print_mac_and_mask((unsigned char *)c
->sender_addr
,
306 (unsigned char *)c
->sender_addrmsk
);
307 else if (EBT_STP_PORT
== (1 << i
))
308 print_range(c
->portl
, c
->portu
);
309 else if (EBT_STP_MSGAGE
== (1 << i
))
310 print_range(c
->msg_agel
, c
->msg_ageu
);
311 else if (EBT_STP_MAXAGE
== (1 << i
))
312 print_range(c
->max_agel
, c
->max_ageu
);
313 else if (EBT_STP_HELLOTIME
== (1 << i
))
314 print_range(c
->hello_timel
, c
->hello_timeu
);
315 else if (EBT_STP_FWDD
== (1 << i
))
316 print_range(c
->forward_delayl
, c
->forward_delayu
);
321 static int compare(const struct ebt_entry_match
*m1
,
322 const struct ebt_entry_match
*m2
)
324 return (!memcmp(m1
->data
, m2
->data
, sizeof(struct ebt_stp_info
)));
327 static struct ebt_u_match stp_match
=
330 .size
= sizeof(struct ebt_stp_info
),
334 .final_check
= final_check
,
342 ebt_register_match(&stp_match
);