GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldpctl/ldpctl.c Lines: 0 303 0.0 %
Date: 2017-11-07 Branches: 0 186 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ldpctl.c,v 1.32 2016/07/15 17:09:25 renato Exp $
2
 *
3
 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <sys/un.h>
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
#include <net/if_media.h>
27
#include <net/if_types.h>
28
#include <netmpls/mpls.h>
29
30
#include <err.h>
31
#include <errno.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
#include <limits.h>
37
38
#include "ldp.h"
39
#include "ldpd.h"
40
#include "ldpe.h"
41
#include "log.h"
42
#include "parser.h"
43
44
__dead void	 usage(void);
45
const char	*fmt_timeframe_core(time_t);
46
const char	*get_linkstate(uint8_t, int);
47
int		 show_interface_msg(struct imsg *, struct parse_result *);
48
int		 show_discovery_msg(struct imsg *, struct parse_result *);
49
uint64_t	 get_ifms_type(uint8_t);
50
int		 show_lib_msg(struct imsg *, struct parse_result *);
51
int		 show_nbr_msg(struct imsg *, struct parse_result *);
52
void		 show_fib_head(void);
53
int		 show_fib_msg(struct imsg *, struct parse_result *);
54
void		 show_interface_head(void);
55
int		 show_fib_interface_msg(struct imsg *);
56
int		 show_l2vpn_pw_msg(struct imsg *);
57
int		 show_l2vpn_binding_msg(struct imsg *);
58
const char	*get_media_descr(uint64_t);
59
void		 print_baudrate(uint64_t);
60
61
struct imsgbuf	*ibuf;
62
63
__dead void
64
usage(void)
65
{
66
	extern char *__progname;
67
68
	fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
69
	exit(1);
70
}
71
72
int
73
main(int argc, char *argv[])
74
{
75
	struct sockaddr_un	 sun;
76
	struct parse_result	*res;
77
	struct imsg		 imsg;
78
	unsigned int		 ifidx = 0;
79
	struct kroute		 kr;
80
	int			 ctl_sock;
81
	int			 done = 0, verbose = 0;
82
	int			 n;
83
	struct ctl_nbr		 nbr;
84
85
	/* parse options */
86
	if ((res = parse(argc - 1, argv + 1)) == NULL)
87
		exit(1);
88
89
	/* connect to ldpd control socket */
90
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
91
		err(1, "socket");
92
93
	memset(&sun, 0, sizeof(sun));
94
	sun.sun_family = AF_UNIX;
95
	strlcpy(sun.sun_path, LDPD_SOCKET, sizeof(sun.sun_path));
96
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
97
		err(1, "connect: %s", LDPD_SOCKET);
98
99
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
100
		err(1, "pledge");
101
102
	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
103
		err(1, NULL);
104
	imsg_init(ibuf, ctl_sock);
105
	done = 0;
106
107
	/* process user request */
108
	switch (res->action) {
109
	case NONE:
110
		usage();
111
		/* not reached */
112
	case SHOW:
113
	case SHOW_IFACE:
114
		printf("%-4s %-11s %-6s %-10s %-8s %-12s %3s\n",
115
		    "AF", "Interface", "State", "Linkstate", "Uptime",
116
		    "Hello Timers", "ac");
117
		if (*res->ifname) {
118
			ifidx = if_nametoindex(res->ifname);
119
			if (ifidx == 0)
120
				errx(1, "no such interface %s", res->ifname);
121
		}
122
		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
123
		    &ifidx, sizeof(ifidx));
124
		break;
125
	case SHOW_DISC:
126
		printf("%-4s %-15s %-8s %-15s %9s\n",
127
		    "AF", "ID", "Type", "Source", "Holdtime");
128
		imsg_compose(ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1,
129
		    NULL, 0);
130
		break;
131
	case SHOW_NBR:
132
		printf("%-4s %-15s %-11s %-15s %8s\n",
133
		    "AF", "ID", "State", "Remote Address", "Uptime");
134
		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
135
		break;
136
	case SHOW_LIB:
137
		printf("%-4s %-20s %-15s %-11s %-13s %6s\n", "AF",
138
		    "Destination", "Nexthop", "Local Label", "Remote Label",
139
		    "In Use");
140
		imsg_compose(ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
141
		break;
142
	case SHOW_FIB:
143
		if (!ldp_addrisset(res->family, &res->addr))
144
			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
145
			    &res->flags, sizeof(res->flags));
146
		else {
147
			memset(&kr, 0, sizeof(kr));
148
			kr.af = res->family;
149
			kr.prefix = res->addr;
150
			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
151
			    &kr, sizeof(kr));
152
		}
