xref: /freebsd/sbin/ifconfig/ifbridge.c (revision c41469a89f74e921ccbab09074c7b24edacbcc85)
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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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, &param, 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