1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/param.h>
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42
43 #include <stdlib.h>
44 #include <unistd.h>
45
46 #include <net/ethernet.h>
47 #include <net/if.h>
48 #include <net/if_bridgevar.h>
49 #include <net/route.h>
50
51 #include <ctype.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <err.h>
57 #include <errno.h>
58
59 #include <libifconfig.h>
60
61 #include "ifconfig.h"
62
63 static int parse_vlans(ifbvlan_set_t *set, const char *str);
64 static int get_val(const char *cp, u_long *valp);
65 static int get_vlan_id(const char *cp, ether_vlanid_t *valp);
66
67 static const char *stpstates[] = { STP_STATES };
68 static const char *stpproto[] = { STP_PROTOS };
69 static const char *stproles[] = { STP_ROLES };
70
71 static int
get_val(const char * cp,u_long * valp)72 get_val(const char *cp, u_long *valp)
73 {
74 char *endptr;
75 u_long val;
76
77 errno = 0;
78 val = strtoul(cp, &endptr, 0);
79 if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
80 return (-1);
81
82 *valp = val;
83 return (0);
84 }
85
86 static int
get_vlan_id(const char * cp,ether_vlanid_t * valp)87 get_vlan_id(const char *cp, ether_vlanid_t *valp)
88 {
89 u_long val;
90
91 if (get_val(cp, &val) == -1)
92 return (-1);
93 if (val < DOT1Q_VID_MIN || val > DOT1Q_VID_MAX)
94 return (-1);
95
96 *valp = (ether_vlanid_t)val;
97 return (0);
98 }
99
100 static int
do_cmd(if_ctx * ctx,u_long op,void * arg,size_t argsize,int set)101 do_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
102 {
103 struct ifdrv ifd = {};
104
105 strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name));
106 ifd.ifd_cmd = op;
107 ifd.ifd_len = argsize;
108 ifd.ifd_data = arg;
109
110 return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
111 }
112
113 static void
do_bridgeflag(if_ctx * ctx,const char * ifs,int flag,int set)114 do_bridgeflag(if_ctx *ctx, const char *ifs, int flag, int set)
115 {
116 struct ifbreq req;
117
118 strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
119
120 if (do_cmd(ctx, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
121 err(1, "unable to get bridge flags");
122
123 if (set)
124 req.ifbr_ifsflags |= flag;
125 else
126 req.ifbr_ifsflags &= ~flag;
127
128 if (do_cmd(ctx, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
129 err(1, "unable to set bridge flags");
130 }
131
132 static void
bridge_addresses(if_ctx * ctx,const char * prefix)133 bridge_addresses(if_ctx *ctx, const char *prefix)
134 {
135 struct ifbaconf ifbac;
136 struct ifbareq *ifba;
137 char *inbuf = NULL, *ninbuf;
138 size_t len = 8192;
139 struct ether_addr ea;
140
141 for (;;) {
142 ninbuf = realloc(inbuf, len);
143 if (ninbuf == NULL)
144 err(1, "unable to allocate address buffer");
145 ifbac.ifbac_len = len;
146 ifbac.ifbac_buf = inbuf = ninbuf;
147 if (do_cmd(ctx, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
148 err(1, "unable to get address cache");
149 if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
150 break;
151 len *= 2;
152 }
153
154 for (unsigned long i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
155 ifba = ifbac.ifbac_req + i;
156 memcpy(ea.octet, ifba->ifba_dst,
157 sizeof(ea.octet));
158 printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
159 ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
160 printb("flags", ifba->ifba_flags, IFBAFBITS);
161 printf("\n");
162 }
163
164 free(inbuf);
165 }
166
167 static void
print_vlans(ifbvlan_set_t * vlans)168 print_vlans(ifbvlan_set_t *vlans)
169 {
170 unsigned printed = 0;
171
172 for (unsigned vlan = DOT1Q_VID_MIN; vlan <= DOT1Q_VID_MAX;) {
173 unsigned last;
174
175 if (!BRVLAN_TEST(vlans, vlan)) {
176 ++vlan;
177 continue;
178 }
179
180 last = vlan;
181 while (last < DOT1Q_VID_MAX && BRVLAN_TEST(vlans, last + 1))
182 ++last;
183
184 if (printed == 0)
185 printf(" tagged ");
186 else
187 printf(",");
188
189 printf("%u", vlan);
190 if (last != vlan)
191 printf("-%u", last);
192 ++printed;
193 vlan = last + 1;
194 }
195 }
196
197 static char const *
vlan_proto_name(uint16_t proto)198 vlan_proto_name(uint16_t proto)
199 {
200 switch (proto) {
201 case 0:
202 return "none";
203 case ETHERTYPE_VLAN:
204 return "802.1q";
205 case ETHERTYPE_QINQ:
206 return "802.1ad";
207 default:
208 return "unknown";
209 }
210 }
211
212 static void
bridge_status(if_ctx * ctx)213 bridge_status(if_ctx *ctx)
214 {
215 struct ifconfig_bridge_status *bridge;
216 struct ifbropreq *params;
217 const char *pad, *prefix;
218 uint8_t lladdr[ETHER_ADDR_LEN];
219 uint16_t bprio;
220
221 if (ifconfig_bridge_get_bridge_status(lifh, ctx->ifname, &bridge) == -1)
222 return;
223
224 params = bridge->params;
225
226 PV2ID(params->ifbop_bridgeid, bprio, lladdr);
227 printf("\tid %s priority %u hellotime %u fwddelay %u\n",
228 ether_ntoa((struct ether_addr *)lladdr),
229 params->ifbop_priority,
230 params->ifbop_hellotime,
231 params->ifbop_fwddelay);
232 printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
233 params->ifbop_maxage,
234 params->ifbop_holdcount,
235 stpproto[params->ifbop_protocol],
236 bridge->cache_size,
237 bridge->cache_lifetime);
238 PV2ID(params->ifbop_designated_root, bprio, lladdr);
239 printf("\troot id %s priority %d ifcost %u port %u\n",
240 ether_ntoa((struct ether_addr *)lladdr),
241 bprio,
242 params->ifbop_root_path_cost,
243 params->ifbop_root_port & 0xfff);
244
245 printb("\tbridge flags", bridge->flags, IFBRFBITS);
246 if (bridge->defpvid)
247 printf(" defuntagged=%u", (unsigned) bridge->defpvid);
248 printf("\n");
249
250 prefix = "\tmember: ";
251 pad = "\t ";
252 for (size_t i = 0; i < bridge->members_count; ++i) {
253 struct ifbreq *member = &bridge->members[i];
254
255 printf("%s%s ", prefix, member->ifbr_ifsname);
256 printb("flags", member->ifbr_ifsflags, IFBIFBITS);
257 printf("\n%s", pad);
258 if (member->ifbr_addrmax != 0)
259 printf("ifmaxaddr %u ", member->ifbr_addrmax);
260 printf("port %u priority %u path cost %u",
261 member->ifbr_portno,
262 member->ifbr_priority,
263 member->ifbr_path_cost);
264 if (member->ifbr_ifsflags & IFBIF_STP) {
265 uint8_t proto = member->ifbr_proto;
266 uint8_t role = member->ifbr_role;
267 uint8_t state = member->ifbr_state;
268
269 if (proto < nitems(stpproto))
270 printf(" proto %s", stpproto[proto]);
271 else
272 printf(" <unknown proto %d>", proto);
273 printf("\n%s", pad);
274 if (role < nitems(stproles))
275 printf("role %s", stproles[role]);
276 else
277 printf("<unknown role %d>", role);
278 if (state < nitems(stpstates))
279 printf(" state %s", stpstates[state]);
280 else
281 printf(" <unknown state %d>", state);
282 }
283 if (member->ifbr_vlanproto != 0)
284 printf(" vlan protocol %s",
285 vlan_proto_name(member->ifbr_vlanproto));
286 if (member->ifbr_pvid != 0)
287 printf(" untagged %u", (unsigned)member->ifbr_pvid);
288 print_vlans(&bridge->member_vlans[i]);
289 printf("\n");
290 }
291
292 ifconfig_bridge_free_bridge_status(bridge);
293 }
294
295 static int
setbridge_add(if_ctx * ctx,int argc,const char * const * argv)296 setbridge_add(if_ctx *ctx, int argc, const char *const *argv)
297 {
298 struct ifbreq req;
299 struct ifbif_vlan_req vlreq;
300 int oargc = argc;
301
302 memset(&req, 0, sizeof(req));
303 memset(&vlreq, 0, sizeof(vlreq));
304
305 if (argc < 1)
306 errx(1, "usage: addm <interface> [opts ...]");
307
308 strlcpy(req.ifbr_ifsname, argv[0], sizeof(req.ifbr_ifsname));
309 --argc; ++argv;
310
311 while (argc) {
312 if (strcmp(argv[0], "untagged") == 0) {
313 if (argc < 2)
314 errx(1, "usage: untagged <vlan id>");
315
316 if (get_vlan_id(argv[1], &req.ifbr_pvid) < 0)
317 errx(1, "invalid VLAN identifier: %s", argv[1]);
318
319 argc -= 2;
320 argv += 2;
321 } else if (strcmp(argv[0], "tagged") == 0) {
322 if (argc < 2)
323 errx(1, "usage: tagged <vlan set>");
324
325 vlreq.bv_op = BRDG_VLAN_OP_SET;
326 strlcpy(vlreq.bv_ifname, req.ifbr_ifsname,
327 sizeof(vlreq.bv_ifname));
328 if (parse_vlans(&vlreq.bv_set, argv[1]) != 0)
329 errx(1, "invalid vlan set: %s", argv[1]);
330
331 argc -= 2;
332 argv += 2;
333 } else {
334 break;
335 }
336 }
337
338 if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0)
339 err(1, "BRDGADD %s", req.ifbr_ifsname);
340
341 if (req.ifbr_pvid != 0 &&
342 do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
343 err(1, "BRDGSIFPVID %s %u", req.ifbr_ifsname,
344 (unsigned)req.ifbr_pvid);
345
346 if (vlreq.bv_op != 0 &&
347 do_cmd(ctx, BRDGSIFVLANSET, &vlreq, sizeof(vlreq), 1) < 0)
348 err(1, "BRDGSIFVLANSET %s", req.ifbr_ifsname);
349
350 return (oargc - argc);
351 }
352
353 static void
setbridge_delete(if_ctx * ctx,const char * val,int dummy __unused)354 setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused)
355 {
356 struct ifbreq req;
357
358 memset(&req, 0, sizeof(req));
359 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
360 if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0)
361 err(1, "BRDGDEL %s", val);
362 }
363
364 static void
setbridge_discover(if_ctx * ctx,const char * val,int dummy __unused)365 setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
366 {
367
368 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1);
369 }
370
371 static void
unsetbridge_discover(if_ctx * ctx,const char * val,int dummy __unused)372 unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
373 {
374
375 do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0);
376 }
377
378 static void
setbridge_learn(if_ctx * ctx,const char * val,int dummy __unused)379 setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
380 {
381
382 do_bridgeflag(ctx, val, IFBIF_LEARNING, 1);
383 }
384
385 static void
unsetbridge_learn(if_ctx * ctx,const char * val,int dummy __unused)386 unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
387 {
388
389 do_bridgeflag(ctx, val, IFBIF_LEARNING, 0);
390 }
391
392 static void
setbridge_sticky(if_ctx * ctx,const char * val,int dummy __unused)393 setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
394 {
395
396 do_bridgeflag(ctx, val, IFBIF_STICKY, 1);
397 }
398
399 static void
unsetbridge_sticky(if_ctx * ctx,const char * val,int dummy __unused)400 unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
401 {
402
403 do_bridgeflag(ctx, val, IFBIF_STICKY, 0);
404 }
405
406 static void
setbridge_span(if_ctx * ctx,const char * val,int dummy __unused)407 setbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
408 {
409 struct ifbreq req;
410
411 memset(&req, 0, sizeof(req));
412 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
413 if (do_cmd(ctx, BRDGADDS, &req, sizeof(req), 1) < 0)
414 err(1, "BRDGADDS %s", val);
415 }
416
417 static void
unsetbridge_span(if_ctx * ctx,const char * val,int dummy __unused)418 unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
419 {
420 struct ifbreq req;
421
422 memset(&req, 0, sizeof(req));
423 strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
424 if (do_cmd(ctx, BRDGDELS, &req, sizeof(req), 1) < 0)
425 err(1, "BRDGDELS %s", val);
426 }
427
428 static void
setbridge_stp(if_ctx * ctx,const char * val,int dummy __unused)429 setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
430 {
431
432 do_bridgeflag(ctx, val, IFBIF_STP, 1);
433 }
434
435 static void
unsetbridge_stp(if_ctx * ctx,const char * val,int dummy __unused)436 unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
437 {
438
439 do_bridgeflag(ctx, val, IFBIF_STP, 0);
440 }
441
442 static void
setbridge_edge(if_ctx * ctx,const char * val,int dummy __unused)443 setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
444 {
445 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1);
446 }
447
448 static void
unsetbridge_edge(if_ctx * ctx,const char * val,int dummy __unused)449 unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
450 {
451 do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0);
452 }
453
454 static void
setbridge_autoedge(if_ctx * ctx,const char * val,int dummy __unused)455 setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
456 {
457 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1);
458 }
459
460 static void
unsetbridge_autoedge(if_ctx * ctx,const char * val,int dummy __unused)461 unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
462 {
463 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0);
464 }
465
466 static void
setbridge_ptp(if_ctx * ctx,const char * val,int dummy __unused)467 setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
468 {
469 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1);
470 }
471
472 static void
unsetbridge_ptp(if_ctx * ctx,const char * val,int dummy __unused)473 unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
474 {
475 do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0);
476 }
477
478 static void
setbridge_autoptp(if_ctx * ctx,const char * val,int dummy __unused)479 setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
480 {
481 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1);
482 }
483
484 static void
unsetbridge_autoptp(if_ctx * ctx,const char * val,int dummy __unused)485 unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
486 {
487 do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0);
488 }
489
490 static void
setbridge_flush(if_ctx * ctx,const char * val __unused,int dummy __unused)491 setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused)
492 {
493 struct ifbreq req;
494
495 memset(&req, 0, sizeof(req));
496 req.ifbr_ifsflags = IFBF_FLUSHDYN;
497 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
498 err(1, "BRDGFLUSH");
499 }
500
501 static void
setbridge_flushall(if_ctx * ctx,const char * val __unused,int dummy __unused)502 setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused)
503 {
504 struct ifbreq req;
505
506 memset(&req, 0, sizeof(req));
507 req.ifbr_ifsflags = IFBF_FLUSHALL;
508 if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
509 err(1, "BRDGFLUSH");
510 }
511
512 static int
setbridge_static(if_ctx * ctx,int argc,const char * const * argv)513 setbridge_static(if_ctx *ctx, int argc, const char *const *argv)
514 {
515 struct ifbareq req;
516 struct ether_addr *ea;
517 int arg;
518
519 if (argc < 2)
520 errx(1, "usage: static <interface> <address> [vlan <id>]");
521 arg = 0;
522
523 memset(&req, 0, sizeof(req));
524 req.ifba_flags = IFBAF_STATIC;
525
526 strlcpy(req.ifba_ifsname, argv[arg], sizeof(req.ifba_ifsname));
527 ++arg;
528
529 ea = ether_aton(argv[arg]);
530 if (ea == NULL)
531 errx(1, "invalid address: %s", argv[arg]);
532 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
533 ++arg;
534
535 req.ifba_vlan = 0;
536 if (argc > 2 && strcmp(argv[arg], "vlan") == 0) {
537 if (argc < 3)
538 errx(1, "usage: static <interface> <address> "
539 "[vlan <id>]");
540 ++arg;
541
542 if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
543 errx(1, "invalid vlan id: %s", argv[arg]);
544 ++arg;
545 }
546
547 if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0)
548 err(1, "BRDGSADDR");
549 return arg;
550 }
551
552 static int
setbridge_deladdr(if_ctx * ctx,int argc,const char * const * argv)553 setbridge_deladdr(if_ctx *ctx, int argc, const char *const *argv)
554 {
555 struct ifbareq req;
556 struct ether_addr *ea;
557 int arg;
558
559 if (argc < 1)
560 errx(1, "usage: deladdr <address> [vlan <id>]");
561 arg = 0;
562
563 memset(&req, 0, sizeof(req));
564
565 ea = ether_aton(argv[arg]);
566 if (ea == NULL)
567 errx(1, "invalid address: %s", argv[arg]);
568 memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
569 ++arg;
570
571 req.ifba_vlan = 0;
572 if (argc >= 2 && strcmp(argv[arg], "vlan") == 0) {
573 if (argc < 3)
574 errx(1, "usage: deladdr <address> [vlan <id>]");
575 ++arg;
576
577 if (get_vlan_id(argv[arg], &req.ifba_vlan) < 0)
578 errx(1, "invalid vlan id: %s", argv[arg]);
579 ++arg;
580 }
581
582 if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0)
583 err(1, "BRDGDADDR");
584
585 return arg;
586 }
587
588 static void
setbridge_addr(if_ctx * ctx,const char * val __unused,int dummy __unused)589 setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused)
590 {
591 bridge_addresses(ctx, "");
592 }
593
594 static void
setbridge_maxaddr(if_ctx * ctx,const char * arg,int dummy __unused)595 setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused)
596 {
597 struct ifbrparam param;
598 u_long val;
599
600 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
601 errx(1, "invalid value: %s", arg);
602
603 param.ifbrp_csize = val & 0xffffffff;
604
605 if (do_cmd(ctx, BRDGSCACHE, ¶m, sizeof(param), 1) < 0)
606 err(1, "BRDGSCACHE %s", arg);
607 }
608
609 static void
setbridge_hellotime(if_ctx * ctx,const char * arg,int dummy __unused)610 setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused)
611 {
612 struct ifbrparam param;
613 u_long val;
614
615 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
616 errx(1, "invalid value: %s", arg);
617
618 param.ifbrp_hellotime = val & 0xff;
619
620 if (do_cmd(ctx, BRDGSHT, ¶m, sizeof(param), 1) < 0)
621 err(1, "BRDGSHT %s", arg);
622 }
623
624 static void
setbridge_fwddelay(if_ctx * ctx,const char * arg,int dummy __unused)625 setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused)
626 {
627 struct ifbrparam param;
628 u_long val;
629
630 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
631 errx(1, "invalid value: %s", arg);
632
633 param.ifbrp_fwddelay = val & 0xff;
634
635 if (do_cmd(ctx, BRDGSFD, ¶m, sizeof(param), 1) < 0)
636 err(1, "BRDGSFD %s", arg);
637 }
638
639 static void
setbridge_maxage(if_ctx * ctx,const char * arg,int dummy __unused)640 setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused)
641 {
642 struct ifbrparam param;
643 u_long val;
644
645 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
646 errx(1, "invalid value: %s", arg);
647
648 param.ifbrp_maxage = val & 0xff;
649
650 if (do_cmd(ctx, BRDGSMA, ¶m, sizeof(param), 1) < 0)
651 err(1, "BRDGSMA %s", arg);
652 }
653
654 static void
setbridge_priority(if_ctx * ctx,const char * arg,int dummy __unused)655 setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused)
656 {
657 struct ifbrparam param;
658 u_long val;
659
660 if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
661 errx(1, "invalid value: %s", arg);
662
663 param.ifbrp_prio = val & 0xffff;
664
665 if (do_cmd(ctx, BRDGSPRI, ¶m, sizeof(param), 1) < 0)
666 err(1, "BRDGSPRI %s", arg);
667 }
668
669 static void
setbridge_protocol(if_ctx * ctx,const char * arg,int dummy __unused)670 setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused)
671 {
672 struct ifbrparam param;
673
674 if (strcasecmp(arg, "stp") == 0) {
675 param.ifbrp_proto = 0;
676 } else if (strcasecmp(arg, "rstp") == 0) {
677 param.ifbrp_proto = 2;
678 } else {
679 errx(1, "unknown stp protocol");
680 }
681
682 if (do_cmd(ctx, BRDGSPROTO, ¶m, sizeof(param), 1) < 0)
683 err(1, "BRDGSPROTO %s", arg);
684 }
685
686 static void
setbridge_holdcount(if_ctx * ctx,const char * arg,int dummy __unused)687 setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused)
688 {
689 struct ifbrparam param;
690 u_long val;
691
692 if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
693 errx(1, "invalid value: %s", arg);
694
695 param.ifbrp_txhc = val & 0xff;
696
697 if (do_cmd(ctx, BRDGSTXHC, ¶m, sizeof(param), 1) < 0)
698 err(1, "BRDGSTXHC %s", arg);
699 }
700
701 static void
setbridge_ifpriority(if_ctx * ctx,const char * ifn,const char * pri)702 setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri)
703 {
704 struct ifbreq req;
705 u_long val;
706
707 memset(&req, 0, sizeof(req));
708
709 if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
710 errx(1, "invalid value: %s", pri);
711
712 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
713 req.ifbr_priority = val & 0xff;
714
715 if (do_cmd(ctx, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
716 err(1, "BRDGSIFPRIO %s", pri);
717 }
718
719 static void
setbridge_ifpathcost(if_ctx * ctx,const char * ifn,const char * cost)720 setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost)
721 {
722 struct ifbreq req;
723 u_long val;
724
725 memset(&req, 0, sizeof(req));
726
727 if (get_val(cost, &val) < 0)
728 errx(1, "invalid value: %s", cost);
729
730 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
731 req.ifbr_path_cost = val;
732
733 if (do_cmd(ctx, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
734 err(1, "BRDGSIFCOST %s", cost);
735 }
736
737 static void
setbridge_ifuntagged(if_ctx * ctx,const char * ifn,const char * vlanid)738 setbridge_ifuntagged(if_ctx *ctx, const char *ifn, const char *vlanid)
739 {
740 struct ifbreq req;
741
742 memset(&req, 0, sizeof(req));
743 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
744
745 if (get_vlan_id(vlanid, &req.ifbr_pvid) < 0)
746 errx(1, "invalid VLAN identifier: %s", vlanid);
747
748 if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
749 err(1, "BRDGSIFPVID %s", vlanid);
750 }
751
752 static void
unsetbridge_ifuntagged(if_ctx * ctx,const char * ifn,int dummy __unused)753 unsetbridge_ifuntagged(if_ctx *ctx, const char *ifn, int dummy __unused)
754 {
755 struct ifbreq req;
756
757 memset(&req, 0, sizeof(req));
758
759 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
760 req.ifbr_pvid = 0;
761
762 if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
763 err(1, "BRDGSIFPVID");
764 }
765
766 static void
setbridge_ifmaxaddr(if_ctx * ctx,const char * ifn,const char * arg)767 setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg)
768 {
769 struct ifbreq req;
770 u_long val;
771
772 memset(&req, 0, sizeof(req));
773
774 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
775 errx(1, "invalid value: %s", arg);
776
777 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
778 req.ifbr_addrmax = val & 0xffffffff;
779
780 if (do_cmd(ctx, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
781 err(1, "BRDGSIFAMAX %s", arg);
782 }
783
784 static void
setbridge_timeout(if_ctx * ctx,const char * arg,int dummy __unused)785 setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
786 {
787 struct ifbrparam param;
788 u_long val;
789
790 if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
791 errx(1, "invalid value: %s", arg);
792
793 param.ifbrp_ctime = val & 0xffffffff;
794
795 if (do_cmd(ctx, BRDGSTO, ¶m, sizeof(param), 1) < 0)
796 err(1, "BRDGSTO %s", arg);
797 }
798
799 static void
setbridge_private(if_ctx * ctx,const char * val,int dummy __unused)800 setbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
801 {
802 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1);
803 }
804
805 static void
unsetbridge_private(if_ctx * ctx,const char * val,int dummy __unused)806 unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
807 {
808 do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0);
809 }
810
811 static int
parse_vlans(ifbvlan_set_t * set,const char * str)812 parse_vlans(ifbvlan_set_t *set, const char *str)
813 {
814 char *s, *token;
815
816 /* "none" means the empty vlan set */
817 if (strcmp(str, "none") == 0) {
818 __BIT_ZERO(BRVLAN_SETSIZE, set);
819 return (0);
820 }
821
822 /* "all" means all vlans, except for 0 and 4095 which are reserved */
823 if (strcmp(str, "all") == 0) {
824 __BIT_FILL(BRVLAN_SETSIZE, set);
825 BRVLAN_CLR(set, DOT1Q_VID_NULL);
826 BRVLAN_CLR(set, DOT1Q_VID_RSVD_IMPL);
827 return (0);
828 }
829
830 if ((s = strdup(str)) == NULL)
831 return (-1);
832
833 while ((token = strsep(&s, ",")) != NULL) {
834 unsigned long first, last;
835 char *p, *lastp;
836
837 if ((lastp = strchr(token, '-')) != NULL)
838 *lastp++ = '\0';
839
840 first = last = strtoul(token, &p, 10);
841 if (*p != '\0')
842 goto err;
843 if (first < DOT1Q_VID_MIN || first > DOT1Q_VID_MAX)
844 goto err;
845
846 if (lastp) {
847 last = strtoul(lastp, &p, 10);
848 if (*p != '\0')
849 goto err;
850 if (last < DOT1Q_VID_MIN || last > DOT1Q_VID_MAX ||
851 last < first)
852 goto err;
853 }
854
855 for (unsigned vlan = first; vlan <= last; ++vlan)
856 BRVLAN_SET(set, vlan);
857 }
858
859 free(s);
860 return (0);
861
862 err:
863 free(s);
864 return (-1);
865 }
866
867 static void
set_bridge_vlanset(if_ctx * ctx,const char * ifn,const char * vlans,int op)868 set_bridge_vlanset(if_ctx *ctx, const char *ifn, const char *vlans, int op)
869 {
870 struct ifbif_vlan_req req;
871
872 memset(&req, 0, sizeof(req));
873
874 if (parse_vlans(&req.bv_set, vlans) != 0)
875 errx(1, "invalid vlan set: %s", vlans);
876
877 strlcpy(req.bv_ifname, ifn, sizeof(req.bv_ifname));
878 req.bv_op = op;
879
880 if (do_cmd(ctx, BRDGSIFVLANSET, &req, sizeof(req), 1) < 0)
881 err(1, "BRDGSIFVLANSET %s", vlans);
882 }
883
884 static void
setbridge_iftagged(if_ctx * ctx,const char * ifn,const char * vlans)885 setbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
886 {
887 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_SET);
888 }
889
890 static void
addbridge_iftagged(if_ctx * ctx,const char * ifn,const char * vlans)891 addbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
892 {
893 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_ADD);
894 }
895
896 static void
delbridge_iftagged(if_ctx * ctx,const char * ifn,const char * vlans)897 delbridge_iftagged(if_ctx *ctx, const char *ifn, const char *vlans)
898 {
899 set_bridge_vlanset(ctx, ifn, vlans, BRDG_VLAN_OP_DEL);
900 }
901
902 static void
setbridge_flags(if_ctx * ctx,const char * val __unused,int newflags)903 setbridge_flags(if_ctx *ctx, const char *val __unused, int newflags)
904 {
905 struct ifbrparam req;
906
907 if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0)
908 err(1, "BRDGGFLAGS");
909
910 req.ifbrp_flags |= (uint32_t)newflags;
911
912 if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0)
913 err(1, "BRDGSFLAGS");
914 }
915
916 static void
unsetbridge_flags(if_ctx * ctx,const char * val __unused,int newflags)917 unsetbridge_flags(if_ctx *ctx, const char *val __unused, int newflags)
918 {
919 struct ifbrparam req;
920
921 if (do_cmd(ctx, BRDGGFLAGS, &req, sizeof(req), 0) < 0)
922 err(1, "BRDGGFLAGS");
923
924 req.ifbrp_flags &= ~(uint32_t)newflags;
925
926 if (do_cmd(ctx, BRDGSFLAGS, &req, sizeof(req), 1) < 0)
927 err(1, "BRDGSFLAGS");
928 }
929
930 static void
setbridge_defuntagged(if_ctx * ctx,const char * arg,int dummy __unused)931 setbridge_defuntagged(if_ctx *ctx, const char *arg, int dummy __unused)
932 {
933 struct ifbrparam req;
934
935 memset(&req, 0, sizeof(req));
936 if (get_vlan_id(arg, &req.ifbrp_defpvid) < 0)
937 errx(1, "invalid vlan id: %s", arg);
938
939 if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0)
940 err(1, "BRDGSDEFPVID");
941 }
942
943 static void
unsetbridge_defuntagged(if_ctx * ctx,const char * val __unused,int dummy __unused)944 unsetbridge_defuntagged(if_ctx *ctx, const char *val __unused, int dummy __unused)
945 {
946 struct ifbrparam req;
947
948 memset(&req, 0, sizeof(req));
949 req.ifbrp_defpvid = 0;
950
951 if (do_cmd(ctx, BRDGSDEFPVID, &req, sizeof(req), 1) < 0)
952 err(1, "BRDGSDEFPVID");
953 }
954
955 static void
setbridge_qinq(if_ctx * ctx,const char * val,int dummy __unused)956 setbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused)
957 {
958 do_bridgeflag(ctx, val, IFBIF_QINQ, 1);
959 }
960
961 static void
unsetbridge_qinq(if_ctx * ctx,const char * val,int dummy __unused)962 unsetbridge_qinq(if_ctx *ctx, const char *val, int dummy __unused)
963 {
964 do_bridgeflag(ctx, val, IFBIF_QINQ, 0);
965 }
966
967 static void
setbridge_ifvlanproto(if_ctx * ctx,const char * ifname,const char * proto)968 setbridge_ifvlanproto(if_ctx *ctx, const char *ifname, const char *proto)
969 {
970 struct ifbreq req;
971
972 memset(&req, 0, sizeof(req));
973 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
974
975 if (strcmp(proto, "802.1q") == 0)
976 req.ifbr_vlanproto = ETHERTYPE_VLAN;
977 else if (strcmp(proto, "802.1ad") == 0)
978 req.ifbr_vlanproto = ETHERTYPE_QINQ;
979 else
980 errx(1, "unrecognised VLAN protocol: %s", proto);
981
982 if (do_cmd(ctx, BRDGSIFVLANPROTO, &req, sizeof(req), 1) < 0)
983 err(1, "BRDGSIFVLANPROTO");
984 }
985
986 static struct cmd bridge_cmds[] = {
987 DEF_CMD_VARG("addm", setbridge_add),
988 DEF_CMD_ARG("deletem", setbridge_delete),
989 DEF_CMD_ARG("discover", setbridge_discover),
990 DEF_CMD_ARG("-discover", unsetbridge_discover),
991 DEF_CMD_ARG("learn", setbridge_learn),
992 DEF_CMD_ARG("-learn", unsetbridge_learn),
993 DEF_CMD_ARG("sticky", setbridge_sticky),
994 DEF_CMD_ARG("-sticky", unsetbridge_sticky),
995 DEF_CMD_ARG("span", setbridge_span),
996 DEF_CMD_ARG("-span", unsetbridge_span),
997 DEF_CMD_ARG("stp", setbridge_stp),
998 DEF_CMD_ARG("-stp", unsetbridge_stp),
999 DEF_CMD_ARG("edge", setbridge_edge),
1000 DEF_CMD_ARG("-edge", unsetbridge_edge),
1001 DEF_CMD_ARG("autoedge", setbridge_autoedge),
1002 DEF_CMD_ARG("-autoedge", unsetbridge_autoedge),
1003 DEF_CMD_ARG("ptp", setbridge_ptp),
1004 DEF_CMD_ARG("-ptp", unsetbridge_ptp),
1005 DEF_CMD_ARG("autoptp", setbridge_autoptp),
1006 DEF_CMD_ARG("-autoptp", unsetbridge_autoptp),
1007 DEF_CMD("flush", 0, setbridge_flush),
1008 DEF_CMD("flushall", 0, setbridge_flushall),
1009 DEF_CMD_VARG("static", setbridge_static),
1010 DEF_CMD_VARG("deladdr", setbridge_deladdr),
1011 DEF_CMD("addr", 1, setbridge_addr),
1012 DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
1013 DEF_CMD_ARG("hellotime", setbridge_hellotime),
1014 DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
1015 DEF_CMD_ARG("maxage", setbridge_maxage),
1016 DEF_CMD_ARG("priority", setbridge_priority),
1017 DEF_CMD_ARG("proto", setbridge_protocol),
1018 DEF_CMD_ARG("holdcnt", setbridge_holdcount),
1019 DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
1020 DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
1021 DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr),
1022 DEF_CMD_ARG2("ifuntagged", setbridge_ifuntagged),
1023 DEF_CMD_ARG("-ifuntagged", unsetbridge_ifuntagged),
1024 DEF_CMD_ARG2("iftagged", setbridge_iftagged),
1025 DEF_CMD_ARG2("+iftagged", addbridge_iftagged),
1026 DEF_CMD_ARG2("-iftagged", delbridge_iftagged),
1027 DEF_CMD_ARG2("ifvlanproto", setbridge_ifvlanproto),
1028 DEF_CMD_ARG("timeout", setbridge_timeout),
1029 DEF_CMD_ARG("private", setbridge_private),
1030 DEF_CMD_ARG("-private", unsetbridge_private),
1031 DEF_CMD("vlanfilter", (int32_t)IFBRF_VLANFILTER,
1032 setbridge_flags),
1033 DEF_CMD("-vlanfilter", (int32_t)IFBRF_VLANFILTER,
1034 unsetbridge_flags),
1035 DEF_CMD_ARG("defuntagged", setbridge_defuntagged),
1036 DEF_CMD("-defuntagged", 0, unsetbridge_defuntagged),
1037 DEF_CMD("defqinq", (int32_t)IFBRF_DEFQINQ,
1038 setbridge_flags),
1039 DEF_CMD("-defqinq", (int32_t)IFBRF_DEFQINQ,
1040 unsetbridge_flags),
1041 DEF_CMD_ARG("qinq", setbridge_qinq),
1042 DEF_CMD_ARG("-qinq", unsetbridge_qinq),
1043 };
1044
1045 static struct afswtch af_bridge = {
1046 .af_name = "af_bridge",
1047 .af_af = AF_UNSPEC,
1048 .af_other_status = bridge_status,
1049 };
1050
1051 static __constructor void
bridge_ctor(void)1052 bridge_ctor(void)
1053 {
1054 for (size_t i = 0; i < nitems(bridge_cmds); i++)
1055 cmd_register(&bridge_cmds[i]);
1056 af_register(&af_bridge);
1057 }
1058