GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ifconfig/brconfig.c Lines: 24 514 4.7 %
Date: 2017-11-07 Branches: 6 294 2.0 %

Line Branch Exec Source
1
/*	$OpenBSD: brconfig.c,v 1.16 2017/07/31 02:32:11 jsg Exp $	*/
2
3
/*
4
 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
 * POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
#ifndef SMALL
30
31
#include <stdio.h>
32
#include <sys/types.h>
33
#include <sys/stdint.h>
34
#include <unistd.h>
35
#include <stdlib.h>
36
#include <sys/socket.h>
37
#include <sys/ioctl.h>
38
#include <net/if.h>
39
#include <net/if_dl.h>
40
#include <netinet/in.h>
41
#include <netinet/if_ether.h>
42
#include <net/if_bridge.h>
43
#include <netdb.h>
44
#include <string.h>
45
#include <err.h>
46
#include <errno.h>
47
#include <getopt.h>
48
#include <limits.h>
49
50
#include "brconfig.h"
51
52
void bridge_ifsetflag(const char *, u_int32_t);
53
void bridge_ifclrflag(const char *, u_int32_t);
54
55
void bridge_list(char *);
56
void bridge_cfg(const char *);
57
void bridge_badrule(int, char **, int);
58
void bridge_showrule(struct ifbrlreq *);
59
int is_switch(char *);
60
61
#define	IFBAFBITS	"\020\1STATIC"
62
#define	IFBIFBITS	\
63
"\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN\15LOCAL"
64
65
#define	PV2ID(pv, epri, eaddr)	do {					\
66
	epri	 = pv >> 48;						\
67
	eaddr[0] = pv >> 40;						\
68
	eaddr[1] = pv >> 32;						\
69
	eaddr[2] = pv >> 24;						\
70
	eaddr[3] = pv >> 16;						\
71
	eaddr[4] = pv >> 8;						\
72
	eaddr[5] = pv >> 0;						\
73
} while (0)
74
75
char *stpstates[] = {
76
	"disabled",
77
	"listening",
78
	"learning",
79
	"forwarding",
80
	"blocking",
81
	"discarding"
82
};
83
char *stpproto[] = {
84
	"stp",
85
	"(none)",
86
	"rstp",
87
};
88
char *stproles[] = {
89
	"disabled",
90
	"root",
91
	"designated",
92
	"alternate",
93
	"backup"
94
};
95
96
97
void
98
setdiscover(const char *val, int d)
99
{
100
	bridge_ifsetflag(val, IFBIF_DISCOVER);
101
}
102
103
void
104
unsetdiscover(const char *val, int d)
105
{
106
	bridge_ifclrflag(val, IFBIF_DISCOVER);
107
}
108
109
void
110
setblocknonip(const char *val, int d)
111
{
112
	bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
113
}
114
115
void
116
unsetblocknonip(const char *val, int d)
117
{
118
	bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
119
}
120
121
void
122
setlearn(const char *val, int d)
123
{
124
	bridge_ifsetflag(val, IFBIF_LEARNING);
125
}
126
127
void
128
unsetlearn(const char *val, int d)
129
{
130
	bridge_ifclrflag(val, IFBIF_LEARNING);
131
}
132
133
void
134
setstp(const char *val, int d)
135
{
136
	bridge_ifsetflag(val, IFBIF_STP);
137
}
138
139
void
140
unsetstp(const char *val, int d)
141
{
142
	bridge_ifclrflag(val, IFBIF_STP);
143
}
144
145
void
146
setedge(const char *val, int d)
147
{
148
	bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
149
}
150
151
void
152
unsetedge(const char *val, int d)
153
{
154
	bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
155
}
156
157
void
158
setautoedge(const char *val, int d)
159
{
160
	bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
161
}
162
163
void
164
unsetautoedge(const char *val, int d)
165
{
166
	bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
167
}
168
169
void
170
setptp(const char *val, int d)
171
{
172
	bridge_ifsetflag(val, IFBIF_BSTP_PTP);
173
}
174
175
void
176
unsetptp(const char *val, int d)
177
{
178
	bridge_ifclrflag(val, IFBIF_BSTP_PTP);
179
}
180
181
void
182
setautoptp(const char *val, int d)
183
{
184
	bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
185
}
186
187
void
188
unsetautoptp(const char *val, int d)
189
{
190
	bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
191
}
192
193
void
194
addlocal(const char *ifsname, int d)
195
{
196
	struct ifbreq breq;
197
198
	if (strncmp(ifsname, "vether", (sizeof("vether") - 1)) != 0)
199
		errx(1, "only vether can be local interface");
200
201
	/* Add local */
