blob: 08a48fb72a1375b19583f9bb70a06849fff7fd67 [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 Schuymer510c9ce2006-01-23 18:50:54 +0000239 (unsigned char *)stpinfo->config.root_addr,
240 (unsigned char *)stpinfo->config.root_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000241 ebt_print_error("Bad --stp-root-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000242 break;
243 case EBT_STP_SENDERADDR:
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000244 if (ebt_get_mac_and_mask(argv[optind-1],
245 (unsigned char *)stpinfo->config.sender_addr,
246 (unsigned char *)stpinfo->config.sender_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000247 ebt_print_error("Bad --stp-sender-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000248 break;
249 default:
Bart De Schuymer64182a32004-01-21 20:39:54 +0000250 ebt_print_error("stp match: this shouldn't happen");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000251 }
252 return 1;
253}
254
255static 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)
258{
259 uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
260 uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
261
262 if (memcmp(entry->destmac, bridge_ula, 6) ||
263 memcmp(entry->destmsk, msk, 6))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000264 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");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000267}
268
269static void print(const struct ebt_u_entry *entry,
270 const struct ebt_entry_match *match)
271{
272 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
273 struct ebt_stp_config_info *c = &(stpinfo->config);
274 int i;
275
276 for (i = 0; i < STP_NUMOPS; i++) {
277 if (!(stpinfo->bitmask & (1 << i)))
278 continue;
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);
286 else
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);
293 else
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))
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000298 ebt_print_mac_and_mask((unsigned char *)c->root_addr,
299 (unsigned char*)c->root_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000300 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))
Bart De Schuymer510c9ce2006-01-23 18:50:54 +0000305 ebt_print_mac_and_mask((unsigned char *)c->sender_addr,
306 (unsigned char *)c->sender_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000307 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);
317 printf(" ");
318 }
319}
320
321static int compare(const struct ebt_entry_match *m1,
322 const struct ebt_entry_match *m2)
323{
324 return (!memcmp(m1->data, m2->data, sizeof(struct ebt_stp_info)));
325}
326
327static struct ebt_u_match stp_match =
328{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000329 .name = EBT_STP_MATCH,
330 .size = sizeof(struct ebt_stp_info),
331 .help = print_help,
332 .init = init,
333 .parse = parse,
334 .final_check = final_check,
335 .print = print,
336 .compare = compare,
337 .extra_ops = opts,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000338};
339
Bart De Schuymer64182a32004-01-21 20:39:54 +0000340void _init(void)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000341{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000342 ebt_register_match(&stp_match);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000343}