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#ifndef lint
39static const char rcsid[] =
40  "$FreeBSD$";
41#endif /* not lint */
42
43#include <sys/param.h>
44#include <sys/ioctl.h>
45#include <sys/socket.h>
46#include <sys/sockio.h>
47
48#include <stdlib.h>
49#include <unistd.h>
50
51#include <net/ethernet.h>
52#include <net/if.h>
53#include <net/if_bridgevar.h>
54#include <net/route.h>
55
56#include <ctype.h>
57#include <stdio.h>
58#include <string.h>
59#include <stdlib.h>
60#include <unistd.h>
61#include <err.h>
62#include <errno.h>
63
64#include <libifconfig.h>
65
66#include "ifconfig.h"
67
68static const char *stpstates[] = { STP_STATES };
69static const char *stpproto[] = { STP_PROTOS };
70static const char *stproles[] = { STP_ROLES };
71
72static int
73get_val(const char *cp, u_long *valp)
74{
75	char *endptr;
76	u_long val;
77
78	errno = 0;
79	val = strtoul(cp, &endptr, 0);
80	if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
81		return (-1);
82
83	*valp = val;
84	return (0);
85}
86
87static int
88do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
89{
90	struct ifdrv ifd;
91
92	memset(&ifd, 0, sizeof(ifd));
93
94	strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
95	ifd.ifd_cmd = op;
96	ifd.ifd_len = argsize;
97	ifd.ifd_data = arg;
98
99	return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
100}
101
102static void
103do_bridgeflag(int sock, const char *ifs, int flag, int set)
104{
105	struct ifbreq req;
106
107	strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
108
109	if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
110		err(1, "unable to get bridge flags");
111
112	if (set)
113		req.ifbr_ifsflags |= flag;
114	else
115		req.ifbr_ifsflags &= ~flag;
116
117	if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
118		err(1, "unable to set bridge flags");
119}
120
121static void
122bridge_addresses(int s, const char *prefix)
123{
124	struct ifbaconf ifbac;
125	struct ifbareq *ifba;
126	char *inbuf = NULL, *ninbuf;
127	int i, len = 8192;
128	struct ether_addr ea;
129
130	for (;;) {
131		ninbuf = realloc(inbuf, len);
132		if (ninbuf == NULL)
133			err(1, "unable to allocate address buffer");
134		ifbac.ifbac_len = len;
135		ifbac.ifbac_buf = inbuf = ninbuf;
136		if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
137			err(1, "unable to get address cache");
138		if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
139			break;
140		len *= 2;
141	}
142
143	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
144		ifba = ifbac.ifbac_req + i;
145		memcpy(ea.octet, ifba->ifba_dst,
146		    sizeof(ea.octet));
147		printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
148		    ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
149		printb("flags", ifba->ifba_flags, IFBAFBITS);
150		printf("\n");
151	}
152
153	free(inbuf);
154}
155
156static void
157bridge_status(int s)
158{
159	struct ifconfig_bridge_status *bridge;
160	struct ifbropreq *params;
161	const char *pad, *prefix;
162	uint8_t lladdr[ETHER_ADDR_LEN];
163	uint16_t bprio;
164
165	if (ifconfig_bridge_get_bridge_status(lifh, name, &bridge) == -1)
166		return;
167
168	params = bridge->params;
169
170	PV2ID(params->ifbop_bridgeid, bprio, lladdr);
171	printf("\tid %s priority %u hellotime %u fwddelay %u\n",
172	    ether_ntoa((struct ether_addr *)lladdr),
173	    params->ifbop_priority,
174	    params->ifbop_hellotime,
175	    params->ifbop_fwddelay);
176	printf("\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
177	    params->ifbop_maxage,
178	    params->ifbop_holdcount,
179	    stpproto[params->ifbop_protocol],
180	    bridge->cache_size,
181	    bridge->cache_lifetime);
182	PV2ID(params->ifbop_designated_root, bprio, lladdr);
183	printf("\troot id %s priority %d ifcost %u port %u\n",
184	    ether_ntoa((struct ether_addr *)lladdr),
185	    bprio,
186	    params->ifbop_root_path_cost,
187	    params->ifbop_root_port & 0xfff);
188
189	prefix = "\tmember: ";
190	pad    = "\t        ";
191	for (size_t i = 0; i < bridge->members_count; ++i) {
192		struct ifbreq *member = &bridge->members[i];
193
194		printf("%s%s ", prefix, member->ifbr_ifsname);
195		printb("flags", member->ifbr_ifsflags, IFBIFBITS);
196		printf("\n%s", pad);
197		printf("ifmaxaddr %u port %u priority %u path cost %u",
198		    member->ifbr_addrmax,
199		    member->ifbr_portno,
200		    member->ifbr_priority,
201		    member->ifbr_path_cost);
202		if (member->ifbr_ifsflags & IFBIF_STP) {
203			uint8_t proto = member->ifbr_proto;
204			uint8_t role = member->ifbr_role;
205			uint8_t state = member->ifbr_state;
206
207			if (proto < nitems(stpproto))
208				printf(" proto %s", stpproto[proto]);
209			else
210				printf(" <unknown proto %d>", proto);
211			printf("\n%s", pad);
212			if (role < nitems(stproles))
213				printf("role %s", stproles[role]);
214			else
215				printf("<unknown role %d>", role);
216			if (state < nitems(stpstates))
217				printf(" state %s", stpstates[state]);
218			else
219				printf(" <unknown state %d>", state);
220		}
221		printf("\n");
222	}
223
224	ifconfig_bridge_free_bridge_status(bridge);
225}
226
227static void
228setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
229{
230	struct ifbreq req;
231
232	memset(&req, 0, sizeof(req));
233	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
234	if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
235		err(1, "BRDGADD %s",  val);
236}
237
238static void
239setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
240{
241	struct ifbreq req;
242
243	memset(&req, 0, sizeof(req));
244	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
245	if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
246		err(1, "BRDGDEL %s",  val);
247}
248
249static void
250setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
251{
252
253	do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
254}
255
256static void
257unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
258{
259
260	do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
261}
262
263static void
264setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
265{
266
267	do_bridgeflag(s, val, IFBIF_LEARNING,  1);
268}
269
270static void
271unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
272{
273
274	do_bridgeflag(s, val, IFBIF_LEARNING,  0);
275}
276
277static void
278setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
279{
280
281	do_bridgeflag(s, val, IFBIF_STICKY,  1);
282}
283
284static void
285unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
286{
287
288	do_bridgeflag(s, val, IFBIF_STICKY,  0);
289}
290
291static void
292setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
293{
294	struct ifbreq req;
295
296	memset(&req, 0, sizeof(req));
297	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
298	if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
299		err(1, "BRDGADDS %s",  val);
300}
301
302static void
303unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
304{
305	struct ifbreq req;
306
307	memset(&req, 0, sizeof(req));
308	strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
309	if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
310		err(1, "BRDGDELS %s",  val);
311}
312
313static void
314setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
315{
316
317	do_bridgeflag(s, val, IFBIF_STP, 1);
318}
319
320static void
321unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
322{
323
324	do_bridgeflag(s, val, IFBIF_STP, 0);
325}
326
327static void
328setbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
329{
330	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1);
331}
332
333static void
334unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
335{
336	do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0);
337}
338
339static void
340setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
341{
342	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1);
343}
344
345static void
346unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
347{
348	do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0);
349}
350
351static void
352setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
353{
354	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1);
355}
356
357static void
358unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
359{
360	do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0);
361}
362
363static void
364setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
365{
366	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1);
367}
368
369static void
370unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
371{
372	do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0);
373}
374
375static void
376setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
377{
378	struct ifbreq req;
379
380	memset(&req, 0, sizeof(req));
381	req.ifbr_ifsflags = IFBF_FLUSHDYN;
382	if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
383		err(1, "BRDGFLUSH");
384}
385
386static void
387setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
388{
389	struct ifbreq req;
390
391	memset(&req, 0, sizeof(req));
392	req.ifbr_ifsflags = IFBF_FLUSHALL;
393	if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
394		err(1, "BRDGFLUSH");
395}
396
397static void
398setbridge_static(const char *val, const char *mac, int s,
399    const struct afswtch *afp)
400{
401	struct ifbareq req;
402	struct ether_addr *ea;
403
404	memset(&req, 0, sizeof(req));
405	strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
406
407	ea = ether_aton(mac);
408	if (ea == NULL)
409		errx(1, "%s: invalid address: %s", val, mac);
410
411	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
412	req.ifba_flags = IFBAF_STATIC;
413	req.ifba_vlan = 1; /* XXX allow user to specify */
414
415	if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
416		err(1, "BRDGSADDR %s",  val);
417}
418
419static void
420setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
421{
422	struct ifbareq req;
423	struct ether_addr *ea;
424
425	memset(&req, 0, sizeof(req));
426
427	ea = ether_aton(val);
428	if (ea == NULL)
429		errx(1, "invalid address: %s",  val);
430
431	memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
432
433	if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
434		err(1, "BRDGDADDR %s",  val);
435}
436
437static void
438setbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
439{
440
441	bridge_addresses(s, "");
442}
443
444static void
445setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
446{
447	struct ifbrparam param;
448	u_long val;
449
450	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
451		errx(1, "invalid value: %s",  arg);
452
453	param.ifbrp_csize = val & 0xffffffff;
454
455	if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
456		err(1, "BRDGSCACHE %s",  arg);
457}
458
459static void
460setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
461{
462	struct ifbrparam param;
463	u_long val;
464
465	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
466		errx(1, "invalid value: %s",  arg);
467
468	param.ifbrp_hellotime = val & 0xff;
469
470	if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
471		err(1, "BRDGSHT %s",  arg);
472}
473
474static void
475setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
476{
477	struct ifbrparam param;
478	u_long val;
479
480	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
481		errx(1, "invalid value: %s",  arg);
482
483	param.ifbrp_fwddelay = val & 0xff;
484
485	if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
486		err(1, "BRDGSFD %s",  arg);
487}
488
489static void
490setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
491{
492	struct ifbrparam param;
493	u_long val;
494
495	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
496		errx(1, "invalid value: %s",  arg);
497
498	param.ifbrp_maxage = val & 0xff;
499
500	if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
501		err(1, "BRDGSMA %s",  arg);
502}
503
504static void
505setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
506{
507	struct ifbrparam param;
508	u_long val;
509
510	if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
511		errx(1, "invalid value: %s",  arg);
512
513	param.ifbrp_prio = val & 0xffff;
514
515	if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
516		err(1, "BRDGSPRI %s",  arg);
517}
518
519static void
520setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp)
521{
522	struct ifbrparam param;
523
524	if (strcasecmp(arg, "stp") == 0) {
525		param.ifbrp_proto = 0;
526	} else if (strcasecmp(arg, "rstp") == 0) {
527		param.ifbrp_proto = 2;
528	} else {
529		errx(1, "unknown stp protocol");
530	}
531
532	if (do_cmd(s, BRDGSPROTO, &param, sizeof(param), 1) < 0)
533		err(1, "BRDGSPROTO %s",  arg);
534}
535
536static void
537setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp)
538{
539	struct ifbrparam param;
540	u_long val;
541
542	if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
543		errx(1, "invalid value: %s",  arg);
544
545	param.ifbrp_txhc = val & 0xff;
546
547	if (do_cmd(s, BRDGSTXHC, &param, sizeof(param), 1) < 0)
548		err(1, "BRDGSTXHC %s",  arg);
549}
550
551static void
552setbridge_ifpriority(const char *ifn, const char *pri, int s,
553    const struct afswtch *afp)
554{
555	struct ifbreq req;
556	u_long val;
557
558	memset(&req, 0, sizeof(req));
559
560	if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
561		errx(1, "invalid value: %s",  pri);
562
563	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
564	req.ifbr_priority = val & 0xff;
565
566	if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
567		err(1, "BRDGSIFPRIO %s",  pri);
568}
569
570static void
571setbridge_ifpathcost(const char *ifn, const char *cost, int s,
572    const struct afswtch *afp)
573{
574	struct ifbreq req;
575	u_long val;
576
577	memset(&req, 0, sizeof(req));
578
579	if (get_val(cost, &val) < 0)
580		errx(1, "invalid value: %s",  cost);
581
582	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
583	req.ifbr_path_cost = val;
584
585	if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
586		err(1, "BRDGSIFCOST %s",  cost);
587}
588
589static void
590setbridge_ifmaxaddr(const char *ifn, const char *arg, int s,
591    const struct afswtch *afp)
592{
593	struct ifbreq req;
594	u_long val;
595
596	memset(&req, 0, sizeof(req));
597
598	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
599		errx(1, "invalid value: %s",  arg);
600
601	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
602	req.ifbr_addrmax = val & 0xffffffff;
603
604	if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
605		err(1, "BRDGSIFAMAX %s",  arg);
606}
607
608static void
609setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
610{
611	struct ifbrparam param;
612	u_long val;
613
614	if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
615		errx(1, "invalid value: %s",  arg);
616
617	param.ifbrp_ctime = val & 0xffffffff;
618
619	if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
620		err(1, "BRDGSTO %s",  arg);
621}
622
623static void
624setbridge_private(const char *val, int d, int s, const struct afswtch *afp)
625{
626
627	do_bridgeflag(s, val, IFBIF_PRIVATE, 1);
628}
629
630static void
631unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp)
632{
633
634	do_bridgeflag(s, val, IFBIF_PRIVATE, 0);
635}
636
637static struct cmd bridge_cmds[] = {
638	DEF_CMD_ARG("addm",		setbridge_add),
639	DEF_CMD_ARG("deletem",		setbridge_delete),
640	DEF_CMD_ARG("discover",		setbridge_discover),
641	DEF_CMD_ARG("-discover",	unsetbridge_discover),
642	DEF_CMD_ARG("learn",		setbridge_learn),
643	DEF_CMD_ARG("-learn",		unsetbridge_learn),
644	DEF_CMD_ARG("sticky",		setbridge_sticky),
645	DEF_CMD_ARG("-sticky",		unsetbridge_sticky),
646	DEF_CMD_ARG("span",		setbridge_span),
647	DEF_CMD_ARG("-span",		unsetbridge_span),
648	DEF_CMD_ARG("stp",		setbridge_stp),
649	DEF_CMD_ARG("-stp",		unsetbridge_stp),
650	DEF_CMD_ARG("edge",		setbridge_edge),
651	DEF_CMD_ARG("-edge",		unsetbridge_edge),
652	DEF_CMD_ARG("autoedge",		setbridge_autoedge),
653	DEF_CMD_ARG("-autoedge",	unsetbridge_autoedge),
654	DEF_CMD_ARG("ptp",		setbridge_ptp),
655	DEF_CMD_ARG("-ptp",		unsetbridge_ptp),
656	DEF_CMD_ARG("autoptp",		setbridge_autoptp),
657	DEF_CMD_ARG("-autoptp",		unsetbridge_autoptp),
658	DEF_CMD("flush", 0,		setbridge_flush),
659	DEF_CMD("flushall", 0,		setbridge_flushall),
660	DEF_CMD_ARG2("static",		setbridge_static),
661	DEF_CMD_ARG("deladdr",		setbridge_deladdr),
662	DEF_CMD("addr",	 1,		setbridge_addr),
663	DEF_CMD_ARG("maxaddr",		setbridge_maxaddr),
664	DEF_CMD_ARG("hellotime",	setbridge_hellotime),
665	DEF_CMD_ARG("fwddelay",		setbridge_fwddelay),
666	DEF_CMD_ARG("maxage",		setbridge_maxage),
667	DEF_CMD_ARG("priority",		setbridge_priority),
668	DEF_CMD_ARG("proto",		setbridge_protocol),
669	DEF_CMD_ARG("holdcnt",		setbridge_holdcount),
670	DEF_CMD_ARG2("ifpriority",	setbridge_ifpriority),
671	DEF_CMD_ARG2("ifpathcost",	setbridge_ifpathcost),
672	DEF_CMD_ARG2("ifmaxaddr",	setbridge_ifmaxaddr),
673	DEF_CMD_ARG("timeout",		setbridge_timeout),
674	DEF_CMD_ARG("private",		setbridge_private),
675	DEF_CMD_ARG("-private",		unsetbridge_private),
676};
677static struct afswtch af_bridge = {
678	.af_name	= "af_bridge",
679	.af_af		= AF_UNSPEC,
680	.af_other_status = bridge_status,
681};
682
683static __constructor void
684bridge_ctor(void)
685{
686	int i;
687
688	for (i = 0; i < nitems(bridge_cmds);  i++)
689		cmd_register(&bridge_cmds[i]);
690	af_register(&af_bridge);
691}
692