202
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
203
	strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname));
204
	if (ioctl(s, SIOCBRDGADDL, (caddr_t)&breq) < 0) {
205
		if (errno == EEXIST)
206
			return;
207
		else
208
			err(1, "%s: ioctl SIOCBRDGADDL %s", name, ifsname);
209
	}
210
}
211
212
void
213
bridge_ifsetflag(const char *ifsname, u_int32_t flag)
214
{
215
	struct ifbreq req;
216
217
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
218
	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
219
	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
220
		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
221
222
	req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK;
223
224
	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
225
		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
226
}
227
228
void
229
bridge_ifclrflag(const char *ifsname, u_int32_t flag)
230
{
231
	struct ifbreq req;
232
233
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
234
	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
235
236
	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
237
		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
238
239
	req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK);
240
241
	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
242
		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
243
}
244
245
void
246
bridge_flushall(const char *val, int p)
247
{
248
	struct ifbreq req;
249
250
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
251
	req.ifbr_ifsflags = IFBF_FLUSHALL;
252
	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
253
		err(1, "%s", name);
254
}
255
256
void
257
bridge_flush(const char *val, int p)
258
{
259
	struct ifbreq req;
260
261
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
262
	req.ifbr_ifsflags = IFBF_FLUSHDYN;
263
	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
264
		err(1, "%s", name);
265
}
266
267
void
268
bridge_cfg(const char *delim)
269
{
270
	struct ifbropreq ifbp;
271
	u_int16_t pri;
272
	u_int8_t ht, fd, ma, hc, proto;
273
	u_int8_t lladdr[ETHER_ADDR_LEN];
274
	u_int16_t bprio;
275
276
	strlcpy(ifbp.ifbop_name, name, sizeof(ifbp.ifbop_name));
277
	if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp))
278
		err(1, "%s", name);
279
	printf("%s", delim);
280
	pri = ifbp.ifbop_priority;
281
	ht = ifbp.ifbop_hellotime;
282
	fd = ifbp.ifbop_fwddelay;
283
	ma = ifbp.ifbop_maxage;
284
	hc = ifbp.ifbop_holdcount;
285
	proto = ifbp.ifbop_protocol;
286
287
	printf("priority %u hellotime %u fwddelay %u maxage %u "
288
	    "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]);
289
290
	if (aflag)
291
		return;
292
293
	PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr);
294
	printf("\tdesignated: id %s priority %u\n",
295
	    ether_ntoa((struct ether_addr *)lladdr), bprio);
296
297
	if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge)
298
		return;
299
300
	PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr);
301
	printf("\troot: id %s priority %u ifcost %u port %u\n",
302
	    ether_ntoa((struct ether_addr *)lladdr), bprio,
303
	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
304
}
305
306
void
307
bridge_list(char *delim)
308
{
309
	struct ifbreq *reqp;
310
	struct ifbifconf bifc;
311
	int i, len = 8192;
312
	char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb;
313
314
	while (1) {
315
		bifc.ifbic_len = len;
316
		inb = realloc(inbuf, len);
317
		if (inb == NULL)
318
			err(1, "malloc");
319
		bifc.ifbic_buf = inbuf = inb;
320
		strlcpy(bifc.ifbic_name, name, sizeof(bifc.ifbic_name));
321
		if (ioctl(s, SIOCBRDGIFS, &bifc) < 0)
322
			err(1, "%s", name);
323
		if (bifc.ifbic_len + sizeof(*reqp) < len)
324
			break;
325
		len *= 2;
326
	}
327
	for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
328
		reqp = bifc.ifbic_req + i;
329
		strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
330
		printf("%s%s ", delim, buf);
331
		printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
332
		printf("\n");
333
		if (reqp->ifbr_ifsflags & IFBIF_SPAN)
334
			continue;
335
		printf("\t\t");
336
		printf("port %u ifpriority %u ifcost %u",
337
		    reqp->ifbr_portno, reqp->ifbr_priority,
338
		    reqp->ifbr_path_cost);
339
		if (reqp->ifbr_ifsflags & IFBIF_STP)
340
			printf(" %s role %s",
341
			    stpstates[reqp->ifbr_state],
342
			    stproles[reqp->ifbr_role]);
343
		printf("\n");
344
		bridge_rules(buf, 1);
345
	}
