blob: b458c40ef3fc6f32db4d793a00cd39b9d94599ce [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 Schuymerdaf06382003-07-17 20:10:29 +000081#define determine_value(p,s) \
82{ \
83 uint32_t _tmp2; \
84 char *_tmp; \
85 _tmp2 = strtoul(s, &_tmp, 0); \
Bart De Schuymer926ee0b2003-07-17 21:54:19 +000086 if (*_tmp != '\0') \
Bart De Schuymerdaf06382003-07-17 20:10:29 +000087 return -1; \
88 if (size == 2) { \
89 if (_tmp2 >= (1 << 16)) \
90 return -1; \
91 *(uint16_t *)p = (uint16_t)_tmp2;\
92 } else \
93 *(uint32_t *)p = _tmp2; \
94}
95
96static int parse_range(char *rangestring, void *lower, void *upper,
97 int size)
98{
99 char *buffer, *cp;
100
101 buffer = strdup(rangestring);
102 if ((cp = strchr(buffer, ':')) == NULL) {
103 determine_value(lower, buffer);
104 determine_value(upper, buffer);
105 return 0;
106 }
107 *cp = '\0';
108 determine_value(lower, buffer);
109 determine_value(upper, cp + 1);
110 if (lower > upper)
111 return -1;
112 return 0;
113}
114
115static void print_range(uint32_t l, uint32_t u)
116{
117 if (l == u)
118 printf("%d ", l);
119 else
120 printf("%d:%d ", l, u);
121}
122
123static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
124 unsigned int *flags, struct ebt_entry_match **match)
125{
126 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
127 unsigned int flag;
128 long int i;
129 char *end = NULL;
130
Bart De Schuymer926ee0b2003-07-17 21:54:19 +0000131 if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
132 return 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000133 flag = 1 << (c - 'a');
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000134 ebt_check_option(flags, flag);
135 if (ebt_check_inverse(optarg))
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000136 stpinfo->invflags |= flag;
137 if (optind > argc)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000138 ebt_print_error("Missing argument for --%s", opts[c-'a'].name);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000139 stpinfo->bitmask |= flag;
140 switch (flag) {
141 case EBT_STP_TYPE:
142 i = strtol(argv[optind - 1], &end, 0);
143 if (i < 0 || i > 255 || *end != '\0') {
144 if (!strcasecmp(argv[optind - 1],
145 BPDU_TYPE_CONFIG_STRING))
146 stpinfo->type = BPDU_TYPE_CONFIG;
147 else if (!strcasecmp(argv[optind - 1],
148 BPDU_TYPE_TCN_STRING))
149 stpinfo->type = BPDU_TYPE_TCN;
150 else
Bart De Schuymer64182a32004-01-21 20:39:54 +0000151 ebt_print_error("Bad STP type argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000152 } else
153 stpinfo->type = i;
154 break;
155 case EBT_STP_FLAGS:
156 i = strtol(argv[optind - 1], &end, 0);
157 if (i < 0 || i > 255 || *end != '\0') {
158 if (!strcasecmp(argv[optind - 1],
159 FLAG_TC_STRING))
160 stpinfo->config.flags = FLAG_TC;
161 else if (!strcasecmp(argv[optind - 1],
162 FLAG_TC_ACK_STRING))
163 stpinfo->config.flags = FLAG_TC_ACK;
164 else
Bart De Schuymer64182a32004-01-21 20:39:54 +0000165 ebt_print_error("Bad STP config flags "
166 "argument");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000167 } else
168 stpinfo->config.flags = i;
169 break;
170 case EBT_STP_ROOTPRIO:
171 if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
172 &(stpinfo->config.root_priou), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000173 ebt_print_error("Bad STP config root priority range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000174 break;
175 case EBT_STP_ROOTCOST:
176 if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
177 &(stpinfo->config.root_costu), 4))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000178 ebt_print_error("Bad STP config root cost range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000179 break;
180 case EBT_STP_SENDERPRIO:
181 if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
182 &(stpinfo->config.sender_priou), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000183 ebt_print_error("Bad STP config sender priority range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000184 break;
185 case EBT_STP_PORT:
186 if (parse_range(argv[optind-1], &(stpinfo->config.portl),
187 &(stpinfo->config.portu), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000188 ebt_print_error("Bad STP config port range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000189 break;
190 case EBT_STP_MSGAGE:
191 if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
192 &(stpinfo->config.msg_ageu), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000193 ebt_print_error("Bad STP config message age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000194 break;
195 case EBT_STP_MAXAGE:
196 if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
197 &(stpinfo->config.max_ageu), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000198 ebt_print_error("Bad STP config maximum age range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000199 break;
200 case EBT_STP_HELLOTIME:
201 if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
202 &(stpinfo->config.hello_timeu), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000203 ebt_print_error("Bad STP config hello time range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000204 break;
205 case EBT_STP_FWDD:
206 if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
207 &(stpinfo->config.forward_delayu), 2))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000208 ebt_print_error("Bad STP config forward delay range");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000209 break;
210 case EBT_STP_ROOTADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000211 if (ebt_get_mac_and_mask(argv[optind-1],
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000212 stpinfo->config.root_addr, stpinfo->config.root_addrmsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000213 ebt_print_error("Bad STP config root address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000214 break;
215 case EBT_STP_SENDERADDR:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000216 if (ebt_get_mac_and_mask(argv[optind-1], stpinfo->config.sender_addr,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000217 stpinfo->config.sender_addrmsk))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000218 ebt_print_error("Bad STP config sender address");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000219 break;
220 default:
Bart De Schuymer64182a32004-01-21 20:39:54 +0000221 ebt_print_error("stp match: this shouldn't happen");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000222 }
223 return 1;
224}
225
226static void final_check(const struct ebt_u_entry *entry,
227 const struct ebt_entry_match *match, const char *name,
228 unsigned int hookmask, unsigned int time)
229{
230 uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
231 uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
232
233 if (memcmp(entry->destmac, bridge_ula, 6) ||
234 memcmp(entry->destmsk, msk, 6))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000235 ebt_print_error("STP matching is only valid when the "
236 "destination MAC address is the bridge group "
237 "address (BGA) 01:80:c2:00:00:00");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000238}
239
240static void print(const struct ebt_u_entry *entry,
241 const struct ebt_entry_match *match)
242{
243 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
244 struct ebt_stp_config_info *c = &(stpinfo->config);
245 int i;
246
247 for (i = 0; i < STP_NUMOPS; i++) {
248 if (!(stpinfo->bitmask & (1 << i)))
249 continue;
250 printf("--%s %s", opts[i].name,
251 (stpinfo->invflags & (1 << i)) ? "! " : "");
252 if (EBT_STP_TYPE == (1 << i)) {
253 if (stpinfo->type == BPDU_TYPE_CONFIG)
254 printf("%s", BPDU_TYPE_CONFIG_STRING);
255 else if (stpinfo->type == BPDU_TYPE_TCN)
256 printf("%s", BPDU_TYPE_TCN_STRING);
257 else
258 printf("%d", stpinfo->type);
259 } else if (EBT_STP_FLAGS == (1 << i)) {
260 if (c->flags == FLAG_TC)
261 printf("%s", FLAG_TC_STRING);
262 else if (c->flags == FLAG_TC_ACK)
263 printf("%s", FLAG_TC_ACK_STRING);
264 else
265 printf("%d", c->flags);
266 } else if (EBT_STP_ROOTPRIO == (1 << i))
267 print_range(c->root_priol, c->root_priou);
268 else if (EBT_STP_ROOTADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000269 ebt_print_mac_and_mask(c->root_addr, c->root_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000270 else if (EBT_STP_ROOTCOST == (1 << i))
271 print_range(c->root_costl, c->root_costu);
272 else if (EBT_STP_SENDERPRIO == (1 << i))
273 print_range(c->sender_priol, c->sender_priou);
274 else if (EBT_STP_SENDERADDR == (1 << i))
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000275 ebt_print_mac_and_mask(c->sender_addr, c->sender_addrmsk);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000276 else if (EBT_STP_PORT == (1 << i))
277 print_range(c->portl, c->portu);
278 else if (EBT_STP_MSGAGE == (1 << i))
279 print_range(c->msg_agel, c->msg_ageu);
280 else if (EBT_STP_MAXAGE == (1 << i))
281 print_range(c->max_agel, c->max_ageu);
282 else if (EBT_STP_HELLOTIME == (1 << i))
283 print_range(c->hello_timel, c->hello_timeu);
284 else if (EBT_STP_FWDD == (1 << i))
285 print_range(c->forward_delayl, c->forward_delayu);
286 printf(" ");
287 }
288}
289
290static int compare(const struct ebt_entry_match *m1,
291 const struct ebt_entry_match *m2)
292{
293 return (!memcmp(m1->data, m2->data, sizeof(struct ebt_stp_info)));
294}
295
296static struct ebt_u_match stp_match =
297{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000298 .name = EBT_STP_MATCH,
299 .size = sizeof(struct ebt_stp_info),
300 .help = print_help,
301 .init = init,
302 .parse = parse,
303 .final_check = final_check,
304 .print = print,
305 .compare = compare,
306 .extra_ops = opts,
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000307};
308
Bart De Schuymer64182a32004-01-21 20:39:54 +0000309void _init(void)
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000310{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000311 ebt_register_match(&stp_match);
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000312}