GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/ifconfig/brconfig.c Lines: 8 408 2.0 %
Date: 2016-12-06 Branches: 3 270 1.1 %

Line Branch Exec Source
1
/*	$OpenBSD: brconfig.c,v 1.9 2015/07/18 06:50:24 rzalamena 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
60
#define	IFBAFBITS	"\020\1STATIC"
61
#define	IFBIFBITS	\
62
"\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN"
63
64
#define	PV2ID(pv, epri, eaddr)	do {					\
65
	epri	 = pv >> 48;						\
66
	eaddr[0] = pv >> 40;						\
67
	eaddr[1] = pv >> 32;						\
68
	eaddr[2] = pv >> 24;						\
69
	eaddr[3] = pv >> 16;						\
70
	eaddr[4] = pv >> 8;						\
71
	eaddr[5] = pv >> 0;						\
72
} while (0)
73
74
char *stpstates[] = {
75
	"disabled",
76
	"listening",
77
	"learning",
78
	"forwarding",
79
	"blocking",
80
	"discarding"
81
};
82
char *stpproto[] = {
83
	"stp",
84
	"(none)",
85
	"rstp",
86
};
87
char *stproles[] = {
88
	"disabled",
89
	"root",
90
	"designated",
91
	"alternate",
92
	"backup"
93
};
94
95
96
void
97
setdiscover(const char *val, int d)
98
{
99
	bridge_ifsetflag(val, IFBIF_DISCOVER);
100
}
101
102
void
103
unsetdiscover(const char *val, int d)
104
{
105
	bridge_ifclrflag(val, IFBIF_DISCOVER);
106
}
107
108
void
109
setblocknonip(const char *val, int d)
110
{
111
	bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
112
}
113
114
void
115
unsetblocknonip(const char *val, int d)
116
{
117
	bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
118
}
119
120
void
121
setlearn(const char *val, int d)
122
{
123
	bridge_ifsetflag(val, IFBIF_LEARNING);
124
}
125
126
void
127
unsetlearn(const char *val, int d)
128
{
129
	bridge_ifclrflag(val, IFBIF_LEARNING);
130
}
131
132
void
133
setstp(const char *val, int d)
134
{
135
	bridge_ifsetflag(val, IFBIF_STP);
136
}
137
138
void
139
unsetstp(const char *val, int d)
140
{
141
	bridge_ifclrflag(val, IFBIF_STP);
142
}
143
144
void
145
setedge(const char *val, int d)
146
{
147
	bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
148
}
149
150
void
151
unsetedge(const char *val, int d)
152
{
153
	bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
154
}
155
156
void
157
setautoedge(const char *val, int d)
158
{
159
	bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
160
}
161
162
void
163
unsetautoedge(const char *val, int d)
164
{
165
	bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
166
}
167
168
void
169
setptp(const char *val, int d)
170
{
171
	bridge_ifsetflag(val, IFBIF_BSTP_PTP);
172
}
173
174
void
175
unsetptp(const char *val, int d)
176
{
177
	bridge_ifclrflag(val, IFBIF_BSTP_PTP);
178
}
179
180
void
181
setautoptp(const char *val, int d)
182
{
183
	bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
184
}
185
186
void
187
unsetautoptp(const char *val, int d)
188
{
189
	bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
190
}
191
192
193
void
194
bridge_ifsetflag(const char *ifsname, u_int32_t flag)
195
{
196
	struct ifbreq req;
197
198
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
199
	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
200
	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
201
		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
202
203
	req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK;
204
205
	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
206
		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
207
}
208
209
void
210
bridge_ifclrflag(const char *ifsname, u_int32_t flag)
211
{
212
	struct ifbreq req;
213
214
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
215
	strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname));
216
217
	if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0)
218
		err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname);
219
220
	req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK);
221
222
	if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0)
223
		err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname);
224
}
225
226
void
227
bridge_flushall(const char *val, int p)
228
{
229
	struct ifbreq req;
230
231
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
232
	req.ifbr_ifsflags = IFBF_FLUSHALL;
233
	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
234
		err(1, "%s", name);
235
}
236
237
void
238
bridge_flush(const char *val, int p)
239
{
240
	struct ifbreq req;
241
242
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
243
	req.ifbr_ifsflags = IFBF_FLUSHDYN;
244
	if (ioctl(s, SIOCBRDGFLUSH, &req) < 0)
245
		err(1, "%s", name);
246
}
247
248
void
249
bridge_cfg(const char *delim)
250
{
251
	struct ifbropreq ifbp;
252
	u_int16_t pri;
253
	u_int8_t ht, fd, ma, hc, proto;
254
	u_int8_t lladdr[ETHER_ADDR_LEN];
255
	u_int16_t bprio;
256
257
	strlcpy(ifbp.ifbop_name, name, sizeof(ifbp.ifbop_name));
258
	if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp))
259
		err(1, "%s", name);
260
	printf("%s", delim);
261
	pri = ifbp.ifbop_priority;
262
	ht = ifbp.ifbop_hellotime;
263
	fd = ifbp.ifbop_fwddelay;
264
	ma = ifbp.ifbop_maxage;
265
	hc = ifbp.ifbop_holdcount;
266
	proto = ifbp.ifbop_protocol;
267
268
	printf("priority %u hellotime %u fwddelay %u maxage %u "
269
	    "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]);
270
271
	if (aflag)
272
		return;
273
274
	PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr);
275
	printf("\tdesignated: id %s priority %u\n",
276
	    ether_ntoa((struct ether_addr *)lladdr), bprio);
277
278
	if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge)
279
		return;
280
281
	PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr);
282
	printf("\troot: id %s priority %u ifcost %u port %u\n",
283
	    ether_ntoa((struct ether_addr *)lladdr), bprio,
284
	    ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
285
}
286
287
void
288
bridge_list(char *delim)
289
{
290
	struct ifbreq *reqp;
291
	struct ifbifconf bifc;
292
	int i, len = 8192;
293
	char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb;
294
295
	while (1) {
296
		bifc.ifbic_len = len;
297
		inb = realloc(inbuf, len);
298
		if (inb == NULL)
299
			err(1, "malloc");
300
		bifc.ifbic_buf = inbuf = inb;
301
		strlcpy(bifc.ifbic_name, name, sizeof(bifc.ifbic_name));
302
		if (ioctl(s, SIOCBRDGIFS, &bifc) < 0)
303
			err(1, "%s", name);
304
		if (bifc.ifbic_len + sizeof(*reqp) < len)
305
			break;
306
		len *= 2;
307
	}
308
	for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) {
309
		reqp = bifc.ifbic_req + i;
310
		strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf));
311
		printf("%s%s ", delim, buf);
312
		printb("flags", reqp->ifbr_ifsflags, IFBIFBITS);
313
		printf("\n");
314
		if (reqp->ifbr_ifsflags & IFBIF_SPAN)
315
			continue;
316
		printf("\t\t");
317
		printf("port %u ifpriority %u ifcost %u",
318
		    reqp->ifbr_portno, reqp->ifbr_priority,
319
		    reqp->ifbr_path_cost);
320
		if (reqp->ifbr_ifsflags & IFBIF_STP)
321
			printf(" %s role %s",
322
			    stpstates[reqp->ifbr_state],
323
			    stproles[reqp->ifbr_role]);
324
		printf("\n");
325
		bridge_rules(buf, 1);
326
	}
327
	free(bifc.ifbic_buf);
328
}
329
330
void
331
bridge_add(const char *ifn, int d)
332
{
333
	struct ifbreq req;
334
335
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
336
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
337
	if (ioctl(s, SIOCBRDGADD, &req) < 0) {
338
		if (errno == EEXIST)
339
			return;
340
		err(1, "%s: %s", name, ifn);
341
	}
342
}
343
344
void
345
bridge_delete(const char *ifn, int d)
346
{
347
	struct ifbreq req;
348
349
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
350
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
351
	if (ioctl(s, SIOCBRDGDEL, &req) < 0)
352
		err(1, "%s: %s", name, ifn);
353
}
354
355
void
356
bridge_addspan(const char *ifn, int d)
357
{
358
	struct ifbreq req;
359
360
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
361
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
362
	if (ioctl(s, SIOCBRDGADDS, &req) < 0) {
363
		if (errno == EEXIST)
364
			return;
365
		err(1, "%s: %s", name, ifn);
366
	}
367
}
368
369
void
370
bridge_delspan(const char *ifn, int d)
371
{
372
	struct ifbreq req;
373
374
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
375
	strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
376
	if (ioctl(s, SIOCBRDGDELS, &req) < 0)
377
		err(1, "%s: %s", name, ifn);
378
}
379
380
void
381
bridge_timeout(const char *arg, int d)
382
{
383
	struct ifbrparam bp;
384
	long newtime;
385
	char *endptr;
386
387
	errno = 0;
388
	newtime = strtol(arg, &endptr, 0);
389
	if (arg[0] == '\0' || endptr[0] != '\0' ||
390
	    (newtime & ~INT_MAX) != 0L ||
391
	    (errno == ERANGE && newtime == LONG_MAX))
392
		errx(1, "invalid arg for timeout: %s", arg);
393
394
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
395
	bp.ifbrp_ctime = newtime;
396
	if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0)
397
		err(1, "%s", name);
398
}
399
400
void
401
bridge_maxage(const char *arg, int d)
402
{
403
	struct ifbrparam bp;
404
	unsigned long v;
405
	char *endptr;
406
407
	errno = 0;
408
	v = strtoul(arg, &endptr, 0);
409
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
410
	    (errno == ERANGE && v == ULONG_MAX))
411
		errx(1, "invalid arg for maxage: %s", arg);
412
413
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
414
	bp.ifbrp_maxage = v;
415
	if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0)
416
		err(1, "%s", name);
417
}
418
419
void
420
bridge_priority(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 > 0xffffUL ||
429
	    (errno == ERANGE && v == ULONG_MAX))
430
		errx(1, "invalid arg for spanpriority: %s", arg);
431
432
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
433
	bp.ifbrp_prio = v;
434
	if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0)
435
		err(1, "%s", name);
436
}
437
438
void
439
bridge_proto(const char *arg, int d)
440
{
441
	struct ifbrparam bp;
442
	int i, proto = -1;
443
444
	for (i = 0; i <= BSTP_PROTO_MAX; i++)
445
		if (strcmp(arg, stpproto[i]) == 0) {
446
			proto = i;
447
			break;
448
		}
449
	if (proto == -1)
450
		errx(1, "invalid arg for proto: %s", arg);
451
452
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
453
	bp.ifbrp_prio = proto;
454
	if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0)
455
		err(1, "%s", name);
456
}
457
458
void
459
bridge_fwddelay(const char *arg, int d)
460
{
461
	struct ifbrparam bp;
462
	unsigned long v;
463
	char *endptr;
464
465
	errno = 0;
466
	v = strtoul(arg, &endptr, 0);
467
	if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
468
	    (errno == ERANGE && v == ULONG_MAX))
469
		errx(1, "invalid arg for fwddelay: %s", arg);
470
471
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
472
	bp.ifbrp_fwddelay = v;
473
	if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0)
474
		err(1, "%s", name);
475
}
476
477
void
478
bridge_hellotime(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 hellotime: %s", arg);
489
490
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
491
	bp.ifbrp_hellotime = v;
492
	if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0)
493
		err(1, "%s", name);
494
}
495
496
void
497
bridge_maxaddr(const char *arg, int d)
498
{
499
	struct ifbrparam bp;
500
	unsigned long newsize;
501
	char *endptr;
502
503
	errno = 0;
504
	newsize = strtoul(arg, &endptr, 0);
505
	if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL ||
506
	    (errno == ERANGE && newsize == ULONG_MAX))
507
		errx(1, "invalid arg for maxaddr: %s", arg);
508
509
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
510
	bp.ifbrp_csize = newsize;
511
	if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0)
512
		err(1, "%s", name);
513
}
514
515
void
516
bridge_deladdr(const char *addr, int d)
517
{
518
	struct ifbareq ifba;
519
	struct ether_addr *ea;
520
521
	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
522
	ea = ether_aton(addr);
523
	if (ea == NULL)
524
		err(1, "Invalid address: %s", addr);
525
526
	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
527
528
	if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0)
529
		err(1, "%s: %s", name, addr);
530
}
531
532
void
533
bridge_ifprio(const char *ifname, const char *val)
534
{
535
	struct ifbreq breq;
536
	unsigned long v;
537
	char *endptr;
538
539
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
540
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
541
542
	errno = 0;
543
	v = strtoul(val, &endptr, 0);
544
	if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL ||
545
	    (errno == ERANGE && v == ULONG_MAX))
546
		err(1, "invalid arg for ifpriority: %s", val);
547
	breq.ifbr_priority = v;
548
549
	if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0)
550
		err(1, "%s: %s", name, val);
551
}
552
553
void
554
bridge_ifcost(const char *ifname, const char *val)
555
{
556
	struct ifbreq breq;
557
	unsigned long v;
558
	char *endptr;
559
560
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
561
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
562
563
	errno = 0;
564
	v = strtoul(val, &endptr, 0);
565
	if (val[0] == '\0' || endptr[0] != '\0' ||
566
	    v < 0 || v > 0xffffffffUL ||
567
	    (errno == ERANGE && v == ULONG_MAX))
568
		errx(1, "invalid arg for ifcost: %s", val);
569
570
	breq.ifbr_path_cost = v;
571
572
	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
573
		err(1, "%s: %s", name, val);
574
}
575
576
void
577
bridge_noifcost(const char *ifname, int d)
578
{
579
	struct ifbreq breq;
580
581
	strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name));
582
	strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname));
583
584
	breq.ifbr_path_cost = 0;
585
586
	if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0)
587
		err(1, "%s", name);
588
}
589
590
void
591
bridge_addaddr(const char *ifname, const char *addr)
592
{
593
	struct ifbareq ifba;
594
	struct ether_addr *ea;
595
596
	strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name));
597
	strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname));
598
599
	ea = ether_aton(addr);
600
	if (ea == NULL)
601
		errx(1, "Invalid address: %s", addr);
602
603
	bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr));
604
	ifba.ifba_flags = IFBAF_STATIC;
605
606
	if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0)
607
		err(1, "%s: %s", name, addr);
608
}
609
610
void
611
bridge_addrs(const char *delim, int d)
612
{
613
	char dstaddr[NI_MAXHOST];
614
	char dstport[NI_MAXSERV];
615
	const int niflag = NI_NUMERICHOST|NI_DGRAM;
616
	struct ifbaconf ifbac;
617
	struct ifbareq *ifba;
618
	char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb;
619
	struct sockaddr *sa;
620
	int i, len = 8192;
621
622
	/* ifconfig will call us with the argv of the command */