346
	free(bifc.ifbic_buf);
347
}
348
349
void
350
bridge_add(const char *ifn, int d)
351
{
352
	struct ifbreq req;
353
354
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
355
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
356
	if (ioctl(s, SIOCBRDGADD, &req) < 0) {
357
		if (errno == EEXIST)
358
			return;
359
		err(1, "%s: %s", name, ifn);
360
	}
361
}
362
363
void
364
bridge_delete(const char *ifn, int d)
365
{
366
	struct ifbreq req;
367
368
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
369
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
370
	if (ioctl(s, SIOCBRDGDEL, &req) < 0)
371
		err(1, "%s: %s", name, ifn);
372
}
373
374
void
375
bridge_addspan(const char *ifn, int d)
376
{
377
	struct ifbreq req;
378
379
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
380
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
381
	if (ioctl(s, SIOCBRDGADDS, &req) < 0) {
382
		if (errno == EEXIST)
383
			return;
384
		err(1, "%s: %s", name, ifn);
385
	}
386
}
387
388
void
389
bridge_delspan(const char *ifn, int d)
390
{
391
	struct ifbreq req;
392
393
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
394
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
395
	if (ioctl(s, SIOCBRDGDELS, &req) < 0)
396
		err(1, "%s: %s", name, ifn);
397
}
398
399
void
400
bridge_timeout(const char *arg, int d)
401
{
402
	struct ifbrparam bp;
403
	long newtime;
404
	char *endptr;
405
406
	errno = 0;
407
	newtime = strtol(arg, &endptr, 0);
408
	if (arg[0] == '\0' || endptr[0] != '\0' ||
409
	    (newtime & ~INT_MAX) != 0L ||
410
	    (errno == ERANGE && newtime == LONG_MAX))
411
		errx(1, "invalid arg for timeout: %s", arg);
412
413
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
414
	bp.ifbrp_ctime = newtime;
415
	if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0)
416
		err(1, "%s", name);
417
}
418
419
void
420
bridge_maxage(const char *arg, int d)
421
{
422
	struct ifbrparam bp;
423
	unsigned long v;
424
	char *endptr;
425
426
	errno = 0;
427
	v = strtoul(arg, &endptr, 0);
428
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
429
	    (errno == ERANGE && v == ULONG_MAX))
430
		errx(1, "invalid arg for maxage: %s", arg);
431
432
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
433
	bp.ifbrp_maxage = v;
434
	if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0)
435
		err(1, "%s", name);
436
}
437
438
void
439
bridge_priority(const char *arg, int d)
440
{
441
	struct ifbrparam bp;
442
	unsigned long v;
443
	char *endptr;
444
445
	errno = 0;
446
	v = strtoul(arg, &endptr, 0);
447
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL ||
448
	    (errno == ERANGE && v == ULONG_MAX))
449
		errx(1, "invalid arg for spanpriority: %s", arg);
450
451
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
452
	bp.ifbrp_prio = v;
453
	if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0)
454
		err(1, "%s", name);
455
}
456
457
void
458
bridge_proto(const char *arg, int d)
459
{
460
	struct ifbrparam bp;
461
	int i, proto = -1;
462
463
	for (i = 0; i <= BSTP_PROTO_MAX; i++)
464
		if (strcmp(arg, stpproto[i]) == 0) {
465
			proto = i;
466
			break;
467
		}
468
	if (proto == -1)
469
		errx(1, "invalid arg for proto: %s", arg);
470
471
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
472
	bp.ifbrp_prio = proto;
473
	if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0)
474
		err(1, "%s", name);
475
}
476
477
void
478
bridge_fwddelay(const char *arg, int d)
479
{
480
	struct ifbrparam bp;
481
	unsigned long v;
482
	char *endptr;
483
484
	errno = 0;
485
	v = strtoul(arg, &endptr, 0);
486
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
487
	    (errno == ERANGE && v == ULONG_MAX))
488
		errx(1, "invalid arg for fwddelay: %s", arg);
489
490
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
491
	bp.ifbrp_fwddelay = v;
492
	if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0)
493
		err(1, "%s", name);
494
}
495
496
void
497
bridge_hellotime(const char *arg, int d)
498
{
499
	struct ifbrparam bp;
500
	unsigned long v;
501
	char *endptr;
502
503
	errno = 0;
504
	v = strtoul(arg, &endptr, 0);
505
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
506
	    (errno == ERANGE && v == ULONG_MAX))
