xref: /openbsd/usr.sbin/ldpctl/ldpctl.c (revision e5dd7070)
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", 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 }
685