153
		show_fib_head();
154
		break;
155
	case SHOW_FIB_IFACE:
156
		if (*res->ifname)
157
			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
158
			    res->ifname, sizeof(res->ifname));
159
		else
160
			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
161
		show_interface_head();
162
		break;
163
	case SHOW_L2VPN_PW:
164
		printf("%-11s %-15s %-14s %-10s\n",
165
		    "Interface", "Neighbor", "PWID", "Status");
166
		imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0);
167
		break;
168
	case SHOW_L2VPN_BINDING:
169
		imsg_compose(ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1,
170
		    NULL, 0);
171
		break;
172
	case CLEAR_NBR:
173
		memset(&nbr, 0, sizeof(nbr));
174
		nbr.af = res->family;
175
		memcpy(&nbr.raddr, &res->addr, sizeof(nbr.raddr));
176
		imsg_compose(ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr,
177
		    sizeof(nbr));
178
		done = 1;
179
		break;
180
	case FIB:
181
		errx(1, "fib couple|decouple");
182
		break;
183
	case FIB_COUPLE:
184
		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
185
		printf("couple request sent.\n");
186
		done = 1;
187
		break;
188
	case FIB_DECOUPLE:
189
		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
190
		printf("decouple request sent.\n");
191
		done = 1;
192
		break;
193
	case LOG_VERBOSE:
194
		verbose = 1;
195
		/* FALLTHROUGH */
196
	case LOG_BRIEF:
197
		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
198
		    &verbose, sizeof(verbose));
199
		printf("logging request sent.\n");
200
		done = 1;
201
		break;
202
	case RELOAD:
203
		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
204
		printf("reload request sent.\n");
205
		done = 1;
206
		break;
207
	}
208
209
	while (ibuf->w.queued)
210
		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
211
			err(1, "write error");
212
213
	while (!done) {
214
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
215
			errx(1, "imsg_read error");
216
		if (n == 0)
217
			errx(1, "pipe closed");
218
219
		while (!done) {
220
			if ((n = imsg_get(ibuf, &imsg)) == -1)
221
				errx(1, "imsg_get error");
222
			if (n == 0)
223
				break;
224
			switch (res->action) {
225
			case SHOW:
226
			case SHOW_IFACE:
227
				done = show_interface_msg(&imsg, res);
228
				break;
229
			case SHOW_DISC:
230
				done = show_discovery_msg(&imsg, res);
231
				break;
232
			case SHOW_NBR:
233
				done = show_nbr_msg(&imsg, res);
234
				break;
235
			case SHOW_LIB:
236
				done = show_lib_msg(&imsg, res);
237
				break;
238
			case SHOW_FIB:
239
				done = show_fib_msg(&imsg, res);
240
				break;
241
			case SHOW_FIB_IFACE:
242
				done = show_fib_interface_msg(&imsg);
243
				break;
244
			case SHOW_L2VPN_PW:
245
				done = show_l2vpn_pw_msg(&imsg);
246
				break;
247
			case SHOW_L2VPN_BINDING:
248
				done = show_l2vpn_binding_msg(&imsg);
249
				break;
250
			case NONE:
251
			case CLEAR_NBR:
252
			case FIB:
253
			case FIB_COUPLE:
254
			case FIB_DECOUPLE:
255
			case LOG_VERBOSE:
256
			case LOG_BRIEF:
257
			case RELOAD:
258
				break;
259
			}
260
			imsg_free(&imsg);
261
		}
262
	}
263
	close(ctl_sock);
264
	free(ibuf);
265
266
	return (0);