623
	if (strcmp(delim, "addr") == 0)
624
		delim = "";
625
626
	while (1) {
627
		ifbac.ifbac_len = len;
628
		inb = realloc(inbuf, len);
629
		if (inb == NULL)
630
			err(1, "malloc");
631
		ifbac.ifbac_buf = inbuf = inb;
632
		strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name));
633
		if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) {
634
			if (errno == ENETDOWN)
635
				return;
636
			err(1, "%s", name);
637
		}
638
		if (ifbac.ifbac_len + sizeof(*ifba) < len)
639
			break;
640
		len *= 2;
641
	}
642
643
	for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
644
		ifba = ifbac.ifbac_req + i;
645
		strlcpy(buf, ifba->ifba_ifsname, sizeof(buf));
646
		printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
647
		    buf, ifba->ifba_age);
648
		sa = (struct sockaddr *)&ifba->ifba_dstsa;
649
		printb("flags", ifba->ifba_flags, IFBAFBITS);
650
		if (sa->sa_family != AF_UNSPEC &&
651
		    getnameinfo(sa, sa->sa_len,
652
		    dstaddr, sizeof(dstaddr),
653
		    dstport, sizeof(dstport), niflag) == 0)
654
			printf(" tunnel %s:%s", dstaddr, dstport);
