blob: 8ed4c472d8c420fefa9c3662e068b2b7f3803ce3 [file] [log] [blame]
Bart De Schuymerdaf06382003-07-17 20:10:29 +00001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <getopt.h>
5#include "../include/ebtables_u.h"
6#include <linux/netfilter_bridge/ebt_stp.h>
7
8#define STP_TYPE 'a'
9#define STP_FLAGS 'b'
10#define STP_ROOTPRIO 'c'
11#define STP_ROOTADDR 'd'
12#define STP_ROOTCOST 'e'
13#define STP_SENDERPRIO 'f'
14#define STP_SENDERADDR 'g'
15#define STP_PORT 'h'
16#define STP_MSGAGE 'i'
17#define STP_MAXAGE 'j'
18#define STP_HELLOTIME 'k'
19#define STP_FWDD 'l'
20#define STP_NUMOPS 12
21
22static struct option opts[] =
23{
24 { "stp-type" , required_argument, 0, STP_TYPE},
25 { "stp-flags" , required_argument, 0, STP_FLAGS},
26 { "stp-root-prio" , required_argument, 0, STP_ROOTPRIO},
27 { "stp-root-addr" , required_argument, 0, STP_ROOTADDR},
28 { "stp-root-cost" , required_argument, 0, STP_ROOTCOST},
29 { "stp-sender-prio" , required_argument, 0, STP_SENDERPRIO},
30 { "stp-sender-addr" , required_argument, 0, STP_SENDERADDR},
31 { "stp-port" , required_argument, 0, STP_PORT},
32 { "stp-msg-age" , required_argument, 0, STP_MSGAGE},
33 { "stp-max-age" , required_argument, 0, STP_MAXAGE},
34 { "stp-hello-time" , required_argument, 0, STP_HELLOTIME},
35 { "stp-forward-delay", required_argument, 0, STP_FWDD},
36 { 0 }
37};
38
39#define BPDU_TYPE_CONFIG 0
40#define BPDU_TYPE_TCN 0x80
41#define BPDU_TYPE_CONFIG_STRING "config"
42#define BPDU_TYPE_TCN_STRING "tcn"
43
44#define FLAG_TC 0x01
45#define FLAG_TC_ACK 0x80
46#define FLAG_TC_STRING "topology-change"
47#define FLAG_TC_ACK_STRING "topology-change-ack"
48
49static void print_help()
50{
51 printf(
52"stp options:\n"
53"--stp-type type : BPDU type\n"
54"--stp-flags flag : control flag\n"
55"--stp-root-prio prio[:prio] : root priority (16-bit) range\n"
56"--stp-root-addr address[/mask] : MAC address of root\n"
57"--stp-root-cost cost[:cost] : root cost (32-bit) range\n"
58"--stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
59"--stp-sender-addr address[/mask] : MAC address of sender\n"
60"--stp-port port[:port] : port id (16-bit) range\n"
61"--stp-msg-age age[:age] : message age timer (16-bit) range\n"
62"--stp-max-age age[:age] : maximum age timer (16-bit) range\n"
63"--stp-hello-time time[:time] : hello time timer (16-bit) range\n"
64"--stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
65" Recognized BPDU type strings:\n"
66" \"config\": configuration BPDU (=0)\n"
67" \"tcn\" : topology change notification BPDU (=0x80)\n"
68" Recognized control flag strings:\n"
Bart De Schuymer20a12b22003-07-25 17:23:24 +000069" \"topology-change\" : topology change flag (0x01)\n"
Bart De Schuymerdaf06382003-07-17 20:10:29 +000070" \"topology-change-ack\": topology change acknowledgement flag (0x80)");
71}
72
73static void init(struct ebt_entry_match *match)
74{
75 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
76
77 stpinfo->invflags = 0;
78 stpinfo->bitmask = 0;
79}
80
Bart De Schuymer16effef2004-12-21 20:27:43 +000081static int parse_range(const char *portstring, void *lower, void *upper,
82 int bits, uint32_t min, uint32_t max)
Bart De Schuymerdaf06382003-07-17 20:10:29 +000083{
Bart De Schuymer16effef2004-12-21 20:27:43 +000084 char *buffer;
85 char *cp, *end;
86 uint32_t low_nr, upp_nr;
87 int ret = 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +000088
Bart De Schuymer16effef2004-12-21 20:27:43 +000089 buffer = strdup(portstring);
Bart De Schuymerdaf06382003-07-17 20:10:29 +000090 if ((cp = strchr(buffer, ':')) == NULL) {
Bart De Schuymer16effef2004-12-21 20:27:43 +000091 low_nr = strtoul(buffer, &end, 10);
92 if (*end || low_nr < min || low_nr > max) {
93 ret = -1;
94 goto out;
95 }
96 if (bits == 2) {
97 *(uint16_t *)lower = low_nr;
98 *(uint16_t *)upper = low_nr;
99 } else {
100 *(uint32_t *)lower = low_nr;
101 *(uint32_t *)upper = low_nr;
102 }
103 } else {
104 *cp = '\0';
105 cp++;
106 if (!*buffer)
107 low_nr = min;
108 else {
109 low_nr = strtoul(buffer, &end, 10);
110 if (*end || low_nr < min) {
111 ret = -1;
112 goto out;
113 }
114 }
115 if (!*cp)
116 upp_nr = max;
117 else {
118 upp_nr = strtoul(cp, &end, 10);
119 if (*end || upp_nr > max) {
120 ret = -1;
121 goto out;
122 }
123 }
124 if (upp_nr < low_nr) {
125 ret = -1;
126 goto out;
127 }
128 if (bits == 2) {
129 *(uint16_t *)lower = low_nr;
130 *(uint16_t *)upper = upp_nr;
131 } else {
132 *(uint32_t *)lower = low_nr;
133 *(uint32_t *)upper = upp_nr;
134 }
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000135 }
Bart De Schuymer16effef2004-12-21 20:27:43 +0000136out:
137 free(buffer);
138 return ret;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000139}
140
Bart De Schuymer16effef2004-12-21 20:27:43 +0000141static void print_range(unsigned int l, unsigned int u)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000142{
143 if (l == u)
Bart De Schuymer16effef2004-12-21 20:27:43 +0000144 printf("%u ", l);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000145 else
Bart De Schuymer16effef2004-12-21 20:27:43 +0000146 printf("%u:%u ", l, u);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000147}
148
149static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
150 unsigned int *flags, struct ebt_entry_match **match)
151{
152 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
153 unsigned int flag;
154 long int i;
155 char *end = NULL;
156
Bart De Schuymer926ee0b2003-07-17 21:54:19 +0000157 if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
158 return 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000159 flag = 1 << (c - 'a');
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000160 ebt_check_option(flags, flag);
161 if (ebt_check_inverse(optarg))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000162 stpinfo->invflags |= flag;
163 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000164 ebt_print_error("Missing argument for --%s", opts[c-'a'].name);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000165 stpinfo->bitmask |= flag;
166 switch (flag) {
167 case EBT_STP_TYPE:
168 i = strtol(argv[optind - 1], &end, 0);
169 if (i < 0 || i > 255 || *end != '\0') {
170 if (!strcasecmp(argv[optind - 1],
171 BPDU_TYPE_CONFIG_STRING))
172 stpinfo->type = BPDU_TYPE_CONFIG;
173 else if (!strcasecmp(argv[optind - 1],
174 BPDU_TYPE_TCN_STRING))
175 stpinfo->type = BPDU_TYPE_TCN;
176 else
Bart De Schuymer16effef2004-12-21 20:27:43 +0000177 ebt_print_error("Bad --stp-type argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000178 } else
179 stpinfo->type = i;
180 break;
181 case EBT_STP_FLAGS:
182 i = strtol(argv[optind - 1], &end, 0);
183 if (i < 0 || i > 255 || *end != '\0') {
184 if (!strcasecmp(argv[optind - 1],
185 FLAG_TC_STRING))
186 stpinfo->config.flags = FLAG_TC;
187 else if (!strcasecmp(argv[optind - 1],
188 FLAG_TC_ACK_STRING))
189 stpinfo->config.flags = FLAG_TC_ACK;
190 else
Bart De Schuymer16effef2004-12-21 20:27:43 +0000191 ebt_print_error("Bad --stp-flags argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000192 } else
193 stpinfo->config.flags = i;
194 break;
195 case EBT_STP_ROOTPRIO:
196 if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000197 &(stpinfo->config.root_priou), 2, 0, 0xffff))
198 ebt_print_error("Bad --stp-root-prio range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000199 break;
200 case EBT_STP_ROOTCOST:
201 if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000202 &(stpinfo->config.root_costu), 4, 0, 0xffffffff))
203 ebt_print_error("Bad --stp-root-cost range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000204 break;
205 case EBT_STP_SENDERPRIO:
206 if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000207 &(stpinfo->config.sender_priou), 2, 0, 0xffff))
208 ebt_print_error("Bad --stp-sender-prio range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000209 break;
210 case EBT_STP_PORT:
211 if (parse_range(argv[optind-1], &(stpinfo->config.portl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000212 &(stpinfo->config.portu), 2, 0, 0xffff))
213 ebt_print_error("Bad --stp-port range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000214 break;
215 case EBT_STP_MSGAGE:
216 if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000217 &(stpinfo->config.msg_ageu), 2, 0, 0xffff))
218 ebt_print_error("Bad --stp-msg-age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000219 break;
220 case EBT_STP_MAXAGE:
221 if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000222 &(stpinfo->config.max_ageu), 2, 0, 0xffff))
223 ebt_print_error("Bad --stp-max-age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000224 break;
225 case EBT_STP_HELLOTIME:
226 if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000227 &(stpinfo->config.hello_timeu), 2, 0, 0xffff))
228 ebt_print_error("Bad --stp-hello-time range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000229 break;
230 case EBT_STP_FWDD:
231 if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
Bart De Schuymer16effef2004-12-21 20:27:43 +0000232 &(stpinfo->config.forward_delayu), 2, 0, 0xffff))
233 ebt_print_error("Bad --stp-forward-delay range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000234 break;
235 case EBT_STP_ROOTADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000236 if (ebt_get_mac_and_mask(argv[optind-1],
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000237 stpinfo->config.root_addr, stpinfo->config.root_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000238 ebt_print_error("Bad --stp-root-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000239 break;
240 case EBT_STP_SENDERADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000241 if (ebt_get_mac_and_mask(argv[optind-1], stpinfo->config.sender_addr,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000242 stpinfo->config.sender_addrmsk))
Bart De Schuymer16effef2004-12-21 20:27:43 +0000243 ebt_print_error("Bad --stp-sender-addr address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000244 break;
245 default:
Bart De Schuymer64182a32004-01-21 20:39:54 +0000246 ebt_print_error("stp match: this shouldn't happen");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000247 }
248 return 1;
249}
250
251static void final_check(const struct ebt_u_entry *entry,
252 const struct ebt_entry_match *match, const char *name,
253 unsigned int hookmask, unsigned int time)
254{
255 uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
256 uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
257
258 if (memcmp(entry->destmac, bridge_ula, 6) ||
259 memcmp(entry->destmsk, msk, 6))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000260 ebt_print_error("STP matching is only valid when the "
261 "destination MAC address is the bridge group "
262 "address (BGA) 01:80:c2:00:00:00");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000263}
264
265static void print(const struct ebt_u_entry *entry,
266 const struct ebt_entry_match *match)
267{
268 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
269 struct ebt_stp_config_info *c = &(stpinfo->config);
270 int i;
271
272 for (i = 0; i < STP_NUMOPS; i++) {
273 if (!(stpinfo->bitmask & (1 << i)))
274 continue;
275 printf("--%s %s", opts[i].name,
276 (stpinfo->invflags & (1 << i)) ? "! " : "");
277 if (EBT_STP_TYPE == (1 << i)) {
278 if (stpinfo->type == BPDU_TYPE_CONFIG)
279 printf("%s", BPDU_TYPE_CONFIG_STRING);
280 else if (stpinfo->type == BPDU_TYPE_TCN)
281 printf("%s", BPDU_TYPE_TCN_STRING);
282 else
283 printf("%d", stpinfo->type);
284 } else if (EBT_STP_FLAGS == (1 << i)) {
285 if (c->flags == FLAG_TC)
286 printf("%s", FLAG_TC_STRING);
287 else if (c->flags == FLAG_TC_ACK)
288 printf("%s", FLAG_TC_ACK_STRING);
289 else
290 printf("%d", c->flags);
291 } else if (EBT_STP_ROOTPRIO == (1 << i))
292 print_range(c->root_priol, c->root_priou);
293 else if (EBT_STP_ROOTADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000294 ebt_print_mac_and_mask(c->root_addr, c->root_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000295 else if (EBT_STP_ROOTCOST == (1 << i))
296 print_range(c->root_costl, c->root_costu);
297 else if (EBT_STP_SENDERPRIO == (1 << i))
298 print_range(c->sender_priol, c->sender_priou);
299 else if (EBT_STP_SENDERADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000300 ebt_print_mac_and_mask(c->sender_addr, c->sender_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000301 else if (EBT_STP_PORT == (1 << i))
302 print_range(c->portl, c->portu);
303 else if (EBT_STP_MSGAGE == (1 << i))
304 print_range(c->msg_agel, c->msg_ageu);
305 else if (EBT_STP_MAXAGE == (1 << i))
306 print_range(c->max_agel, c->max_ageu);
307 else if (EBT_STP_HELLOTIME == (1 << i))
308 print_range(c->hello_timel, c->hello_timeu);
309 else if (EBT_STP_FWDD == (1 << i))
310 print_range(c->forward_delayl, c->forward_delayu);
311 printf(" ");
312 }
313}
314
315static int compare(const struct ebt_entry_match *m1,
316 const struct ebt_entry_match *m2)
317{
318 return (!memcmp(m1->data, m2->data, sizeof(struct ebt_stp_info)));
319}
320
321static struct ebt_u_match stp_match =
322{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000323 .name = EBT_STP_MATCH,
324 .size = sizeof(struct ebt_stp_info),
325 .help = print_help,
326 .init = init,
327 .parse = parse,
328 .final_check = final_check,
329 .print = print,
330 .compare = compare,
331 .extra_ops = opts,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000332};
333
Bart De Schuymer64182a32004-01-21 20:39:54 +0000334void _init(void)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000335{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000336 ebt_register_match(&stp_match);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000337}