267
}
268
269
uint64_t
270
get_ifms_type(uint8_t if_type)
271
{
272
	switch (if_type) {
273
	case IFT_ETHER:
274
		return (IFM_ETHER);
275
		break;
276
	case IFT_FDDI:
277
		return (IFM_FDDI);
278
		break;
279
	case IFT_CARP:
280
		return (IFM_CARP);
281
		break;
282
	default:
283
		return (0);
284
		break;
285
	}
286
}
287
288
#define	TF_BUFS	8
289
#define	TF_LEN	9
290
291
const char *
292
fmt_timeframe_core(time_t t)
293
{
294
	char		*buf;
295
	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
296
	static int	 idx = 0;
297
	unsigned int	 sec, min, hrs, day, week;
298
299
	if (t == 0)
300
		return ("Stopped");
301
302
	buf = tfbuf[idx++];
303
	if (idx == TF_BUFS)
304
		idx = 0;
305
306
	week = t;
307
308
	sec = week % 60;
309
	week /= 60;
310
	min = week % 60;
311
	week /= 60;
312
	hrs = week % 24;
313
	week /= 24;
314
	day = week % 7;
315
	week /= 7;
316
317
	if (week > 0)
318
		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
319
	else if (day > 0)
320
		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
321
	else
322
		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
323
324
	return (buf);
325
}
326
327
int
328
show_interface_msg(struct imsg *imsg, struct parse_result *res)
329
{
330
	struct ctl_iface	*iface;
331
	char			*timers;
332
333
	switch (imsg->hdr.type) {
334
	case IMSG_CTL_SHOW_INTERFACE:
335
		iface = imsg->data;
336
337
		if (res->family != AF_UNSPEC && res->family != iface->af)
338
			break;
339
340
		if (asprintf(&timers, "%u/%u", iface->hello_interval,
341
		    iface->hello_holdtime) == -1)
342
			err(1, NULL);
343
344
		printf("%-4s %-11s %-6s %-10s %-8s %-12s %3u\n",
345
		    af_name(iface->af), iface->name,
346
		    if_state_name(iface->state), get_linkstate(iface->if_type,
347
		    iface->linkstate), iface->uptime == 0 ? "00:00:00" :
348
		    fmt_timeframe_core(iface->uptime), timers, iface->adj_cnt);
349
		free(timers);
350
		break;
351
	case IMSG_CTL_END:
352
		printf("\n");
353
		return (1);
354
	default:
355
		break;
356
	}
357
358
	return (0);
359
}
360
361
int
362
show_discovery_msg(struct imsg *imsg, struct parse_result *res)
363
{
364
	struct ctl_adj	*adj;
365
	const char	*addr;
366
367
	switch (imsg->hdr.type) {
368
	case IMSG_CTL_SHOW_DISCOVERY:
369
		adj = imsg->data;
370
371
		if (res->family != AF_UNSPEC && res->family != adj->af)
372
			break;
373
374
		printf("%-4s %-15s ", af_name(adj->af), inet_ntoa(adj->id));
375
		switch(adj->type) {
376
		case HELLO_LINK:
377
			printf("%-8s %-15s ", "Link", adj->ifname);
378
			break;
379
		case HELLO_TARGETED:
380
			addr = log_addr(adj->af, &adj->src_addr);
381
382
			printf("%-8s %-15s ", "Targeted", addr);
383
			if (strlen(addr) > 15)
384
				printf("\n%46s", " ");
385
			break;
386
		}
387
		printf("%9u\n", adj->holdtime);
388
		break;
389
	case IMSG_CTL_END:
390
		printf("\n");
391
		return (1);
392
	default:
393
		break;
394
	}
395
396
	return (0);
397
}
398
399
int
400
show_lib_msg(struct imsg *imsg, struct parse_result *res)
401
{
402
	struct ctl_rt	*rt;
403
	char		*dstnet;
404
405
	switch (imsg->hdr.type) {
406
	case IMSG_CTL_SHOW_LIB:
407
		rt = imsg->data;
408
409
		if (res->family != AF_UNSPEC && res->family != rt->af)
410
			break;
411
412
		if (asprintf(&dstnet, "%s/%d", log_addr(rt->af, &rt->prefix),
413
		    rt->prefixlen) == -1)
414
			err(1, NULL);
415
416
		printf("%-4s %-20s", af_name(rt->af), dstnet);
417
		if (strlen(dstnet) > 20)
418
			printf("\n%25s", " ");
419
		printf(" %-15s %-11s %-13s %6s\n", inet_ntoa(rt->nexthop),
420
		    log_label(rt->local_label), log_label(rt->remote_label),
421
		    rt->in_use ? "yes" : "no");
422
423
		free(dstnet);
424
		break;
425
	case IMSG_CTL_END:
426
		printf("\n");
427
		return (1);
428
	default:
429
		break;
430
	}
431
432
	return (0);
433
}
434
435
int
436
show_nbr_msg(struct imsg *imsg, struct parse_result *res)
437
{
438
	struct ctl_nbr	*nbr;
439
	const char	*addr;
440
441
	switch (imsg->hdr.type) {
442
	case IMSG_CTL_SHOW_NBR:
443
		nbr = imsg->data;
444
445
		if (res->family != AF_UNSPEC && res->family != nbr->af)
446
			break;
447
448
		addr = log_addr(nbr->af, &nbr->raddr);
449
450
		printf("%-4s %-15s %-11s %-15s",
451
		    af_name(nbr->af), inet_ntoa(nbr->id),
452
		    nbr_state_name(nbr->nbr_state), addr);
453
		if (strlen(addr) > 15)
454
			printf("\n%48s", " ");
455
		printf(" %8s\n", nbr->uptime == 0 ? "-" :
456
		    fmt_timeframe_core(nbr->uptime));
457
		break;
458
	case IMSG_CTL_END:
459
		printf("\n");
460
		return (1);
461
	default:
462
		break;
463
	}
464
465
	return (0);
466
}
467
468
void
469
show_fib_head(void)
470
{
471
	printf("Flags: C = Connected, S = Static\n");
472
	printf(" %-4s %-20s %-17s %-17s %s\n", "Prio", "Destination",
473
	    "Nexthop", "Local Label", "Remote Label");
474
}
475
476
int
477
show_fib_msg(struct imsg *imsg, struct parse_result *res)
478
{
479
	struct kroute	*k;
480
	char		*p;
481
	const char	*nexthop;
482
483
	switch (imsg->hdr.type) {
484
	case IMSG_CTL_KROUTE:
485
		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
486
			errx(1, "wrong imsg len");
487
		k = imsg->data;
488
489
		if (res->family != AF_UNSPEC && res->family != k->af)
490
			break;
491
492
		if (k->flags & F_CONNECTED)
493
			printf("C");
494
		else if (k->flags & F_STATIC)
495
			printf("S");
496
		else
497
			printf(" ");
498
499
		printf(" %3d ", k->priority);
500
		if (asprintf(&p, "%s/%u", log_addr(k->af, &k->prefix),
501
		    k->prefixlen) == -1)
502
			err(1, NULL);
503
		printf("%-20s ", p);
504
		if (strlen(p) > 20)
505
			printf("\n%27s", " ");
506
		free(p);
507
508
		if (ldp_addrisset(k->af, &k->nexthop)) {
509
			switch (k->af) {
510
			case AF_INET:
511
				printf("%-18s", inet_ntoa(k->nexthop.v4));
512
				break;
513
			case AF_INET6:
514
				nexthop = log_in6addr_scope(&k->nexthop.v6,
515
				    k->ifindex);
516
				printf("%-18s", nexthop);
517
				if (strlen(nexthop) > 18)
518
					printf("\n%45s", " ");
519
				break;
520
			default:
521
				printf("%-18s", " ");
522
				break;
523
			}
524
		} else if (k->flags & F_CONNECTED)
525
			printf("link#%-13u", k->ifindex);
526
527
		printf("%-18s", log_label(k->local_label));
528
		printf("%s", log_label(k->remote_label));
529
		printf("\n");
530
		break;
531
	case IMSG_CTL_END:
532
		printf("\n");
533
		return (1);
534
	default:
535
		break;
536
	}
537
538
	return (0);
539
}
540
541
void
542
show_interface_head(void)
543
{
544
	printf("%-15s%-15s%s\n", "Interface", "Flags",
545
	    "Link state");
546
}
547
548
int
549
show_fib_interface_msg(struct imsg *imsg)
550
{
551
	struct kif	*k;
552
	uint64_t	 ifms_type;
553
554
	switch (imsg->hdr.type) {
555
	case IMSG_CTL_IFINFO:
556
		k = imsg->data;
557
		printf("%-15s", k->ifname);
558
		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
559
		ifms_type = get_ifms_type(k->if_type);
560
		if (ifms_type)
561
			printf("%s, ", get_media_descr(ifms_type));
562
563
		printf("%s", get_linkstate(k->if_type, k->link_state));
564
565
		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
566
			printf(", ");
567
			print_baudrate(k->baudrate);
568
		}
569
		printf("\n");
570
		break;
571
	case IMSG_CTL_END:
572
		printf("\n");
573
		return (1);
574
	default:
575
		break;
576
	}