655
		printf("\n");
656
	}
657
	free(inbuf);
658
}
659
660
void
661
bridge_holdcnt(const char *value, int d)
662
{
663
	struct ifbrparam bp;
664
	const char *errstr;
665
666
	bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr);
667
	if (errstr)
668
		err(1, "holdcnt %s %s", value, errstr);
669
670
	strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name));
671
	if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0)
672
		err(1, "%s", name);
673
}
674
675
/*
676
 * Check to make sure 'brdg' is really a bridge interface.
677
 */
678
int
679
is_bridge(char *brdg)
680
102
{
681
	struct ifreq ifr;
682
	struct ifbaconf ifbac;
683
684
102
	strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name));
685
686
102
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
687
		return (0);
688
689
102
	ifbac.ifbac_len = 0;
690
102
	strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name));
691
102
	if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) {
692
102
		if (errno == ENETDOWN)
693
			return (1);
694
102
		return (0);
695
	}
696
	return (1);
697
}
698
699
void
700
bridge_status(void)
701
{
702
	struct ifreq ifr;
703
	struct ifbrparam bp1, bp2;
704
705
	if (!is_bridge(name))
706
		return;
707
708
	strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
709
	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
710
		return;
711
712
	bridge_cfg("\t");
713
714
	bridge_list("\t");
715
716
	if (aflag && !ifaliases)
717
		return;
718
719
	strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name));
