blob: 8e02605cf4534639d53b54ee1a1f6fc4dcdf8586 [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
81/* defined in ebtables.c */
82int get_mac_and_mask(char *from, char *to, char *mask);
83void print_mac_and_mask(const char *mac, const char *mask);
84
85#define determine_value(p,s) \
86{ \
87 uint32_t _tmp2; \
88 char *_tmp; \
89 _tmp2 = strtoul(s, &_tmp, 0); \
Bart De Schuymer926ee0b2003-07-17 21:54:19 +000090 if (*_tmp != '\0') \
Bart De Schuymerdaf06382003-07-17 20:10:29 +000091 return -1; \
92 if (size == 2) { \
93 if (_tmp2 >= (1 << 16)) \
94 return -1; \
95 *(uint16_t *)p = (uint16_t)_tmp2;\
96 } else \
97 *(uint32_t *)p = _tmp2; \
98}
99
100static int parse_range(char *rangestring, void *lower, void *upper,
101 int size)
102{
103 char *buffer, *cp;
104
105 buffer = strdup(rangestring);
106 if ((cp = strchr(buffer, ':')) == NULL) {
107 determine_value(lower, buffer);
108 determine_value(upper, buffer);
109 return 0;
110 }
111 *cp = '\0';
112 determine_value(lower, buffer);
113 determine_value(upper, cp + 1);
114 if (lower > upper)
115 return -1;
116 return 0;
117}
118
119static void print_range(uint32_t l, uint32_t u)
120{
121 if (l == u)
122 printf("%d ", l);
123 else
124 printf("%d:%d ", l, u);
125}
126
127static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
128 unsigned int *flags, struct ebt_entry_match **match)
129{
130 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)(*match)->data;
131 unsigned int flag;
132 long int i;
133 char *end = NULL;
134
Bart De Schuymer926ee0b2003-07-17 21:54:19 +0000135 if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
136 return 0;
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000137 flag = 1 << (c - 'a');
138 check_option(flags, flag);
139 if (check_inverse(optarg))
140 stpinfo->invflags |= flag;
141 if (optind > argc)
142 print_error("Missing argument for --%s", opts[c-'a'].name);
143 stpinfo->bitmask |= flag;
144 switch (flag) {
145 case EBT_STP_TYPE:
146 i = strtol(argv[optind - 1], &end, 0);
147 if (i < 0 || i > 255 || *end != '\0') {
148 if (!strcasecmp(argv[optind - 1],
149 BPDU_TYPE_CONFIG_STRING))
150 stpinfo->type = BPDU_TYPE_CONFIG;
151 else if (!strcasecmp(argv[optind - 1],
152 BPDU_TYPE_TCN_STRING))
153 stpinfo->type = BPDU_TYPE_TCN;
154 else
155 print_error("Bad STP type argument");
156 } else
157 stpinfo->type = i;
158 break;
159 case EBT_STP_FLAGS:
160 i = strtol(argv[optind - 1], &end, 0);
161 if (i < 0 || i > 255 || *end != '\0') {
162 if (!strcasecmp(argv[optind - 1],
163 FLAG_TC_STRING))
164 stpinfo->config.flags = FLAG_TC;
165 else if (!strcasecmp(argv[optind - 1],
166 FLAG_TC_ACK_STRING))
167 stpinfo->config.flags = FLAG_TC_ACK;
168 else
169 print_error("Bad STP config flags argument");
170 } else
171 stpinfo->config.flags = i;
172 break;
173 case EBT_STP_ROOTPRIO:
174 if (parse_range(argv[optind-1], &(stpinfo->config.root_priol),
175 &(stpinfo->config.root_priou), 2))
176 print_error("Bad STP config root priority range");
177 break;
178 case EBT_STP_ROOTCOST:
179 if (parse_range(argv[optind-1], &(stpinfo->config.root_costl),
180 &(stpinfo->config.root_costu), 4))
181 print_error("Bad STP config root cost range");
182 break;
183 case EBT_STP_SENDERPRIO:
184 if (parse_range(argv[optind-1], &(stpinfo->config.sender_priol),
185 &(stpinfo->config.sender_priou), 2))
186 print_error("Bad STP config sender priority range");
187 break;
188 case EBT_STP_PORT:
189 if (parse_range(argv[optind-1], &(stpinfo->config.portl),
190 &(stpinfo->config.portu), 2))
191 print_error("Bad STP config port range");
192 break;
193 case EBT_STP_MSGAGE:
194 if (parse_range(argv[optind-1], &(stpinfo->config.msg_agel),
195 &(stpinfo->config.msg_ageu), 2))
196 print_error("Bad STP config message age range");
197 break;
198 case EBT_STP_MAXAGE:
199 if (parse_range(argv[optind-1], &(stpinfo->config.max_agel),
200 &(stpinfo->config.max_ageu), 2))
201 print_error("Bad STP config maximum age range");
202 break;
203 case EBT_STP_HELLOTIME:
204 if (parse_range(argv[optind-1], &(stpinfo->config.hello_timel),
205 &(stpinfo->config.hello_timeu), 2))
206 print_error("Bad STP config hello time range");
207 break;
208 case EBT_STP_FWDD:
209 if (parse_range(argv[optind-1], &(stpinfo->config.forward_delayl),
210 &(stpinfo->config.forward_delayu), 2))
211 print_error("Bad STP config forward delay range");
212 break;
213 case EBT_STP_ROOTADDR:
214 if (get_mac_and_mask(argv[optind-1],
215 stpinfo->config.root_addr, stpinfo->config.root_addrmsk))
216 print_error("Bad STP config root address");
217 break;
218 case EBT_STP_SENDERADDR:
219 if (get_mac_and_mask(argv[optind-1], stpinfo->config.sender_addr,
220 stpinfo->config.sender_addrmsk))
221 print_error("Bad STP config sender address");
222 break;
223 default:
Bart De Schuymer926ee0b2003-07-17 21:54:19 +0000224 print_error("stp match: this shouldn't happen");
Bart De Schuymerdaf06382003-07-17 20:10:29 +0000225 }
226 return 1;
227}
228
229static void final_check(const struct ebt_u_entry *entry,
230 const struct ebt_entry_match *match, const char *name,
231 unsigned int hookmask, unsigned int time)
232{
233 uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
234 uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
235
236 if (memcmp(entry->destmac, bridge_ula, 6) ||
237 memcmp(entry->destmsk, msk, 6))
238 print_error("STP matching is only valid when the destination"
239 " MAC address is the bridge group address (BGA)"
240 " 01:80:c2:00:00:00");
241}
242
243static void print(const struct ebt_u_entry *entry,
244 const struct ebt_entry_match *match)
245{
246 struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
247 struct ebt_stp_config_info *c = &(stpinfo->config);
248 int i;
249
250 for (i = 0; i < STP_NUMOPS; i++) {
251 if (!(stpinfo->bitmask & (1 << i)))
252 continue;
253 printf("--%s %s", opts[i].name,
254 (stpinfo->invflags & (1 << i)) ? "! " : "");
255 if (EBT_STP_TYPE == (1 << i)) {
256 if (stpinfo->type == BPDU_TYPE_CONFIG)
257 printf("%s", BPDU_TYPE_CONFIG_STRING);
258 else if (stpinfo->type == BPDU_TYPE_TCN)
259 printf("%s", BPDU_TYPE_TCN_STRING);
260 else
261 printf("%d", stpinfo->type);
262 } else if (EBT_STP_FLAGS == (1 << i)) {
263 if (c->flags == FLAG_TC)
264 printf("%s", FLAG_TC_STRING);
265 else if (c->flags == FLAG_TC_ACK)
266 printf("%s", FLAG_TC_ACK_STRING);
267 else
268 printf("%d", c->flags);
269 } else if (EBT_STP_ROOTPRIO == (1 << i))
270 print_range(c->root_priol, c->root_priou);
271 else if (EBT_STP_ROOTADDR == (1 << i))
272 print_mac_and_mask(c->root_addr, c->root_addrmsk);
273 else if (EBT_STP_ROOTCOST == (1 << i))
274 print_range(c->root_costl, c->root_costu);
275 else if (EBT_STP_SENDERPRIO == (1 << i))
276 print_range(c->sender_priol, c->sender_priou);
277 else if (EBT_STP_SENDERADDR == (1 << i))
278 print_mac_and_mask(c->sender_addr, c->sender_addrmsk);
279 else if (EBT_STP_PORT == (1 << i))
280 print_range(c->portl, c->portu);
281 else if (EBT_STP_MSGAGE == (1 << i))
282 print_range(c->msg_agel, c->msg_ageu);
283 else if (EBT_STP_MAXAGE == (1 << i))
284 print_range(c->max_agel, c->max_ageu);
285 else if (EBT_STP_HELLOTIME == (1 << i))
286 print_range(c->hello_timel, c->hello_timeu);
287 else if (EBT_STP_FWDD == (1 << i))
288 print_range(c->forward_delayl, c->forward_delayu);
289 printf(" ");
290 }
291}
292
293static int compare(const struct ebt_entry_match *m1,
294 const struct ebt_entry_match *m2)
295{
296 return (!memcmp(m1->data, m2->data, sizeof(struct ebt_stp_info)));
297}
298
299static struct ebt_u_match stp_match =
300{
301 EBT_STP_MATCH,
302 sizeof(struct ebt_stp_info),
303 print_help,
304 init,
305 parse,
306 final_check,
307 print,
308 compare,
309 opts
310};
311
312static void _init(void) __attribute__ ((constructor));
313static void _init(void)
314{
315 register_match(&stp_match);
316}