577
578
	return (0);
579
}
580
581
int
582
show_l2vpn_pw_msg(struct imsg *imsg)
583
{
584
	struct ctl_pw	*pw;
585
586
	switch (imsg->hdr.type) {
587
	case IMSG_CTL_SHOW_L2VPN_PW:
588
		pw = imsg->data;
589
590
		printf("%-11s %-15s %-14u %-10s\n", pw->ifname,
591
		    inet_ntoa(pw->lsr_id), pw->pwid,
592
		    (pw->status ? "UP" : "DOWN"));
593
		break;
594
	case IMSG_CTL_END:
595
		printf("\n");
596
		return (1);
597
	default:
598
		break;
599
	}
600
601
	return (0);
602
}
603
604
int
605
show_l2vpn_binding_msg(struct imsg *imsg)
606
{
607
	struct ctl_pw	*pw;
608
609
	switch (imsg->hdr.type) {
610
	case IMSG_CTL_SHOW_L2VPN_BINDING:
611
		pw = imsg->data;
612
613
		printf("Neighbor: %s - PWID: %u (%s)\n",
614
		    inet_ntoa(pw->lsr_id), pw->pwid,
615
		    pw_type_name(pw->type));
616
		printf("%-12s%-15s%-15s%-10s\n", "", "Label", "Group-ID",
617
		    "MTU");
618
		if (pw->local_label != NO_LABEL)
619
			printf("  %-10s%-15u%-15u%u\n", "Local",
620
			    pw->local_label, pw->local_gid, pw->local_ifmtu);
621
		else
622
			printf("  %-10s%-15s%-15s%s\n", "Local", "-",
623
			    "-", "-");
624
		if (pw->remote_label != NO_LABEL)
625
			printf("  %-10s%-15u%-15u%u\n", "Remote",
626
			    pw->remote_label, pw->remote_gid,
627
			    pw->remote_ifmtu);
628
		else
629
			printf("  %-10s%-15s%-15s%s\n", "Remote", "-",
630
			    "-", "-");
631
		break;
632
	case IMSG_CTL_END:
633
		printf("\n");
634
		return (1);
635
	default:
636
		break;
637
	}
638
639
	return (0);
640
}
641
642
const struct if_status_description
643
		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
644
const struct ifmedia_description
645
		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
646
647
const char *
648
get_media_descr(uint64_t media_type)
649
{
650
	const struct ifmedia_description	*p;
651
652
	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
653
		if (media_type == p->ifmt_word)
654
			return (p->ifmt_string);
655
656
	return ("unknown");
657
}
658
659
const char *
660
get_linkstate(uint8_t if_type, int link_state)
661
{
662
	const struct if_status_description *p;
663
	static char buf[8];
664
665
	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
666
		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
667
			return (p->ifs_string);
668
	}
669
	snprintf(buf, sizeof(buf), "[#%d]", link_state);
670
	return (buf);
671
}
672
673
void
674
print_baudrate(uint64_t baudrate)
675
{
676
	if (baudrate > IF_Gbps(1))
677
		printf("%llu GBit/s", baudrate / IF_Gbps(1));
678
	else if (baudrate > IF_Mbps(1))
679
		printf("%llu MBit/s", baudrate / IF_Mbps(1));
680
	else if (baudrate > IF_Kbps(1))
681
		printf("%llu KBit/s", baudrate / IF_Kbps(1));
682
	else
683
		printf("%llu Bit/s", baudrate);
684
}