www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / userapps / opensource / ebtables / extensions / ebt_stp.c
1 #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
22 static 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
49 static 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"
69 "   \"topology-change\"    : topology change flag (0x01)\n"
70 "   \"topology-change-ack\": topology change acknowledgement flag (0x80)");
71 }
72
73 static 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 */
82 int get_mac_and_mask(char *from, char *to, char *mask);
83 void 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);            \
90         if (*_tmp != '\0')                       \
91                 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
100 static 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
119 static 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
127 static 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
135         if (c < 'a' || c > ('a' + STP_NUMOPS - 1))
136                 return 0;
137         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:
224                 print_error("stp match: this shouldn't happen");
225         }
226         return 1;
227 }
228
229 static 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
243 static 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
293 static 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
299 static struct ebt_u_match stp_match =
300 {
301         .name           = EBT_STP_MATCH,
302         .size           = sizeof(struct ebt_stp_info),
303         .help           = print_help,
304         .init           = init,
305         .parse          = parse,
306         .final_check    = final_check,
307         .print          = print,
308         .compare        = compare,
309         .extra_ops      = opts,
310 };
311
312 static void _init(void) __attribute__ ((constructor));
313 static void _init(void)
314 {
315         register_match(&stp_match);
316 }