720
	if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0)
721
		return;
722
723
	strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name));
724
	if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0)
725
		return;
726
727
	printf("\tAddresses (max cache: %u, timeout: %u):\n",
728
	    bp1.ifbrp_csize, bp2.ifbrp_ctime);
729
730
	bridge_addrs("\t\t", 0);
731
}
732
733
void
734
bridge_flushrule(const char *ifname, int d)
735
{
736
	struct ifbrlreq req;
737
738
	strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name));
739
	strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname));
740
	if (ioctl(s, SIOCBRDGFRL, &req) < 0)
741
		err(1, "%s: %s", name, ifname);
742
}
743
744
void
745
bridge_rules(const char *ifname, int usetab)
746
{
747
	char *inbuf = NULL, *inb;
748
	struct ifbrlconf ifc;
749
	struct ifbrlreq *ifrp;
750
	int len = 8192, i;
751
752
	while (1) {
753
		ifc.ifbrl_len = len;
754
		inb = realloc(inbuf, len);
755
		if (inb == NULL)
756
			err(1, "malloc");
757
		ifc.ifbrl_buf = inbuf = inb;
758
		strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name));
759
		strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname));
760
		if (ioctl(s, SIOCBRDGGRL, &ifc) < 0)
761
			err(1, "ioctl(SIOCBRDGGRL)");