507
		errx(1, "invalid arg for hellotime: %s", arg);
508
509
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
510
	bp.ifbrp_hellotime = v;
511
	if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0)
512
		err(1, "%s", name);
513
}
514
515
void
516
bridge_maxaddr(const char *arg, int d)
517
{
518
	struct ifbrparam bp;
519
	unsigned long newsize;
520
	char *endptr;
521
522
	errno = 0;
523
	newsize = strtoul(arg, &endptr, 0);
524
	if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL ||
525
	    (errno == ERANGE && newsize == ULONG_MAX))
526
		errx(1, "invalid arg for maxaddr: %s", arg);
527
528
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
529
	bp.ifbrp_csize = newsize;
530
	if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0)
531
		err(1, "%s", name);
532
}
533
534
void
535
bridge_deladdr(const char *addr, int d)
536
{
537
	struct ifbareq ifba;
538
	struct ether_addr *ea;
539
540
	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
541
	ea = ether_aton(addr);
542
	if (ea == NULL)
543
		err(1, "Invalid address: %s", addr);
544
545
	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
546
547
	if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0)
548
		err(1, "%s: %s", name, addr);
549
}
550
551
void
552
bridge_ifprio(const char *ifname, const char *val)
553
{
554
	struct ifbreq breq;
555
	unsigned long v;
556
	char *endptr;
557
558
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
559
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
560
561
	errno = 0;
562
	v = strtoul(val, &endptr, 0);
563
	if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
564
	    (errno == ERANGE && v == ULONG_MAX))
565
		err(1, "invalid arg for ifpriority: %s", val);
566
	breq.ifbr_priority = v;
567
568
	if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0)
569
		err(1, "%s: %s", name, val);
570
}
571
572
void
573
bridge_ifcost(const char *ifname, const char *val)
574
{
575
	struct ifbreq breq;
576
	unsigned long v;
577
	char *endptr;
578
579
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
580
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
581
582
	errno = 0;
583
	v = strtoul(val, &endptr, 0);
584
	if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffffffffUL ||
585
	    (errno == ERANGE && v == ULONG_MAX))
586
		errx(1, "invalid arg for ifcost: %s", val);
587
588
	breq.ifbr_path_cost = v;
589
590
	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
591
		err(1, "%s: %s", name, val);
592
}
593
594
void
595
bridge_noifcost(const char *ifname, int d)
596
{
597
	struct ifbreq breq;
598
599
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
600
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
601
602
	breq.ifbr_path_cost = 0;
603
604
	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
605
		err(1, "%s", name);
606
}
607
608
void
609
bridge_addaddr(const char *ifname, const char *addr)
610
{
611
	struct ifbareq ifba;
612
	struct ether_addr *ea;
613
614
	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
615
	strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
616
617
	ea = ether_aton(addr);
618
	if (ea == NULL)
619
		errx(1, "Invalid address: %s", addr);
620
621
	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
622
	ifba.ifba_flags = IFBAF_STATIC;
623
624
	if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0)
625
		err(1, "%s: %s", name, addr);
626
}
627
628
void
629
bridge_addrs(const char *delim, int d)
630
{
631
	char dstaddr[NI_MAXHOST];
632
	char dstport[NI_MAXSERV];
633
	const int niflag = NI_NUMERICHOST|NI_DGRAM;
634
	struct ifbaconf ifbac;
635
	struct ifbareq *ifba;
636
	char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb;
637
	struct sockaddr *sa;
638
	int i, len = 8192;
639
640
	/* ifconfig will call us with the argv of the command */
641
	if (strcmp(delim, "addr") == 0)
642
		delim = "";
643
644
	while (1) {
645
		ifbac.ifbac_len = len;
646
		inb = realloc(inbuf, len);
647
		if (inb == NULL)
648
			err(1, "malloc");
649
		ifbac.ifbac_buf = inbuf = inb;
650
		strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name));
651
		if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) {
652
			if (errno == ENETDOWN)
653
				return;
654
			err(1, "%s", name);
655
		}
656
		if (ifbac.ifbac_len + sizeof(*ifba) < len)
657
			break;
658
		len *= 2;
659
	}
660
661
	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
662
		ifba = ifbac.ifbac_req + i;
663
		strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
