blob: 307131f97b7bc827aee31ed1cfb44c45e3a33a2c [file] [log] [blame]
Bart De Schuymerff587202005-02-08 20:02:28 +00001/* ebt_stp
2 *
3 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
5 *
6 * July, 2003
7 */
8
Bart De Schuymerdaf06382003-07-17 20:10:29 +00009#include <stdio.h>
10#include <string.h>
11#include <stdlib.h>
12#include <getopt.h>
13#include "../include/ebtables_u.h"
14#include <linux/netfilter_bridge/ebt_stp.h>
15
16#define STP_TYPE 'a'
17#define STP_FLAGS 'b'
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'
23#define STP_PORT 'h'
24#define STP_MSGAGE 'i'
25#define STP_MAXAGE 'j'
26#define STP_HELLOTIME 'k'
27#define STP_FWDD 'l'
28#define STP_NUMOPS 12
29
30static struct option opts[] =
31{
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},
44 { 0 }
45};
46
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"
51
52#define FLAG_TC 0x01
53#define FLAG_TC_ACK 0x80
54#define FLAG_TC_STRING "topology-change"
55#define FLAG_TC_ACK_STRING "topology-change-ack"
56
57static void print_help()
58{
59 printf(
60"stp options:\n"
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"
Bart De Schuymer20a12b22003-07-25 17:23:24 +000077" \"topology-change\" : topology change flag (0x01)\n"
Bart De Schuymerdaf06382003-07-17 20:10:29 +000078" \"topology-change-ack\": topology change acknowledgement flag (0x80)");
79}
80
81static void init(struct ebt_entry_match *match)
82{
83 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
84
85 stpinfo->invflags = 0;
86 stpinfo->bitmask = 0;
87}
88
Bart De Schuymer16effef2004-12-21 20:27:43 +000089static int parse_range(const char *portstring, void *lower, void *upper,
90 int bits, uint32_t min, uint32_t max)
Bart De Schuymerdaf06382003-07-17 20:10:29 +000091{
Bart De Schuymer16effef2004-12-21 20:27:43 +000092 char *buffer;
93 char *cp, *end;
94 uint32_t low_nr, upp_nr;
95 int ret = 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +000096
Bart De Schuymer16effef2004-12-21 20:27:43 +000097 buffer = strdup(portstring);
Bart De Schuymerdaf06382003-07-17 20:10:29 +000098 if ((cp = strchr(buffer, ':')) == NULL) {
Bart De Schuymer16effef2004-12-21 20:27:43 +000099 low_nr = strtoul(buffer, &end, 10);
100 if (*end || low_nr < min || low_nr > max) {
101 ret = -1;
102 goto out;
103 }
104 if (bits == 2) {
105 *(uint16_t *)lower = low_nr;
106 *(uint16_t *)upper = low_nr;
107 } else {
108 *(uint32_t *)lower = low_nr;
109 *(uint32_t *)upper = low_nr;
110 }
111 } else {
112 *cp = '\0';
113 cp++;
114 if (!*buffer)
115 low_nr = min;
116 else {
117 low_nr = strtoul(buffer, &end, 10);
118 if (*end || low_nr < min) {
119 ret = -1;
120 goto out;
121 }
122 }
123 if (!*cp)
124 upp_nr = max;
125 else {
126 upp_nr = strtoul(cp, &end, 10);
127 if (*end || upp_nr > max) {
128 ret = -1;
129 goto out;
130 }
131 }
132 if (upp_nr < low_nr) {
133 ret = -1;
134 goto out;
135 }
136 if (bits == 2) {
137 *(uint16_t *)lower = low_nr;
138 *(uint16_t *)upper = upp_nr;
139 } else {
140 *(uint32_t *)lower = low_nr;
141 *(uint32_t *)upper = upp_nr;
142 }
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000143 }
Bart De Schuymer16effef2004-12-21 20:27:43 +0000144out:
145 free(buffer);
146 return ret;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000147}
148
Bart De Schuymer16effef2004-12-21 20:27:43 +0000149static void print_range(unsigned int l, unsigned int u)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000150{
151 if (l == u)
Bart De Schuymer16effef2004-12-21 20:27:43 +0000152 printf("%u ", l);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000153 else
Bart De Schuymer16effef2004-12-21 20:27:43 +0000154 printf("%u:%u ", l, u);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000155}
156
157static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
158 unsigned int *flags, struct ebt_entry_match **match)
159{
160 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
161 unsigned int flag;
162 long int i;
163 char *end = NULL;
164
Bart De Schuymer926ee0b2003-07-17 21:54:19 +0000165 if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
166 return 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000167 flag = 1 << (c - 'a');
Bart De Schuymerff587202005-02-08 20:02:28 +0000168 ebt_check_option2(flags, flag);
169 if (ebt_check_inverse2(optarg))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000170 stpinfo->invflags |= flag;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000171 stpinfo->bitmask |= flag;
172 switch (flag) {
173 case EBT_STP_TYPE:
Bart De Schuymerff587202005-02-08 20:02:28 +0000174 i = strtol(optarg, &end, 0);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000175 if (i < 0 || i > 255 || *end != '\0') {
Bart De Schuymerff587202005-02-08 20:02:28 +0000176 if (!strcasecmp(optarg, BPDU_TYPE_CONFIG_STRING))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000177 stpinfo->type = BPDU_TYPE_CONFIG;
Bart De Schuymerff587202005-02-08 20:02:28 +0000178 else if (!strcasecmp(optarg, BPDU_TYPE_TCN_STRING))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000179 stpinfo->type = BPDU_TYPE_TCN;
180 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000181 ebt_print_error2("Bad --stp-type argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000182 } else
183 stpinfo->type = i;
184 break;
185 case EBT_STP_FLAGS:
Bart De Schuymerff587202005-02-08 20:02:28 +0000186 i = strtol(optarg, &end, 0);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000187 if (i < 0 || i > 255 || *end != '\0') {
Bart De Schuymerff587202005-02-08 20:02:28 +0000188 if (!strcasecmp(optarg, FLAG_TC_STRING))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000189 stpinfo->config.flags = FLAG_TC;
Bart De Schuymerff587202005-02-08 20:02:28 +0000190 else if (!strcasecmp(optarg, FLAG_TC_ACK_STRING))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000191 stpinfo->config.flags = FLAG_TC_ACK;
192 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000193 ebt_print_error2("Bad --stp-flags argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000194 } else
195 stpinfo->config.flags = i;
196 break;
197 case EBT_STP_ROOTPRIO:
198 if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000199 &(stpinfo->config.root_priou), 2, 0, 0xffff))
200 ebt_print_error("Bad --stp-root-prio range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000201 break;
202 case EBT_STP_ROOTCOST:
203 if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000204 &(stpinfo->config.root_costu), 4, 0, 0xffffffff))
205 ebt_print_error("Bad --stp-root-cost range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000206 break;
207 case EBT_STP_SENDERPRIO:
208 if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000209 &(stpinfo->config.sender_priou), 2, 0, 0xffff))
210 ebt_print_error("Bad --stp-sender-prio range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000211 break;
212 case EBT_STP_PORT:
213 if (parse_range(argv[optind-1], &(stpinfo->config.portl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000214 &(stpinfo->config.portu), 2, 0, 0xffff))
215 ebt_print_error("Bad --stp-port range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000216 break;
217 case EBT_STP_MSGAGE:
218 if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000219 &(stpinfo->config.msg_ageu), 2, 0, 0xffff))
220 ebt_print_error("Bad --stp-msg-age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000221 break;
222 case EBT_STP_MAXAGE:
223 if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000224 &(stpinfo->config.max_ageu), 2, 0, 0xffff))
225 ebt_print_error("Bad --stp-max-age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000226 break;
227 case EBT_STP_HELLOTIME:
228 if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000229 &(stpinfo->config.hello_timeu), 2, 0, 0xffff))
230 ebt_print_error("Bad --stp-hello-time range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000231 break;
232 case EBT_STP_FWDD:
233 if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000234 &(stpinfo->config.forward_delayu), 2, 0, 0xffff))
235 ebt_print_error("Bad --stp-forward-delay range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000236 break;
237 case EBT_STP_ROOTADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000238 if (ebt_get_mac_and_mask(argv[optind-1],
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000239 stpinfo->config.root_addr, stpinfo->config.root_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000240 ebt_print_error("Bad --stp-root-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000241 break;
242 case EBT_STP_SENDERADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000243 if (ebt_get_mac_and_mask(argv[optind-1], stpinfo->config.sender_addr,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000244 stpinfo->config.sender_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000245 ebt_print_error("Bad --stp-sender-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000246 break;
247 default:
Bart De Schuymer64182a32004-01-21 20:39:54 +0000248 ebt_print_error("stp match: this shouldn't happen");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000249 }
250 return 1;
251}
252
253static void final_check(const struct ebt_u_entry *entry,
254 const struct ebt_entry_match *match, const char *name,
255 unsigned int hookmask, unsigned int time)
256{
257 uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
258 uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
259
260 if (memcmp(entry->destmac, bridge_ula, 6) ||
261 memcmp(entry->destmsk, msk, 6))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000262 ebt_print_error("STP matching is only valid when the "
263 "destination MAC address is the bridge group "
264 "address (BGA) 01:80:c2:00:00:00");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000265}
266
267static void print(const struct ebt_u_entry *entry,
268 const struct ebt_entry_match *match)
269{
270 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
271 struct ebt_stp_config_info *c = &(stpinfo->config);
272 int i;
273
274 for (i = 0; i < STP_NUMOPS; i++) {
275 if (!(stpinfo->bitmask & (1 << i)))
276 continue;
277 printf("--%s %s", opts[i].name,
278 (stpinfo->invflags & (1 << i)) ? "! " : "");
279 if (EBT_STP_TYPE == (1 << i)) {
280 if (stpinfo->type == BPDU_TYPE_CONFIG)
281 printf("%s", BPDU_TYPE_CONFIG_STRING);
282 else if (stpinfo->type == BPDU_TYPE_TCN)
283 printf("%s", BPDU_TYPE_TCN_STRING);
284 else
285 printf("%d", stpinfo->type);
286 } else if (EBT_STP_FLAGS == (1 << i)) {
287 if (c->flags == FLAG_TC)
288 printf("%s", FLAG_TC_STRING);
289 else if (c->flags == FLAG_TC_ACK)
290 printf("%s", FLAG_TC_ACK_STRING);
291 else
292 printf("%d", c->flags);
293 } else if (EBT_STP_ROOTPRIO == (1 << i))
294 print_range(c->root_priol, c->root_priou);
295 else if (EBT_STP_ROOTADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000296 ebt_print_mac_and_mask(c->root_addr, c->root_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000297 else if (EBT_STP_ROOTCOST == (1 << i))
298 print_range(c->root_costl, c->root_costu);
299 else if (EBT_STP_SENDERPRIO == (1 << i))
300 print_range(c->sender_priol, c->sender_priou);
301 else if (EBT_STP_SENDERADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000302 ebt_print_mac_and_mask(c->sender_addr, c->sender_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000303 else if (EBT_STP_PORT == (1 << i))
304 print_range(c->portl, c->portu);
305 else if (EBT_STP_MSGAGE == (1 << i))
306 print_range(c->msg_agel, c->msg_ageu);
307 else if (EBT_STP_MAXAGE == (1 << i))
308 print_range(c->max_agel, c->max_ageu);
309 else if (EBT_STP_HELLOTIME == (1 << i))
310 print_range(c->hello_timel, c->hello_timeu);
311 else if (EBT_STP_FWDD == (1 << i))
312 print_range(c->forward_delayl, c->forward_delayu);
313 printf(" ");
314 }
315}
316
317static int compare(const struct ebt_entry_match *m1,
318 const struct ebt_entry_match *m2)
319{
320 return (!memcmp(m1->data, m2->data, sizeof(struct ebt_stp_info)));
321}
322
323static struct ebt_u_match stp_match =
324{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000325 .name = EBT_STP_MATCH,
326 .size = sizeof(struct ebt_stp_info),
327 .help = print_help,
328 .init = init,
329 .parse = parse,
330 .final_check = final_check,
331 .print = print,
332 .compare = compare,
333 .extra_ops = opts,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000334};
335
Bart De Schuymer64182a32004-01-21 20:39:54 +0000336void _init(void)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000337{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000338 ebt_register_match(&stp_match);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000339}