762
		if (ifc.ifbrl_len + sizeof(*ifrp) < len)
763
			break;
764
		len *= 2;
765
	}
766
	ifrp = ifc.ifbrl_req;
767
	for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) {
768
		ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i);
769
770
		if (usetab)
771
			printf("\t");
772
773
		bridge_showrule(ifrp);
774
	}
775
}
776
777
void
778
bridge_showrule(struct ifbrlreq *r)
779
{
780
	if (r->ifbr_action == BRL_ACTION_BLOCK)
781
		printf("block ");
782
	else if (r->ifbr_action == BRL_ACTION_PASS)
783
		printf("pass ");
784
	else
785
		printf("[neither block nor pass?]\n");
786
787
	if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) ==
788
	    (BRL_FLAG_IN | BRL_FLAG_OUT))
789
		printf("in/out ");
790
	else if (r->ifbr_flags & BRL_FLAG_IN)
791
		printf("in ");
792
	else if (r->ifbr_flags & BRL_FLAG_OUT)
793
		printf("out ");
794
	else
795
		printf("[neither in nor out?]\n");
796
797
	printf("on %s", r->ifbr_ifsname);
798
799
	if (r->ifbr_flags & BRL_FLAG_SRCVALID)
800
		printf(" src %s", ether_ntoa(&r->ifbr_src));
801
	if (r->ifbr_flags & BRL_FLAG_DSTVALID)
802
		printf(" dst %s", ether_ntoa(&r->ifbr_dst));
803
	if (r->ifbr_tagname[0])
804
		printf(" tag %s", r->ifbr_tagname);
805
806
	printf("\n");
807
}
808
809
/*
810
 * Parse a rule definition and send it upwards.
811
 *
812
 * Syntax:
813
 *	{block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}]
814
 */
815
int
816
bridge_rule(int targc, char **targv, int ln)
817
{
818
	char **argv = targv;
819
	int argc = targc;
820
	struct ifbrlreq rule;
821
	struct ether_addr *ea, *dea;
822
823
	if (argc == 0) {
824
		warnx("invalid rule");
825
		return (1);
826
	}
827
	rule.ifbr_tagname[0] = 0;
828
	rule.ifbr_flags = 0;
829
	rule.ifbr_action = 0;
830
	strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name));
831
832
	if (strcmp(argv[0], "block") == 0)
833
		rule.ifbr_action = BRL_ACTION_BLOCK;
834
	else if (strcmp(argv[0], "pass") == 0)
835
		rule.ifbr_action = BRL_ACTION_PASS;
836
	else
837
		goto bad_rule;
838
	argc--;	argv++;
839
840
	if (argc == 0) {
841
		bridge_badrule(targc, targv, ln);
842
		return (1);
843
	}