664
		printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
665
		    buf, ifba->ifba_age);
666
		sa = (struct sockaddr *)&ifba->ifba_dstsa;
667
		printb("flags", ifba->ifba_flags, IFBAFBITS);
668
		if (sa->sa_family != AF_UNSPEC &&
669
		    getnameinfo(sa, sa->sa_len,
670
		    dstaddr, sizeof(dstaddr),
671
		    dstport, sizeof(dstport), niflag) == 0)
672
			printf(" tunnel %s:%s", dstaddr, dstport);
673
		printf("\n");
674
	}
675
	free(inbuf);
676
}
677
678
void
679
bridge_holdcnt(const char *value, int d)
680
{
681
	struct ifbrparam bp;
682
	const char *errstr;
683
684
	bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
685
	if (errstr)
686
		err(1, "holdcnt %s %s", value, errstr);
687
688
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
689
	if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0)
690
		err(1, "%s", name);
691
}
692
693
/*
694
 * Check to make sure 'brdg' is really a bridge interface.
695
 */
696
int
697
is_bridge(char *brdg)
698
{
699
16094
	struct ifreq ifr;
700
8047
	struct ifbaconf ifbac;
701
702
8047
	strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
703
704
8047
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
705
		return (0);
706
707
8047
	ifbac.ifbac_len = 0;
708
8047
	strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
709
8047
	if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) {
710
8047
		if (errno == ENETDOWN)
711
			return (1);
712
8047
		return (0);
713
	}
714
	return (1);
715
8047
}
716
717
void
718
bridge_status(void)
719
{
720
3246
	struct ifreq ifr;
721
1623
	struct ifbrparam bp1, bp2;
722
723

1623
	if (!is_bridge(name) || is_switch(name))
724
1623
		return;
725
726
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
727
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
728
		return;
729
730
	bridge_cfg("\t");
731
732
	bridge_list("\t");
733
734
	if (aflag && !ifaliases)
735
		return;
736
737
	strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name));
738
	if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0)
739
		return;
740
741
	strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name));
742
	if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0)
743
		return;
744
745
	printf("\tAddresses (max cache: %u, timeout: %u):\n",
746
	    bp1.ifbrp_csize, bp2.ifbrp_ctime);
747
748
	bridge_addrs("\t\t", 0);
749
1623
}
750
751
void
752
bridge_flushrule(const char *ifname, int d)
753
{
754
	struct ifbrlreq req;
755
756
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
757
	strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
758
	if (ioctl(s, SIOCBRDGFRL, &req) < 0)
759
		err(1, "%s: %s", name, ifname);
760
}
761
762
void
763
bridge_rules(const char *ifname, int usetab)
764
{
765
	char *inbuf = NULL, *inb;
766
	struct ifbrlconf ifc;
767
	struct ifbrlreq *ifrp;
768
	int len = 8192, i;
769
770
	while (1) {
771
		ifc.ifbrl_len = len;
772
		inb = realloc(inbuf, len);
773
		if (inb == NULL)
774
			err(1, "malloc");
775
		ifc.ifbrl_buf = inbuf = inb;
776
		strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name));
777
		strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname));
778
		if (ioctl(s, SIOCBRDGGRL, &ifc) < 0)
779
			err(1, "ioctl(SIOCBRDGGRL)");
780
		if (ifc.ifbrl_len + sizeof(*ifrp) < len)
781
			break;
782
		len *= 2;
783
	}
784
	ifrp = ifc.ifbrl_req;
785
	for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) {
786
		ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i);
787
788
		if (usetab)
789
			printf("\t");
790
791
		bridge_showrule(ifrp);
792
	}
793
}
794
795
void
796
bridge_showrule(struct ifbrlreq *r)
797
{
798
	if (r->ifbr_action == BRL_ACTION_BLOCK)
799
		printf("block ");
800
	else if (r->ifbr_action == BRL_ACTION_PASS)
801
		printf("pass ");
802
	else
803
		printf("[neither block nor pass?]\n");
804
805
	if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) ==
806
	    (BRL_FLAG_IN | BRL_FLAG_OUT))
807
		printf("in/out ");
808
	else if (r->ifbr_flags & BRL_FLAG_IN)
809
		printf("in ");
810
	else if (r->ifbr_flags & BRL_FLAG_OUT)
811
		printf("out ");
812
	else
813
		printf("[neither in nor out?]\n");
