117623Smpp/*-
217623Smpp * SPDX-License-Identifier: BSD-4-Clause
317623Smpp *
417623Smpp * Copyright 2001 Wasabi Systems, Inc.
517623Smpp * All rights reserved.
617623Smpp *
717623Smpp * Written by Jason R. Thorpe for Wasabi Systems, Inc.
817623Smpp *
917623Smpp * Redistribution and use in source and binary forms, with or without
1017623Smpp * modification, are permitted provided that the following conditions
1117623Smpp * are met:
1217623Smpp * 1. Redistributions of source code must retain the above copyright
1317623Smpp *    notice, this list of conditions and the following disclaimer.
1417623Smpp * 2. Redistributions in binary form must reproduce the above copyright
1517623Smpp *    notice, this list of conditions and the following disclaimer in the
1617623Smpp *    documentation and/or other materials provided with the distribution.
1717623Smpp * 3. All advertising materials mentioning features or use of this software
1817623Smpp *    must display the following acknowledgement:
1917623Smpp *	This product includes software developed for the NetBSD Project by
2017623Smpp *	Wasabi Systems, Inc.
2117623Smpp * 4. The name of Wasabi Systems, Inc. may not be used to endorse
2217623Smpp *    or promote products derived from this software without specific prior
2317623Smpp *    written permission.
2417623Smpp *
2517623Smpp * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
2617623Smpp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2717623Smpp * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2817623Smpp * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
2917623Smpp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3017623Smpp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3117623Smpp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3250476Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3323466Sjmg * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3417623Smpp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3517623Smpp * POSSIBILITY OF SUCH DAMAGE.
3617623Smpp */
3717623Smpp
3817623Smpp#include <sys/param.h>
3917623Smpp#include <sys/ioctl.h>
4017623Smpp#include <sys/socket.h>
4117623Smpp#include <sys/sockio.h>
4217623Smpp
4317623Smpp#include <stdlib.h>
44131530Sru#include <unistd.h>
45131530Sru
4617623Smpp#include <net/ethernet.h>
4717623Smpp#include <net/if.h>
4817623Smpp#include <net/if_bridgevar.h>
49131530Sru#include <net/route.h>
50131530Sru
5117623Smpp#include <ctype.h>
52131530Sru#include <stdio.h>
53131530Sru#include <string.h>
5417623Smpp#include <stdlib.h>
5517623Smpp#include <unistd.h>
5617623Smpp#include <err.h>
5717623Smpp#include <errno.h>
5817623Smpp
5979727Sschweikh#include <libifconfig.h>
6017623Smpp
6117623Smpp#include "ifconfig.h"
6217623Smpp
6317623Smppstatic const char *stpstates[] = { STP_STATES };
6417623Smppstatic const char *stpproto[] = { STP_PROTOS };
6517623Smppstatic const char *stproles[] = { STP_ROLES };
6617623Smpp
6779727Sschweikhstatic int
6871895Sruget_val(const char *cp, u_long *valp)
6917623Smpp{
7017623Smpp	char *endptr;
7117623Smpp	u_long val;
7217623Smpp
7344096Sjkoshy	errno = 0;
7444096Sjkoshy	val = strtoul(cp, &endptr, 0);
7544096Sjkoshy	if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
7644096Sjkoshy		return (-1);
7744096Sjkoshy
7879727Sschweikh	*valp = val;
7944096Sjkoshy	return (0);
8044096Sjkoshy}
8144096Sjkoshy
8244096Sjkoshystatic int
8344096Sjkoshydo_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
8444096Sjkoshy{
8544096Sjkoshy	struct ifdrv ifd = {};
8679727Sschweikh
8744096Sjkoshy	strlcpy(ifd.ifd_name, ctx->ifname, sizeof(ifd.ifd_name));
8844096Sjkoshy	ifd.ifd_cmd = op;
8917623Smpp	ifd.ifd_len = argsize;
9017623Smpp	ifd.ifd_data = arg;
9117623Smpp
9217623Smpp	return (ioctl_ctx(ctx, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
9317623Smpp}
9417623Smpp
9544096Sjkoshystatic void
9617623Smppdo_bridgeflag(if_ctx *ctx, const char *ifs, int flag, int set)
9717623Smpp{
98	struct ifbreq req;
99
100	strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
101
102	if (do_cmd(ctx, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
103		err(1, "unable to get bridge flags");
104
105	if (set)
106		req.ifbr_ifsflags |= flag;
107	else
108		req.ifbr_ifsflags &= ~flag;
109
110	if (do_cmd(ctx, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
111		err(1, "unable to set bridge flags");
112}
113
114static void
115bridge_addresses(if_ctx *ctx, const char *prefix)
116{
117	struct ifbaconf ifbac;
118	struct ifbareq *ifba;
119	char *inbuf = NULL, *ninbuf;
120	size_t len = 8192;
121	struct ether_addr ea;
122
123	for (;;) {
124		ninbuf = realloc(inbuf, len);
125		if (ninbuf == NULL)
126			err(1, "unable to allocate address buffer");
127		ifbac.ifbac_len = len;
128		ifbac.ifbac_buf = inbuf = ninbuf;
129		if (do_cmd(ctx, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
130			err(1, "unable to get address cache");
131		if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
132			break;
133		len *= 2;
134	}
135
136	for (unsigned long i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
137		ifba = ifbac.ifbac_req + i;
138		memcpy(ea.octet, ifba->ifba_dst,
139		    sizeof(ea.octet));
140		printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
141		    ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
142		printb("flags", ifba->ifba_flags, IFBAFBITS);
143		printf("\n");
144	}
145
146	free(inbuf);
147}
148
149static void
150bridge_status(if_ctx *ctx)
151{
152	struct ifconfig_bridge_status *bridge;
153	struct ifbropreq *params;
154	const char *pad, *prefix;
155	uint8_t lladdr[ETHER_ADDR_LEN];
156	uint16_t bprio;
157
158	if (ifconfig_bridge_get_bridge_status(lifh, ctx->ifname, &bridge) == -1)
159		return;
160
161	params = bridge->params;
162
163	PV2ID(params->ifbop_bridgeid, bprio, lladdr);
164	printf("\tid %s priority %u hellotime %u fwddelay %u\n",
165	    ether_ntoa((struct ether_addr *)lladdr),
166	    params->ifbop_priority,
167	    params->ifbop_hellotime,
168	    params->ifbop_fwddelay);
169	printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
170	    params->ifbop_maxage,
171	    params->ifbop_holdcount,
172	    stpproto[params->ifbop_protocol],
173	    bridge->cache_size,
174	    bridge->cache_lifetime);
175	PV2ID(params->ifbop_designated_root, bprio, lladdr);
176	printf("\troot id %s priority %d ifcost %u port %u\n",
177	    ether_ntoa((struct ether_addr *)lladdr),
178	    bprio,
179	    params->ifbop_root_path_cost,
180	    params->ifbop_root_port & 0xfff);
181
182	prefix = "\tmember: ";
183	pad    = "\t        ";
184	for (size_t i = 0; i < bridge->members_count; ++i) {
185		struct ifbreq *member = &bridge->members[i];
186
187		printf("%s%s ", prefix, member->ifbr_ifsname);
188		printb("flags", member->ifbr_ifsflags, IFBIFBITS);
189		printf("\n%s", pad);
190		printf("ifmaxaddr %u port %u priority %u path cost %u",
191		    member->ifbr_addrmax,
192		    member->ifbr_portno,
193		    member->ifbr_priority,
194		    member->ifbr_path_cost);
195		if (member->ifbr_ifsflags & IFBIF_STP) {
196			uint8_t proto = member->ifbr_proto;
197			uint8_t role = member->ifbr_role;
198			uint8_t state = member->ifbr_state;
199
200			if (proto < nitems(stpproto))
201				printf(" proto %s", stpproto[proto]);
202			else
203				printf(" <unknown proto %d>", proto);
204			printf("\n%s", pad);
205			if (role < nitems(stproles))
206				printf("role %s", stproles[role]);
207			else
208				printf("<unknown role %d>", role);
209			if (state < nitems(stpstates))
210				printf(" state %s", stpstates[state]);
211			else
212				printf(" <unknown state %d>", state);
213		}
214		printf("\n");
215	}
216
217	ifconfig_bridge_free_bridge_status(bridge);
218}
219
220static void
221setbridge_add(if_ctx *ctx, const char *val, int dummy __unused)
222{
223	struct ifbreq req;
224
225	memset(&req, 0, sizeof(req));
226	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
227	if (do_cmd(ctx, BRDGADD, &req, sizeof(req), 1) < 0)
228		err(1, "BRDGADD %s",  val);
229}
230
231static void
232setbridge_delete(if_ctx *ctx, const char *val, int dummy __unused)
233{
234	struct ifbreq req;
235
236	memset(&req, 0, sizeof(req));
237	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
238	if (do_cmd(ctx, BRDGDEL, &req, sizeof(req), 1) < 0)
239		err(1, "BRDGDEL %s",  val);
240}
241
242static void
243setbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
244{
245
246	do_bridgeflag(ctx, val, IFBIF_DISCOVER, 1);
247}
248
249static void
250unsetbridge_discover(if_ctx *ctx, const char *val, int dummy __unused)
251{
252
253	do_bridgeflag(ctx, val, IFBIF_DISCOVER, 0);
254}
255
256static void
257setbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
258{
259
260	do_bridgeflag(ctx, val, IFBIF_LEARNING,  1);
261}
262
263static void
264unsetbridge_learn(if_ctx *ctx, const char *val, int dummy __unused)
265{
266
267	do_bridgeflag(ctx, val, IFBIF_LEARNING,  0);
268}
269
270static void
271setbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
272{
273
274	do_bridgeflag(ctx, val, IFBIF_STICKY,  1);
275}
276
277static void
278unsetbridge_sticky(if_ctx *ctx, const char *val, int dummy __unused)
279{
280
281	do_bridgeflag(ctx, val, IFBIF_STICKY,  0);
282}
283
284static void
285setbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
286{
287	struct ifbreq req;
288
289	memset(&req, 0, sizeof(req));
290	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
291	if (do_cmd(ctx, BRDGADDS, &req, sizeof(req), 1) < 0)
292		err(1, "BRDGADDS %s",  val);
293}
294
295static void
296unsetbridge_span(if_ctx *ctx, const char *val, int dummy __unused)
297{
298	struct ifbreq req;
299
300	memset(&req, 0, sizeof(req));
301	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
302	if (do_cmd(ctx, BRDGDELS, &req, sizeof(req), 1) < 0)
303		err(1, "BRDGDELS %s",  val);
304}
305
306static void
307setbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
308{
309
310	do_bridgeflag(ctx, val, IFBIF_STP, 1);
311}
312
313static void
314unsetbridge_stp(if_ctx *ctx, const char *val, int dummy __unused)
315{
316
317	do_bridgeflag(ctx, val, IFBIF_STP, 0);
318}
319
320static void
321setbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
322{
323	do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 1);
324}
325
326static void
327unsetbridge_edge(if_ctx *ctx, const char *val, int dummy __unused)
328{
329	do_bridgeflag(ctx, val, IFBIF_BSTP_EDGE, 0);
330}
331
332static void
333setbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
334{
335	do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 1);
336}
337
338static void
339unsetbridge_autoedge(if_ctx *ctx, const char *val, int dummy __unused)
340{
341	do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOEDGE, 0);
342}
343
344static void
345setbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
346{
347	do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 1);
348}
349
350static void
351unsetbridge_ptp(if_ctx *ctx, const char *val, int dummy __unused)
352{
353	do_bridgeflag(ctx, val, IFBIF_BSTP_PTP, 0);
354}
355
356static void
357setbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
358{
359	do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 1);
360}
361
362static void
363unsetbridge_autoptp(if_ctx *ctx, const char *val, int dummy __unused)
364{
365	do_bridgeflag(ctx, val, IFBIF_BSTP_AUTOPTP, 0);
366}
367
368static void
369setbridge_flush(if_ctx *ctx, const char *val __unused, int dummy __unused)
370{
371	struct ifbreq req;
372
373	memset(&req, 0, sizeof(req));
374	req.ifbr_ifsflags = IFBF_FLUSHDYN;
375	if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
376		err(1, "BRDGFLUSH");
377}
378
379static void
380setbridge_flushall(if_ctx *ctx, const char *val __unused, int dummy __unused)
381{
382	struct ifbreq req;
383
384	memset(&req, 0, sizeof(req));
385	req.ifbr_ifsflags = IFBF_FLUSHALL;
386	if (do_cmd(ctx, BRDGFLUSH, &req, sizeof(req), 1) < 0)
387		err(1, "BRDGFLUSH");
388}
389
390static void
391setbridge_static(if_ctx *ctx, const char *val, const char *mac)
392{
393	struct ifbareq req;
394	struct ether_addr *ea;
395
396	memset(&req, 0, sizeof(req));
397	strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
398
399	ea = ether_aton(mac);
400	if (ea == NULL)
401		errx(1, "%s: invalid address: %s", val, mac);
402
403	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
404	req.ifba_flags = IFBAF_STATIC;
405	req.ifba_vlan = 0; /* XXX allow user to specify */
406
407	if (do_cmd(ctx, BRDGSADDR, &req, sizeof(req), 1) < 0)
408		err(1, "BRDGSADDR %s",  val);
409}
410
411static void
412setbridge_deladdr(if_ctx *ctx, const char *val, int dummy __unused)
413{
414	struct ifbareq req;
415	struct ether_addr *ea;
416
417	memset(&req, 0, sizeof(req));
418
419	ea = ether_aton(val);
420	if (ea == NULL)
421		errx(1, "invalid address: %s",  val);
422
423	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
424
425	if (do_cmd(ctx, BRDGDADDR, &req, sizeof(req), 1) < 0)
426		err(1, "BRDGDADDR %s",  val);
427}
428
429static void
430setbridge_addr(if_ctx *ctx, const char *val __unused, int dummy __unused)
431{
432
433	bridge_addresses(ctx, "");
434}
435
436static void
437setbridge_maxaddr(if_ctx *ctx, const char *arg, int dummy __unused)
438{
439	struct ifbrparam param;
440	u_long val;
441
442	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
443		errx(1, "invalid value: %s",  arg);
444
445	param.ifbrp_csize = val & 0xffffffff;
446
447	if (do_cmd(ctx, BRDGSCACHE, &param, sizeof(param), 1) < 0)
448		err(1, "BRDGSCACHE %s",  arg);
449}
450
451static void
452setbridge_hellotime(if_ctx *ctx, const char *arg, int dummy __unused)
453{
454	struct ifbrparam param;
455	u_long val;
456
457	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
458		errx(1, "invalid value: %s",  arg);
459
460	param.ifbrp_hellotime = val & 0xff;
461
462	if (do_cmd(ctx, BRDGSHT, &param, sizeof(param), 1) < 0)
463		err(1, "BRDGSHT %s",  arg);
464}
465
466static void
467setbridge_fwddelay(if_ctx *ctx, const char *arg, int dummy __unused)
468{
469	struct ifbrparam param;
470	u_long val;
471
472	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
473		errx(1, "invalid value: %s",  arg);
474
475	param.ifbrp_fwddelay = val & 0xff;
476
477	if (do_cmd(ctx, BRDGSFD, &param, sizeof(param), 1) < 0)
478		err(1, "BRDGSFD %s",  arg);
479}
480
481static void
482setbridge_maxage(if_ctx *ctx, const char *arg, int dummy __unused)
483{
484	struct ifbrparam param;
485	u_long val;
486
487	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
488		errx(1, "invalid value: %s",  arg);
489
490	param.ifbrp_maxage = val & 0xff;
491
492	if (do_cmd(ctx, BRDGSMA, &param, sizeof(param), 1) < 0)
493		err(1, "BRDGSMA %s",  arg);
494}
495
496static void
497setbridge_priority(if_ctx *ctx, const char *arg, int dummy __unused)
498{
499	struct ifbrparam param;
500	u_long val;
501
502	if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
503		errx(1, "invalid value: %s",  arg);
504
505	param.ifbrp_prio = val & 0xffff;
506
507	if (do_cmd(ctx, BRDGSPRI, &param, sizeof(param), 1) < 0)
508		err(1, "BRDGSPRI %s",  arg);
509}
510
511static void
512setbridge_protocol(if_ctx *ctx, const char *arg, int dummy __unused)
513{
514	struct ifbrparam param;
515
516	if (strcasecmp(arg, "stp") == 0) {
517		param.ifbrp_proto = 0;
518	} else if (strcasecmp(arg, "rstp") == 0) {
519		param.ifbrp_proto = 2;
520	} else {
521		errx(1, "unknown stp protocol");
522	}
523
524	if (do_cmd(ctx, BRDGSPROTO, &param, sizeof(param), 1) < 0)
525		err(1, "BRDGSPROTO %s",  arg);
526}
527
528static void
529setbridge_holdcount(if_ctx *ctx, const char *arg, int dummy __unused)
530{
531	struct ifbrparam param;
532	u_long val;
533
534	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
535		errx(1, "invalid value: %s",  arg);
536
537	param.ifbrp_txhc = val & 0xff;
538
539	if (do_cmd(ctx, BRDGSTXHC, &param, sizeof(param), 1) < 0)
540		err(1, "BRDGSTXHC %s",  arg);
541}
542
543static void
544setbridge_ifpriority(if_ctx *ctx, const char *ifn, const char *pri)
545{
546	struct ifbreq req;
547	u_long val;
548
549	memset(&req, 0, sizeof(req));
550
551	if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
552		errx(1, "invalid value: %s",  pri);
553
554	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
555	req.ifbr_priority = val & 0xff;
556
557	if (do_cmd(ctx, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
558		err(1, "BRDGSIFPRIO %s",  pri);
559}
560
561static void
562setbridge_ifpathcost(if_ctx *ctx, const char *ifn, const char *cost)
563{
564	struct ifbreq req;
565	u_long val;
566
567	memset(&req, 0, sizeof(req));
568
569	if (get_val(cost, &val) < 0)
570		errx(1, "invalid value: %s",  cost);
571
572	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
573	req.ifbr_path_cost = val;
574
575	if (do_cmd(ctx, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
576		err(1, "BRDGSIFCOST %s",  cost);
577}
578
579static void
580setbridge_ifmaxaddr(if_ctx *ctx, const char *ifn, const char *arg)
581{
582	struct ifbreq req;
583	u_long val;
584
585	memset(&req, 0, sizeof(req));
586
587	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
588		errx(1, "invalid value: %s",  arg);
589
590	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
591	req.ifbr_addrmax = val & 0xffffffff;
592
593	if (do_cmd(ctx, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
594		err(1, "BRDGSIFAMAX %s",  arg);
595}
596
597static void
598setbridge_timeout(if_ctx *ctx, const char *arg, int dummy __unused)
599{
600	struct ifbrparam param;
601	u_long val;
602
603	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
604		errx(1, "invalid value: %s",  arg);
605
606	param.ifbrp_ctime = val & 0xffffffff;
607
608	if (do_cmd(ctx, BRDGSTO, &param, sizeof(param), 1) < 0)
609		err(1, "BRDGSTO %s",  arg);
610}
611
612static void
613setbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
614{
615
616	do_bridgeflag(ctx, val, IFBIF_PRIVATE, 1);
617}
618
619static void
620unsetbridge_private(if_ctx *ctx, const char *val, int dummy __unused)
621{
622
623	do_bridgeflag(ctx, val, IFBIF_PRIVATE, 0);
624}
625
626static struct cmd bridge_cmds[] = {
627	DEF_CMD_ARG("addm",		setbridge_add),
628	DEF_CMD_ARG("deletem",		setbridge_delete),
629	DEF_CMD_ARG("discover",		setbridge_discover),
630	DEF_CMD_ARG("-discover",	unsetbridge_discover),
631	DEF_CMD_ARG("learn",		setbridge_learn),
632	DEF_CMD_ARG("-learn",		unsetbridge_learn),
633	DEF_CMD_ARG("sticky",		setbridge_sticky),
634	DEF_CMD_ARG("-sticky",		unsetbridge_sticky),
635	DEF_CMD_ARG("span",		setbridge_span),
636	DEF_CMD_ARG("-span",		unsetbridge_span),
637	DEF_CMD_ARG("stp",		setbridge_stp),
638	DEF_CMD_ARG("-stp",		unsetbridge_stp),
639	DEF_CMD_ARG("edge",		setbridge_edge),
640	DEF_CMD_ARG("-edge",		unsetbridge_edge),
641	DEF_CMD_ARG("autoedge",		setbridge_autoedge),
642	DEF_CMD_ARG("-autoedge",	unsetbridge_autoedge),
643	DEF_CMD_ARG("ptp",		setbridge_ptp),
644	DEF_CMD_ARG("-ptp",		unsetbridge_ptp),
645	DEF_CMD_ARG("autoptp",		setbridge_autoptp),
646	DEF_CMD_ARG("-autoptp",		unsetbridge_autoptp),
647	DEF_CMD("flush", 0,		setbridge_flush),
648	DEF_CMD("flushall", 0,		setbridge_flushall),
649	DEF_CMD_ARG2("static",		setbridge_static),
650	DEF_CMD_ARG("deladdr",		setbridge_deladdr),
651	DEF_CMD("addr",	 1,		setbridge_addr),
652	DEF_CMD_ARG("maxaddr",		setbridge_maxaddr),
653	DEF_CMD_ARG("hellotime",	setbridge_hellotime),
654	DEF_CMD_ARG("fwddelay",		setbridge_fwddelay),
655	DEF_CMD_ARG("maxage",		setbridge_maxage),
656	DEF_CMD_ARG("priority",		setbridge_priority),
657	DEF_CMD_ARG("proto",		setbridge_protocol),
658	DEF_CMD_ARG("holdcnt",		setbridge_holdcount),
659	DEF_CMD_ARG2("ifpriority",	setbridge_ifpriority),
660	DEF_CMD_ARG2("ifpathcost",	setbridge_ifpathcost),
661	DEF_CMD_ARG2("ifmaxaddr",	setbridge_ifmaxaddr),
662	DEF_CMD_ARG("timeout",		setbridge_timeout),
663	DEF_CMD_ARG("private",		setbridge_private),
664	DEF_CMD_ARG("-private",		unsetbridge_private),
665};
666static struct afswtch af_bridge = {
667	.af_name	= "af_bridge",
668	.af_af		= AF_UNSPEC,
669	.af_other_status = bridge_status,
670};
671
672static __constructor void
673bridge_ctor(void)
674{
675	for (size_t i = 0; i < nitems(bridge_cmds);  i++)
676		cmd_register(&bridge_cmds[i]);
677	af_register(&af_bridge);
678}
679