844
	if (strcmp(argv[0], "in") == 0)
845
		rule.ifbr_flags |= BRL_FLAG_IN;
846
	else if (strcmp(argv[0], "out") == 0)
847
		rule.ifbr_flags |= BRL_FLAG_OUT;
848
	else if (strcmp(argv[0], "in/out") == 0)
849
		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
850
	else if (strcmp(argv[0], "on") == 0) {
851
		rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT;
852
		argc++; argv--;
853
	} else
854
		goto bad_rule;
855
	argc--; argv++;
856
857
	if (argc == 0 || strcmp(argv[0], "on"))
858
		goto bad_rule;
859
	argc--; argv++;
860
861
	if (argc == 0)
862
		goto bad_rule;
863
	strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname));
864
	argc--; argv++;
865
866
	while (argc) {
867
		if (strcmp(argv[0], "dst") == 0) {
868
			if (rule.ifbr_flags & BRL_FLAG_DSTVALID)
869
				goto bad_rule;
870
			rule.ifbr_flags |= BRL_FLAG_DSTVALID;
871
			dea = &rule.ifbr_dst;
872
		} else if (strcmp(argv[0], "src") == 0) {
873
			if (rule.ifbr_flags & BRL_FLAG_SRCVALID)
874
				goto bad_rule;
875
			rule.ifbr_flags |= BRL_FLAG_SRCVALID;
876
			dea = &rule.ifbr_src;
877
		} else if (strcmp(argv[0], "tag") == 0) {
878
			if (argc < 2) {
879
				warnx("missing tag name");
880
				goto bad_rule;
881
			}
882
			if (rule.ifbr_tagname[0]) {
883
				warnx("tag already defined");
884
				goto bad_rule;
885
			}
886
			if (strlcpy(rule.ifbr_tagname, argv[1],
887
			    PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) {
888
				warnx("tag name '%s' too long", argv[1]);
889
				goto bad_rule;
890
			}
891
			dea = NULL;
892
		} else
893
			goto bad_rule;
894
895
		argc--; argv++;
896
897
		if (argc == 0)
898
			goto bad_rule;
899
		if (dea != NULL) {
900
			ea = ether_aton(argv[0]);
901
			if (ea == NULL) {
902
				warnx("invalid address: %s", argv[0]);
903
				return (1);
904
			}
905
			bcopy(ea, dea, sizeof(*dea));
906
		}
907
		argc--; argv++;
908
	}
909
910
	if (ioctl(s, SIOCBRDGARL, &rule) < 0) {
911
		warn("%s", name);
912
		return (1);
913
	}
914
	return (0);
915
916
bad_rule:
917
	bridge_badrule(targc, targv, ln);
918
	return (1);
919
}
920
921
#define MAXRULEWORDS 8
922
923
void
924
bridge_rulefile(const char *fname, int d)
925
{
926
	FILE *f;
927
	char *str, *argv[MAXRULEWORDS], buf[1024];
928
	int ln = 0, argc = 0;
929
930
	f = fopen(fname, "r");
931
	if (f == NULL)
932
		err(1, "%s", fname);
933
934
	while (fgets(buf, sizeof(buf), f) != NULL) {
935
		ln++;
936
		if (buf[0] == '#' || buf[0] == '\n')
937
			continue;
938
939
		argc = 0;
940
		str = strtok(buf, "\n\t\r ");
941
		while (str != NULL && argc < MAXRULEWORDS) {
942
			argv[argc++] = str;
943
			str = strtok(NULL, "\n\t\r ");
944
		}
945
946
		/* Rule is too long if there's more. */
947
		if (str != NULL) {
948
			warnx("invalid rule: %d: %s ...", ln, buf);
949
			continue;
950
		}
951
952
		bridge_rule(argc, argv, ln);
953
	}
954
	fclose(f);
955
}
956
957
void
958
bridge_badrule(int argc, char *argv[], int ln)
959
{
960
	extern const char *__progname;
961
	int i;
962
963
	fprintf(stderr, "%s: invalid rule: ", __progname);
964
	if (ln != -1)
965
		fprintf(stderr, "%d: ", ln);
966
	for (i = 0; i < argc; i++)
967
		fprintf(stderr, "%s ", argv[i]);
968
	fprintf(stderr, "\n");
969
}
970
971
#endif