814
815
	printf("on %s", r->ifbr_ifsname);
816
817
	if (r->ifbr_flags & BRL_FLAG_SRCVALID)
818
		printf(" src %s", ether_ntoa(&r->ifbr_src));
819
	if (r->ifbr_flags & BRL_FLAG_DSTVALID)
820
		printf(" dst %s", ether_ntoa(&r->ifbr_dst));
821
	if (r->ifbr_tagname[0])
822
		printf(" tag %s", r->ifbr_tagname);
823
824
	printf("\n");
825
}
826
827
/*
828
 * Parse a rule definition and send it upwards.
829
 *
830
 * Syntax:
831
 *	{block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}]
832
 */
833
int
834
bridge_rule(int targc, char **targv, int ln)
835
{
836
	char **argv = targv;
837
	int argc = targc;
838
	struct ifbrlreq rule;
839
	struct ether_addr *ea, *dea;
840
841
	if (argc == 0) {
842
		warnx("invalid rule");
843
		return (1);
844
	}
845
	rule.ifbr_tagname[0] = 0;
846
	rule.ifbr_flags = 0;
847
	rule.ifbr_action = 0;
848
	strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name));
849
850
	if (strcmp(argv[0], "block") == 0)
851
		rule.ifbr_action = BRL_ACTION_BLOCK;
852
	else if (strcmp(argv[0], "pass") == 0)
853
		rule.ifbr_action = BRL_ACTION_PASS;
854
	else
855
		goto bad_rule;
856
	argc--;	argv++;
857
858
	if (argc == 0) {
859
		bridge_badrule(targc, targv, ln);
860
		return (1);
861
	}
862
	if (strcmp(argv[0], "in") == 0)
863
		rule.ifbr_flags |= BRL_FLAG_IN;
864
	else if (strcmp(argv[0], "out") == 0)
865
		rule.ifbr_flags |= BRL_FLAG_OUT;
866
	else if (strcmp(argv[0], "in/out") == 0)
867
		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
868
	else if (strcmp(argv[0], "on") == 0) {
869
		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
870
		argc++; argv--;
871
	} else
872
		goto bad_rule;
873
	argc--; argv++;
874
875
	if (argc == 0 || strcmp(argv[0], "on"))
876
		goto bad_rule;
877
	argc--; argv++;
878
879
	if (argc == 0)
880
		goto bad_rule;
881
	strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname));
882
	argc--; argv++;
