1 /* ebt_stp
2 *
3 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
5 *
6 * July, 2003
7 */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <netinet/ether.h>
13 #include <linux/netfilter_bridge/ebt_stp.h>
14 #include <xtables.h>
15
16 #include "iptables/nft.h"
17 #include "iptables/nft-bridge.h"
18
19 /* These must correspond to the bit position in EBT_STP_* defines */
20 enum {
21 O_TYPE = 0,
22 O_FLAGS,
23 O_RPRIO,
24 O_RADDR,
25 O_RCOST,
26 O_SPRIO,
27 O_SADDR,
28 O_PORT,
29 O_MSGAGE,
30 O_MAXAGE,
31 O_HTIME,
32 O_FWDD,
33 };
34
35 static const struct xt_option_entry brstp_opts[] = {
36 #define ENTRY(n, i, t) { .name = n, .id = i, .type = t, .flags = XTOPT_INVERT }
37 ENTRY("stp-type", O_TYPE, XTTYPE_STRING),
38 ENTRY("stp-flags", O_FLAGS, XTTYPE_STRING),
39 ENTRY("stp-root-prio", O_RPRIO, XTTYPE_UINT16RC),
40 ENTRY("stp-root-addr", O_RADDR, XTTYPE_ETHERMACMASK),
41 ENTRY("stp-root-cost", O_RCOST, XTTYPE_UINT32RC),
42 ENTRY("stp-sender-prio", O_SPRIO, XTTYPE_UINT16RC),
43 ENTRY("stp-sender-addr", O_SADDR, XTTYPE_ETHERMACMASK),
44 ENTRY("stp-port", O_PORT, XTTYPE_UINT16RC),
45 ENTRY("stp-msg-age", O_MSGAGE, XTTYPE_UINT16RC),
46 ENTRY("stp-max-age", O_MAXAGE, XTTYPE_UINT16RC),
47 ENTRY("stp-hello-time", O_HTIME, XTTYPE_UINT16RC),
48 ENTRY("stp-forward-delay", O_FWDD, XTTYPE_UINT16RC),
49 XTOPT_TABLEEND,
50 };
51
52 #define BPDU_TYPE_CONFIG 0
53 #define BPDU_TYPE_TCN 0x80
54 #define BPDU_TYPE_CONFIG_STRING "config"
55 #define BPDU_TYPE_TCN_STRING "tcn"
56
57 #define FLAG_TC 0x01
58 #define FLAG_TC_ACK 0x80
59 #define FLAG_TC_STRING "topology-change"
60 #define FLAG_TC_ACK_STRING "topology-change-ack"
61
brstp_print_help(void)62 static void brstp_print_help(void)
63 {
64 printf(
65 "stp options:\n"
66 "[!] --stp-type type : BPDU type\n"
67 "[!] --stp-flags flag : control flag\n"
68 "[!] --stp-root-prio prio[:prio] : root priority (16-bit) range\n"
69 "[!] --stp-root-addr address[/mask] : MAC address of root\n"
70 "[!] --stp-root-cost cost[:cost] : root cost (32-bit) range\n"
71 "[!] --stp-sender-prio prio[:prio] : sender priority (16-bit) range\n"
72 "[!] --stp-sender-addr address[/mask] : MAC address of sender\n"
73 "[!] --stp-port port[:port] : port id (16-bit) range\n"
74 "[!] --stp-msg-age age[:age] : message age timer (16-bit) range\n"
75 "[!] --stp-max-age age[:age] : maximum age timer (16-bit) range\n"
76 "[!] --stp-hello-time time[:time] : hello time timer (16-bit) range\n"
77 "[!] --stp-forward-delay delay[:delay]: forward delay timer (16-bit) range\n"
78 " Recognized BPDU type strings:\n"
79 " \"config\": configuration BPDU (=0)\n"
80 " \"tcn\" : topology change notification BPDU (=0x80)\n"
81 " Recognized control flag strings:\n"
82 " \"topology-change\" : topology change flag (0x01)\n"
83 " \"topology-change-ack\": topology change acknowledgement flag (0x80)");
84 }
85
print_range(unsigned int l,unsigned int u)86 static void print_range(unsigned int l, unsigned int u)
87 {
88 if (l == u)
89 printf("%u", l);
90 else
91 printf("%u:%u", l, u);
92 }
93
brstp_parse(struct xt_option_call * cb)94 static void brstp_parse(struct xt_option_call *cb)
95 {
96 struct ebt_stp_info *stpinfo = cb->data;
97 char *end = NULL;
98 long int i;
99
100 xtables_option_parse(cb);
101
102 stpinfo->bitmask |= 1 << cb->entry->id;
103 if (cb->invert)
104 stpinfo->invflags |= 1 << cb->entry->id;
105
106 switch (cb->entry->id) {
107 case O_TYPE:
108 i = strtol(cb->arg, &end, 0);
109 if (i < 0 || i > 255 || *end != '\0') {
110 if (!strcasecmp(cb->arg, BPDU_TYPE_CONFIG_STRING))
111 stpinfo->type = BPDU_TYPE_CONFIG;
112 else if (!strcasecmp(cb->arg, BPDU_TYPE_TCN_STRING))
113 stpinfo->type = BPDU_TYPE_TCN;
114 else
115 xtables_error(PARAMETER_PROBLEM, "Bad --stp-type argument");
116 } else
117 stpinfo->type = i;
118 break;
119 case O_FLAGS:
120 i = strtol(cb->arg, &end, 0);
121 if (i < 0 || i > 255 || *end != '\0') {
122 if (!strcasecmp(cb->arg, FLAG_TC_STRING))
123 stpinfo->config.flags = FLAG_TC;
124 else if (!strcasecmp(cb->arg, FLAG_TC_ACK_STRING))
125 stpinfo->config.flags = FLAG_TC_ACK;
126 else
127 xtables_error(PARAMETER_PROBLEM, "Bad --stp-flags argument");
128 } else
129 stpinfo->config.flags = i;
130 break;
131 case O_RADDR:
132 memcpy(stpinfo->config.root_addr, cb->val.ethermac, ETH_ALEN);
133 memcpy(stpinfo->config.root_addrmsk,
134 cb->val.ethermacmask, ETH_ALEN);
135 break;
136 case O_SADDR:
137 memcpy(stpinfo->config.sender_addr, cb->val.ethermac, ETH_ALEN);
138 memcpy(stpinfo->config.sender_addrmsk,
139 cb->val.ethermacmask, ETH_ALEN);
140 break;
141
142 #define RANGE_ASSIGN(fname, val) { \
143 stpinfo->config.fname##l = val[0]; \
144 stpinfo->config.fname##u = cb->nvals > 1 ? val[1] : val[0]; \
145 }
146 case O_RPRIO:
147 RANGE_ASSIGN(root_prio, cb->val.u16_range);
148 break;
149 case O_RCOST:
150 RANGE_ASSIGN(root_cost, cb->val.u32_range);
151 break;
152 case O_SPRIO:
153 RANGE_ASSIGN(sender_prio, cb->val.u16_range);
154 break;
155 case O_PORT:
156 RANGE_ASSIGN(port, cb->val.u16_range);
157 break;
158 case O_MSGAGE:
159 RANGE_ASSIGN(msg_age, cb->val.u16_range);
160 break;
161 case O_MAXAGE:
162 RANGE_ASSIGN(max_age, cb->val.u16_range);
163 break;
164 case O_HTIME:
165 RANGE_ASSIGN(hello_time, cb->val.u16_range);
166 break;
167 case O_FWDD:
168 RANGE_ASSIGN(forward_delay, cb->val.u16_range);
169 break;
170 #undef RANGE_ASSIGN
171 }
172 }
173
brstp_print(const void * ip,const struct xt_entry_match * match,int numeric)174 static void brstp_print(const void *ip, const struct xt_entry_match *match,
175 int numeric)
176 {
177 const struct ebt_stp_info *stpinfo = (struct ebt_stp_info *)match->data;
178 const struct ebt_stp_config_info *c = &(stpinfo->config);
179 int i;
180
181 for (i = 0; (1 << i) < EBT_STP_MASK; i++) {
182 if (!(stpinfo->bitmask & (1 << i)))
183 continue;
184 printf("%s--%s ",
185 (stpinfo->invflags & (1 << i)) ? "! " : "",
186 brstp_opts[i].name);
187 if (EBT_STP_TYPE == (1 << i)) {
188 if (stpinfo->type == BPDU_TYPE_CONFIG)
189 printf("%s", BPDU_TYPE_CONFIG_STRING);
190 else if (stpinfo->type == BPDU_TYPE_TCN)
191 printf("%s", BPDU_TYPE_TCN_STRING);
192 else
193 printf("%d", stpinfo->type);
194 } else if (EBT_STP_FLAGS == (1 << i)) {
195 if (c->flags == FLAG_TC)
196 printf("%s", FLAG_TC_STRING);
197 else if (c->flags == FLAG_TC_ACK)
198 printf("%s", FLAG_TC_ACK_STRING);
199 else
200 printf("%d", c->flags);
201 } else if (EBT_STP_ROOTPRIO == (1 << i))
202 print_range(c->root_priol, c->root_priou);
203 else if (EBT_STP_ROOTADDR == (1 << i))
204 xtables_print_mac_and_mask((unsigned char *)c->root_addr,
205 (unsigned char*)c->root_addrmsk);
206 else if (EBT_STP_ROOTCOST == (1 << i))
207 print_range(c->root_costl, c->root_costu);
208 else if (EBT_STP_SENDERPRIO == (1 << i))
209 print_range(c->sender_priol, c->sender_priou);
210 else if (EBT_STP_SENDERADDR == (1 << i))
211 xtables_print_mac_and_mask((unsigned char *)c->sender_addr,
212 (unsigned char *)c->sender_addrmsk);
213 else if (EBT_STP_PORT == (1 << i))
214 print_range(c->portl, c->portu);
215 else if (EBT_STP_MSGAGE == (1 << i))
216 print_range(c->msg_agel, c->msg_ageu);
217 else if (EBT_STP_MAXAGE == (1 << i))
218 print_range(c->max_agel, c->max_ageu);
219 else if (EBT_STP_HELLOTIME == (1 << i))
220 print_range(c->hello_timel, c->hello_timeu);
221 else if (EBT_STP_FWDD == (1 << i))
222 print_range(c->forward_delayl, c->forward_delayu);
223 printf(" ");
224 }
225 }
226
227 static struct xtables_match brstp_match = {
228 .name = "stp",
229 .version = XTABLES_VERSION,
230 .family = NFPROTO_BRIDGE,
231 .size = sizeof(struct ebt_stp_info),
232 .help = brstp_print_help,
233 .x6_parse = brstp_parse,
234 .print = brstp_print,
235 .x6_options = brstp_opts
236 };
237
_init(void)238 void _init(void)
239 {
240 xtables_register_match(&brstp_match);
241 }
242