883
884
	while (argc) {
885
		if (strcmp(argv[0], "dst") == 0) {
886
			if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
887
				goto bad_rule;
888
			rule.ifbr_flags |= BRL_FLAG_DSTVALID;
889
			dea = &rule.ifbr_dst;
890
		} else if (strcmp(argv[0], "src") == 0) {
891
			if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
892
				goto bad_rule;
893
			rule.ifbr_flags |= BRL_FLAG_SRCVALID;
894
			dea = &rule.ifbr_src;
895
		} else if (strcmp(argv[0], "tag") == 0) {
896
			if (argc < 2) {
897
				warnx("missing tag name");
898
				goto bad_rule;
899
			}
900
			if (rule.ifbr_tagname[0]) {
901
				warnx("tag already defined");
902
				goto bad_rule;
903
			}
904
			if (strlcpy(rule.ifbr_tagname, argv[1],
905
			    PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
906
				warnx("tag name '%s' too long", argv[1]);
907
				goto bad_rule;
908
			}
909
			dea = NULL;
910
		} else
911
			goto bad_rule;
912
913
		argc--; argv++;
914
915
		if (argc == 0)
916
			goto bad_rule;
917
		if (dea != NULL) {
918
			ea = ether_aton(argv[0]);
919
			if (ea == NULL) {
920
				warnx("invalid address: %s", argv[0]);
921
				return (1);
922
			}
923
			bcopy(ea, dea, sizeof(*dea));
924
		}
925
		argc--; argv++;
926
	}
927
928
	if (ioctl(s, SIOCBRDGARL, &rule) < 0) {
929
		warn("%s", name);
930
		return (1);
931
	}
932
	return (0);
933
934
bad_rule:
935
	bridge_badrule(targc, targv, ln);
936
	return (1);
937
}
938
939
#define MAXRULEWORDS 8
940
941
void
942
bridge_rulefile(const char *fname, int d)
943
{
944
	FILE *f;
945
	char *str, *argv[MAXRULEWORDS], buf[1024];
946
	int ln = 0, argc = 0;
947
948
	f = fopen(fname, "r");
949
	if (f == NULL)
950
		err(1, "%s", fname);
951
952
	while (fgets(buf, sizeof(buf), f) != NULL) {
953
		ln++;
954
		if (buf[0] == '#' || buf[0] == '\n')
955
			continue;
956
957
		argc = 0;
958
		str = strtok(buf, "\n\t\r ");
959
		while (str != NULL && argc < MAXRULEWORDS) {
960
			argv[argc++] = str;
961
			str = strtok(NULL, "\n\t\r ");
962
		}
963
964
		/* Rule is too long if there's more. */
965
		if (str != NULL) {
966
			warnx("invalid rule: %d: %s ...", ln, buf);
967
			continue;
968
		}
969
970
		bridge_rule(argc, argv, ln);
971
	}
972
	fclose(f);
973
}
974
975
void
976
bridge_badrule(int argc, char *argv[], int ln)
977
{
978
	extern const char *__progname;
979
	int i;
980
981
	fprintf(stderr, "%s: invalid rule: ", __progname);
982
	if (ln != -1)
983
		fprintf(stderr, "%d: ", ln);
984
	for (i = 0; i < argc; i++)
985
		fprintf(stderr, "%s ", argv[i]);
986
	fprintf(stderr, "\n");
987
}
988
989
int
990
is_switch(char *swname)
991
{
992
3246
	struct ifbrparam bp;
993
994
1623
	strlcpy(bp.ifbrp_name, swname, sizeof(bp.ifbrp_name));
995
1623
	if (ioctl(s, SIOCSWGDPID, (caddr_t)&bp) < 0)
996
1623
		return (0);
997
998
	return (1);
999
1623
}
1000
1001
void
1002
switch_cfg(char *delim)
1003
{
1004
	struct ifbrparam bp;
1005
1006
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
1007
	if (ioctl(s, SIOCSWGDPID, (caddr_t)&bp) < 0)
1008
		err(1, "%s", name);
1009
1010
	printf("%sdatapath %#016llx", delim, bp.ifbrp_datapath);
1011
1012
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
1013
	if (ioctl(s, SIOCSWGMAXFLOW, (caddr_t)&bp) < 0)
1014
		err(1, "%s", name);
1015
1016
	printf(" maxflow %d", bp.ifbrp_maxflow);
1017
1018
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
1019
	if (ioctl(s, SIOCSWGMAXGROUP, (caddr_t)&bp) < 0)
1020
		err(1, "%s", name);
1021
1022
	printf(" maxgroup %d\n", bp.ifbrp_maxgroup);
1023
}
1024
1025
void
1026
switch_status(void)
1027
{
1028
3246
	struct ifreq ifr;
1029
1030
1623
	if (!is_switch(name))
1031
1623
		return;
1032
1033
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1034
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
1035
		return;
1036
1037
	switch_cfg("\t");
1038
1039
	bridge_list("\t");
1040
1041
	if (aflag && !ifaliases)
1042
		return;
1043
1623
}
1044
1045
void
1046
switch_datapathid(const char *arg, int d)
1047
{
1048
	struct ifbrparam bp;
1049
	uint64_t newdpid;
1050
	char *endptr;
1051
1052
	errno = 0;
1053
	newdpid = strtoull(arg, &endptr, 0);
1054
	if (arg[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
1055
		errx(1, "invalid arg for datapath-id: %s", arg);
1056
1057
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
1058
	bp.ifbrp_datapath = newdpid;
1059
	if (ioctl(s, SIOCSWSDPID, (caddr_t)&bp) < 0)
1060
		err(1, "%s", name);
1061
}
1062
1063
void
1064
switch_portno(const char *ifname, const char *val)
1065
{
1066
	struct ifbreq breq;
1067
	uint32_t newportidx;
1068
	char *endptr;
1069
1070
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
1071
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
1072
1073
	errno = 0;
1074
	newportidx = strtol(val, &endptr, 0);
1075
	if (val[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
1076
		errx(1, "invalid arg for portidx: %s", val);
1077
1078
	breq.ifbr_portno = newportidx;
1079
	if (ioctl(s, SIOCSWSPORTNO, (caddr_t)&breq) < 0) {
1080
		if (errno == EEXIST)
1081
			return;
1082
		else
1083
			err(1, "%s", name);
1084
	}
1085
}
1086
1087
#endif