1 /*	$OpenBSD: util.c,v 1.93 2025/02/04 18:16:56 denis Exp $ */
2 
3 /*
4  * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #include <endian.h>
24 #include <errno.h>
25 #include <netdb.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <vis.h>
30 
31 #include "bgpd.h"
32 #include "rde.h"
33 #include "log.h"
34 
35 const char *
log_addr(const struct bgpd_addr * addr)36 log_addr(const struct bgpd_addr *addr)
37 {
38 	static char	buf[74];
39 	struct sockaddr *sa;
40 	socklen_t	len;
41 
42 	sa = addr2sa(addr, 0, &len);
43 	switch (addr->aid) {
44 	case AID_INET:
45 	case AID_INET6:
46 		return log_sockaddr(sa, len);
47 	case AID_VPN_IPv4:
48 	case AID_VPN_IPv6:
49 		snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
50 		    log_sockaddr(sa, len));
51 		return (buf);
52 	case AID_EVPN:
53 		return log_evpnaddr(addr, sa, len);
54 		break;
55 	}
56 	return ("???");
57 }
58 
59 static const char *
log_mac(const uint8_t mac[ETHER_ADDR_LEN])60 log_mac(const uint8_t mac[ETHER_ADDR_LEN])
61 {
62 	static char buf[18];
63 
64 	snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0],
65 	    mac[1], mac[2], mac[3], mac[4], mac[5]);
66 
67 	return (buf);
68 }
69 
70 static const uint8_t zero_esi[ESI_ADDR_LEN];
71 
72 static const char *
log_esi(const uint8_t esi[ESI_ADDR_LEN])73 log_esi(const uint8_t esi[ESI_ADDR_LEN])
74 {
75 	static char buf[30];
76 
77 	if (memcmp(esi, zero_esi, sizeof(zero_esi)) == 0)
78 		return ("");
79 
80 	snprintf(buf, sizeof(buf),
81 	    "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", esi[0],
82 	    esi[1], esi[2], esi[3], esi[4], esi[5], esi[6], esi[7], esi[8],
83 	    esi[9]);
84 
85 	return (buf);
86 }
87 
88 const char *
log_evpnaddr(const struct bgpd_addr * addr,struct sockaddr * sa,socklen_t salen)89 log_evpnaddr(const struct bgpd_addr *addr, struct sockaddr *sa,
90     socklen_t salen)
91 {
92 	static char	buf[138];
93 	uint32_t	vni;
94 	uint8_t		len;
95 
96 	switch(addr->evpn.type) {
97 	case EVPN_ROUTE_TYPE_2:
98 		memcpy(&vni, addr->labelstack, addr->labellen);
99 		snprintf(buf, sizeof(buf), "[2]:[%s]:[%s]:[%d]:[48]:[%s]",
100 		    log_rd(addr->rd),log_esi(addr->evpn.esi), htonl(vni)>>8,
101 		    log_mac(addr->evpn.mac));
102 		if (sa != NULL) {
103 			len = strlen(buf);
104 			snprintf(buf+len, sizeof(buf)-len, ":[%d]:[%s]",
105 			    sa->sa_family == AF_INET ? 32 : 128,
106 			    log_sockaddr(sa, salen));
107 		}
108 		break;
109 	case EVPN_ROUTE_TYPE_3:
110 		if (sa != NULL) {
111 	  		memcpy(&vni, addr->labelstack, addr->labellen);
112 			snprintf(buf, sizeof(buf), "[3]:[%s]:[%d]:[%s]",
113 			    log_rd(addr->rd),
114 			    sa->sa_family == AF_INET ? 32 : 128,
115 			    log_sockaddr(sa, salen));
116 		}
117 		break;
118 	default:
119 		break;
120 	}
121 	return (buf);
122 }
123 
124 const char *
log_in6addr(const struct in6_addr * addr)125 log_in6addr(const struct in6_addr *addr)
126 {
127 	struct sockaddr_in6	sa_in6;
128 
129 	memset(&sa_in6, 0, sizeof(sa_in6));
130 	sa_in6.sin6_family = AF_INET6;
131 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
132 
133 #ifdef __KAME__
134 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
135 	if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
136 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) ||
137 	    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) &&
138 	    sa_in6.sin6_scope_id == 0) {
139 		uint16_t tmp16;
140 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
141 		sa_in6.sin6_scope_id = ntohs(tmp16);
142 		sa_in6.sin6_addr.s6_addr[2] = 0;
143 		sa_in6.sin6_addr.s6_addr[3] = 0;
144 	}
145 #endif
146 
147 	return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
148 }
149 
150 const char *
log_sockaddr(struct sockaddr * sa,socklen_t len)151 log_sockaddr(struct sockaddr *sa, socklen_t len)
152 {
153 	static char	buf[4][NI_MAXHOST];
154 	static int	bufidx;
155 
156 	bufidx = (bufidx + 1) % 4;
157 	if (sa == NULL || getnameinfo(sa, len, buf[bufidx], sizeof(buf[0]),
158 	    NULL, 0, NI_NUMERICHOST))
159 		return ("(unknown)");
160 	else
161 		return (buf[bufidx]);
162 }
163 
164 const char *
log_as(uint32_t as)165 log_as(uint32_t as)
166 {
167 	static char	buf[11];	/* "4294967294\0" */
168 
169 	if (snprintf(buf, sizeof(buf), "%u", as) < 0)
170 		return ("?");
171 
172 	return (buf);
173 }
174 
175 const char *
log_rd(uint64_t rd)176 log_rd(uint64_t rd)
177 {
178 	static char	buf[32];
179 	struct in_addr	addr;
180 	uint32_t	u32;
181 	uint16_t	u16;
182 
183 	rd = be64toh(rd);
184 	switch (rd >> 48) {
185 	case EXT_COMMUNITY_TRANS_TWO_AS:
186 		u32 = rd & 0xffffffff;
187 		u16 = (rd >> 32) & 0xffff;
188 		snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
189 		break;
190 	case EXT_COMMUNITY_TRANS_FOUR_AS:
191 		u32 = (rd >> 16) & 0xffffffff;
192 		u16 = rd & 0xffff;
193 		snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
194 		break;
195 	case EXT_COMMUNITY_TRANS_IPV4:
196 		u32 = (rd >> 16) & 0xffffffff;
197 		u16 = rd & 0xffff;
198 		addr.s_addr = htonl(u32);
199 		snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
200 		break;
201 	default:
202 		snprintf(buf, sizeof(buf), "rd #%016llx",
203 		    (unsigned long long)rd);
204 		break;
205 	}
206 	return (buf);
207 }
208 
209 const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
210 
211 /* NOTE: this function does not check if the type/subtype combo is
212  * actually valid. */
213 const char *
log_ext_subtype(int type,uint8_t subtype)214 log_ext_subtype(int type, uint8_t subtype)
215 {
216 	static char etype[16];
217 	const struct ext_comm_pairs *cp;
218 
219 	for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
220 		if ((type == cp->type || type == -1) && subtype == cp->subtype)
221 			return (cp->subname);
222 	}
223 	if (type == -1)
224 		return ("???");
225 	snprintf(etype, sizeof(etype), "[%hhx:%hhx]", (uint8_t)type, subtype);
226 	return (etype);
227 }
228 
229 const char *
log_reason(const char * communication)230 log_reason(const char *communication) {
231 	static char buf[(REASON_LEN - 1) * 4 + 1];
232 
233 	strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
234 
235 	return buf;
236 }
237 
238 static const char *
log_expires(time_t expires)239 log_expires(time_t expires)
240 {
241 	static char buf[32];
242 
243 	buf[0] = '\0';
244 	if (expires != 0)
245 		snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
246 	return buf;
247 }
248 
249 const char *
log_roa(struct roa * roa)250 log_roa(struct roa *roa)
251 {
252 	static char buf[256];
253 	char maxbuf[32];
254 #if defined(__GNUC__) && __GNUC__ < 4
255 	struct bgpd_addr addr = { .aid = roa->aid };
256 	addr.v6 = roa->prefix.inet6;
257 #else
258 	struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 };
259 #endif
260 
261 	maxbuf[0] = '\0';
262 	if (roa->prefixlen != roa->maxlen)
263 		snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
264 	snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
265 	    roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
266 	return buf;
267 }
268 
269 const char *
log_aspa(struct aspa_set * aspa)270 log_aspa(struct aspa_set *aspa)
271 {
272 	static char errbuf[256];
273 	static char *buf;
274 	static size_t len;
275 	char asbuf[16];
276 	size_t needed;
277 	uint32_t i;
278 
279 	/* include enough space for header and trailer */
280 	if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72))
281 		goto fail;
282 	needed = aspa->num * sizeof(asbuf) + 72;
283 	if (needed > len) {
284 		char *nbuf;
285 
286 		if ((nbuf = realloc(buf, needed)) == NULL)
287 			goto fail;
288 		len = needed;
289 		buf = nbuf;
290 	}
291 
292 	snprintf(buf, len, "customer-as %s%s provider-as { ",
293 	    log_as(aspa->as), log_expires(aspa->expires));
294 
295 	for (i = 0; i < aspa->num; i++) {
296 		snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
297 		if (strlcat(buf, asbuf, len) >= len)
298 			goto fail;
299 	}
300 	if (strlcat(buf, "}", len) >= len)
301 		goto fail;
302 	return buf;
303 
304  fail:
305 	free(buf);
306 	buf = NULL;
307 	len = 0;
308 	snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
309 	    log_as(aspa->as), log_expires(aspa->expires));
310 	return errbuf;
311 }
312 
313 const char *
log_aspath_error(int error)314 log_aspath_error(int error)
315 {
316 	static char buf[20];
317 
318 	switch (error) {
319 	case AS_ERR_LEN:
320 		return "inconsistent length";
321 	case AS_ERR_TYPE:
322 		return "unknown segment type";
323 	case AS_ERR_BAD:
324 		return "invalid encoding";
325 	case AS_ERR_SOFT:
326 		return "soft failure";
327 	default:
328 		snprintf(buf, sizeof(buf), "unknown %d", error);
329 		return buf;
330 	}
331 }
332 
333 const char *
log_rtr_error(enum rtr_error err)334 log_rtr_error(enum rtr_error err)
335 {
336 	static char buf[20];
337 
338 	switch (err) {
339 	case NO_ERROR:
340 		return "No Error";
341 	case CORRUPT_DATA:
342 		return "Corrupt Data";
343 	case INTERNAL_ERROR:
344 		return "Internal Error";
345 	case NO_DATA_AVAILABLE:
346 		return "No Data Available";
347 	case INVALID_REQUEST:
348 		return "Invalid Request";
349 	case UNSUPP_PROTOCOL_VERS:
350 		return "Unsupported Protocol Version";
351 	case UNSUPP_PDU_TYPE:
352 		return "Unsupported PDU Type";
353 	case UNK_REC_WDRAWL:
354 		return "Withdrawal of Unknown Record";
355 	case DUP_REC_RECV:
356 		return "Duplicate Announcement Received";
357 	case UNEXP_PROTOCOL_VERS:
358 		return "Unexpected Protocol Version";
359 	default:
360 		snprintf(buf, sizeof(buf), "unknown %u", err);
361 		return buf;
362 	}
363 }
364 
365 const char *
log_policy(enum role role)366 log_policy(enum role role)
367 {
368 	switch (role) {
369 	case ROLE_PROVIDER:
370 		return "provider";
371 	case ROLE_RS:
372 		return "rs";
373 	case ROLE_RS_CLIENT:
374 		return "rs-client";
375 	case ROLE_CUSTOMER:
376 		return "customer";
377 	case ROLE_PEER:
378 		return "peer";
379 	default:
380 		return "unknown";
381 	}
382 }
383 
384 const char *
log_capability(uint8_t capa)385 log_capability(uint8_t capa)
386 {
387 	static char buf[20];
388 
389 	switch (capa) {
390 	case CAPA_MP:
391 		return "Multiprotocol Extensions";
392 	case CAPA_REFRESH:
393 		return "Route Refresh";
394 	case CAPA_EXT_NEXTHOP:
395 		return "Extended Nexhop Encoding";
396 	case CAPA_EXT_MSG:
397 		return "Extended Message";
398 	case CAPA_ROLE:
399 		return "BGP Role";
400 	case CAPA_RESTART:
401 		return "Graceful Restart";
402 	case CAPA_AS4BYTE:
403 		return "4-octet AS number";
404 	case CAPA_ADD_PATH:
405 		return "ADD-PATH";
406 	case CAPA_ENHANCED_RR:
407 		return "Enhanced Route Refresh";
408 	default:
409 		snprintf(buf, sizeof(buf), "unknown %u", capa);
410 		return buf;
411 	}
412 }
413 
414 static const char *
aspath_delim(uint8_t seg_type,int closing)415 aspath_delim(uint8_t seg_type, int closing)
416 {
417 	static char db[8];
418 
419 	switch (seg_type) {
420 	case AS_SET:
421 		if (!closing)
422 			return ("{ ");
423 		else
424 			return (" }");
425 	case AS_SEQUENCE:
426 		return ("");
427 	case AS_CONFED_SEQUENCE:
428 		if (!closing)
429 			return ("( ");
430 		else
431 			return (" )");
432 	case AS_CONFED_SET:
433 		if (!closing)
434 			return ("[ ");
435 		else
436 			return (" ]");
437 	default:
438 		if (!closing)
439 			snprintf(db, sizeof(db), "!%u ", seg_type);
440 		else
441 			snprintf(db, sizeof(db), " !%u", seg_type);
442 		return (db);
443 	}
444 }
445 
446 static int
aspath_snprint(char * buf,size_t size,struct ibuf * in)447 aspath_snprint(char *buf, size_t size, struct ibuf *in)
448 {
449 #define UPDATE()						\
450 	do {							\
451 		if (r < 0 || (unsigned int)r >= size)		\
452 			return (-1);				\
453 		size -= r;					\
454 		buf += r;					\
455 	} while (0)
456 
457 	struct ibuf	data;
458 	uint32_t	as;
459 	int		r, n = 0;
460 	uint8_t		i, seg_type, seg_len;
461 
462 	ibuf_from_ibuf(&data, in);
463 	while (ibuf_size(&data) > 0) {
464 		if (ibuf_get_n8(&data, &seg_type) == -1 ||
465 		    ibuf_get_n8(&data, &seg_len) == -1 ||
466 		    seg_len == 0)
467 			return (-1);
468 
469 		r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
470 		    aspath_delim(seg_type, 0));
471 		UPDATE();
472 
473 		for (i = 0; i < seg_len; i++) {
474 			if (ibuf_get_n32(&data, &as) == -1)
475 				return -1;
476 
477 			r = snprintf(buf, size, "%s", log_as(as));
478 			UPDATE();
479 			if (i + 1 < seg_len) {
480 				r = snprintf(buf, size, " ");
481 				UPDATE();
482 			}
483 		}
484 		r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
485 		UPDATE();
486 	}
487 	/* ensure that we have a valid C-string especially for empty as path */
488 	*buf = '\0';
489 	return (0);
490 #undef UPDATE
491 }
492 
493 static ssize_t
aspath_strsize(struct ibuf * in)494 aspath_strsize(struct ibuf *in)
495 {
496 	struct ibuf	 buf;
497 	ssize_t		 total_size = 0;
498 	uint32_t	 as;
499 	uint8_t		 i, seg_type, seg_len;
500 
501 	ibuf_from_ibuf(&buf, in);
502 	while (ibuf_size(&buf) > 0) {
503 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
504 		    ibuf_get_n8(&buf, &seg_len) == -1 ||
505 		    seg_len == 0)
506 			return (-1);
507 
508 		if (total_size != 0)
509 			total_size += 1;
510 		total_size += strlen(aspath_delim(seg_type, 0));
511 
512 		for (i = 0; i < seg_len; i++) {
513 			if (ibuf_get_n32(&buf, &as) == -1)
514 				return (-1);
515 
516 			do {
517 				total_size++;
518 			} while ((as = as / 10) != 0);
519 		}
520 		total_size += seg_len - 1;
521 
522 		total_size += strlen(aspath_delim(seg_type, 1));
523 	}
524 	return (total_size + 1);
525 }
526 
527 int
aspath_asprint(char ** ret,struct ibuf * data)528 aspath_asprint(char **ret, struct ibuf *data)
529 {
530 	ssize_t	slen;
531 
532 	if ((slen = aspath_strsize(data)) == -1) {
533 		*ret = NULL;
534 		errno = EINVAL;
535 		return (-1);
536 	}
537 
538 	*ret = malloc(slen);
539 	if (*ret == NULL)
540 		return (-1);
541 
542 	if (aspath_snprint(*ret, slen, data) == -1) {
543 		free(*ret);
544 		*ret = NULL;
545 		errno = EINVAL;
546 		return (-1);
547 	}
548 
549 	return (0);
550 }
551 
552 /*
553  * Extract the asnum out of the as segment at the specified position.
554  * Direct access is not possible because of non-aligned reads.
555  * Only works on verified 4-byte AS paths.
556  */
557 uint32_t
aspath_extract(const void * seg,int pos)558 aspath_extract(const void *seg, int pos)
559 {
560 	const u_char	*ptr = seg;
561 	uint32_t	 as;
562 
563 	/* minimal pos check, return 0 since that is an invalid ASN */
564 	if (pos < 0 || pos >= ptr[1])
565 		return (0);
566 	ptr += 2 + sizeof(uint32_t) * pos;
567 	memcpy(&as, ptr, sizeof(uint32_t));
568 	return (ntohl(as));
569 }
570 
571 /*
572  * Verify that the aspath is correctly encoded.
573  */
574 int
aspath_verify(struct ibuf * in,int as4byte,int permit_set)575 aspath_verify(struct ibuf *in, int as4byte, int permit_set)
576 {
577 	struct ibuf	 buf;
578 	int		 pos, error = 0;
579 	uint8_t		 seg_len, seg_type;
580 
581 	ibuf_from_ibuf(&buf, in);
582 	if (ibuf_size(&buf) & 1) {
583 		/* odd length aspath are invalid */
584 		error = AS_ERR_BAD;
585 		goto done;
586 	}
587 
588 	while (ibuf_size(&buf) > 0) {
589 		if (ibuf_get_n8(&buf, &seg_type) == -1 ||
590 		    ibuf_get_n8(&buf, &seg_len) == -1) {
591 			error = AS_ERR_LEN;
592 			goto done;
593 		}
594 
595 		if (seg_len == 0) {
596 			/* empty aspath segments are not allowed */
597 			error = AS_ERR_BAD;
598 			goto done;
599 		}
600 
601 		/*
602 		 * BGP confederations should not show up but consider them
603 		 * as a soft error which invalidates the path but keeps the
604 		 * bgp session running.
605 		 */
606 		if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
607 			error = AS_ERR_SOFT;
608 		/*
609 		 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
610 		 * as well.
611 		 */
612 		if (!permit_set && seg_type == AS_SET)
613 			error = AS_ERR_SOFT;
614 		if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
615 		    seg_type != AS_CONFED_SEQUENCE &&
616 		    seg_type != AS_CONFED_SET) {
617 			error = AS_ERR_TYPE;
618 			goto done;
619 		}
620 
621 		/* RFC 7607 - AS 0 is considered malformed */
622 		for (pos = 0; pos < seg_len; pos++) {
623 			uint32_t as;
624 
625 			if (as4byte) {
626 				if (ibuf_get_n32(&buf, &as) == -1) {
627 					error = AS_ERR_LEN;
628 					goto done;
629 				}
630 			} else {
631 				uint16_t tmp;
632 				if (ibuf_get_n16(&buf, &tmp) == -1) {
633 					error = AS_ERR_LEN;
634 					goto done;
635 				}
636 				as = tmp;
637 			}
638 			if (as == 0)
639 				error = AS_ERR_SOFT;
640 		}
641 	}
642 
643  done:
644 	return (error);	/* aspath is valid but probably not loop free */
645 }
646 
647 /*
648  * convert a 2 byte aspath to a 4 byte one.
649  */
650 struct ibuf *
aspath_inflate(struct ibuf * in)651 aspath_inflate(struct ibuf *in)
652 {
653 	struct ibuf	*out;
654 	uint16_t	 short_as;
655 	uint8_t		 seg_type, seg_len;
656 
657 	/*
658 	 * Allocate enough space for the worst case.
659 	 * XXX add 1 byte for the empty ASPATH case since we can't
660 	 * allocate an ibuf of 0 length.
661 	 */
662 	if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL)
663 		return (NULL);
664 
665 	/* then copy the aspath */
666 	while (ibuf_size(in) > 0) {
667 		if (ibuf_get_n8(in, &seg_type) == -1 ||
668 		    ibuf_get_n8(in, &seg_len) == -1 ||
669 		    seg_len == 0)
670 			goto fail;
671 		if (ibuf_add_n8(out, seg_type) == -1 ||
672 		    ibuf_add_n8(out, seg_len) == -1)
673 			goto fail;
674 
675 		for (; seg_len > 0; seg_len--) {
676 			if (ibuf_get_n16(in, &short_as) == -1)
677 				goto fail;
678 			if (ibuf_add_n32(out, short_as) == -1)
679 				goto fail;
680 		}
681 	}
682 
683 	return (out);
684 
685 fail:
686 	ibuf_free(out);
687 	return (NULL);
688 }
689 
690 static const u_char	addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
691 			    0xf8, 0xfc, 0xfe, 0xff };
692 
693 /* NLRI functions to extract prefixes from the NLRI blobs */
694 int
extract_prefix(const u_char * p,int len,void * va,uint8_t pfxlen,uint8_t max)695 extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
696 {
697 	u_char		*a = va;
698 	int		 plen;
699 
700 	plen = PREFIX_SIZE(pfxlen) - 1;
701 	if (len < plen || max < plen)
702 		return -1;
703 
704 	while (pfxlen > 0) {
705 		if (pfxlen < 8) {
706 			*a++ = *p++ & addrmask[pfxlen];
707 			break;
708 		} else {
709 			*a++ = *p++;
710 			pfxlen -= 8;
711 		}
712 	}
713 	return (plen);
714 }
715 
716 static int
extract_prefix_buf(struct ibuf * buf,void * va,uint8_t pfxlen,uint8_t max)717 extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max)
718 {
719 	u_char		*a = va;
720 	unsigned int	 plen;
721 	uint8_t		 tmp;
722 
723 	plen = PREFIX_SIZE(pfxlen) - 1;
724 	if (ibuf_size(buf) < plen || max < plen)
725 		return -1;
726 
727 	while (pfxlen > 0) {
728 		if (ibuf_get_n8(buf, &tmp) == -1)
729 			return -1;
730 
731 		if (pfxlen < 8) {
732 			*a++ = tmp & addrmask[pfxlen];
733 			break;
734 		} else {
735 			*a++ = tmp;
736 			pfxlen -= 8;
737 		}
738 	}
739 	return (0);
740 }
741 
742 int
nlri_get_prefix(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)743 nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
744 {
745 	uint8_t	 pfxlen;
746 
747 	if (ibuf_get_n8(buf, &pfxlen) == -1)
748 		return (-1);
749 	if (pfxlen > 32)
750 		return (-1);
751 
752 	memset(prefix, 0, sizeof(struct bgpd_addr));
753 	prefix->aid = AID_INET;
754 
755 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
756 	    sizeof(prefix->v4)) == -1)
757 		return (-1);
758 
759 	*prefixlen = pfxlen;
760 	return (0);
761 }
762 
763 int
nlri_get_prefix6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)764 nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
765 {
766 	uint8_t	pfxlen;
767 
768 	if (ibuf_get_n8(buf, &pfxlen) == -1)
769 		return (-1);
770 	if (pfxlen > 128)
771 		return (-1);
772 
773 	memset(prefix, 0, sizeof(struct bgpd_addr));
774 	prefix->aid = AID_INET6;
775 
776 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
777 	    sizeof(prefix->v6)) == -1)
778 		return (-1);
779 
780 	*prefixlen = pfxlen;
781 	return (0);
782 }
783 
784 int
nlri_get_vpn4(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)785 nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix,
786     uint8_t *prefixlen, int withdraw)
787 {
788 	int		 done = 0;
789 	uint8_t		 pfxlen;
790 
791 	if (ibuf_get_n8(buf, &pfxlen) == -1)
792 		return (-1);
793 
794 	memset(prefix, 0, sizeof(struct bgpd_addr));
795 	prefix->aid = AID_VPN_IPv4;
796 
797 	/* label stack */
798 	do {
799 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
800 		    pfxlen < 3 * 8)
801 			return (-1);
802 		if (withdraw) {
803 			/* on withdraw ignore the labelstack all together */
804 			if (ibuf_skip(buf, 3) == -1)
805 				return (-1);
806 			pfxlen -= 3 * 8;
807 			break;
808 		}
809 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
810 		    -1)
811 			return -1;
812 		if (prefix->labelstack[prefix->labellen + 2] &
813 		    BGP_MPLS_BOS)
814 			done = 1;
815 		prefix->labellen += 3;
816 		pfxlen -= 3 * 8;
817 	} while (!done);
818 
819 	/* RD */
820 	if (pfxlen < sizeof(uint64_t) * 8 ||
821 	    ibuf_get_h64(buf, &prefix->rd) == -1)
822 		return (-1);
823 	pfxlen -= sizeof(uint64_t) * 8;
824 
825 	/* prefix */
826 	if (pfxlen > 32)
827 		return (-1);
828 	if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
829 	    sizeof(prefix->v4)) == -1)
830 		return (-1);
831 
832 	*prefixlen = pfxlen;
833 	return (0);
834 }
835 
836 int
nlri_get_vpn6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)837 nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix,
838     uint8_t *prefixlen, int withdraw)
839 {
840 	int		done = 0;
841 	uint8_t		pfxlen;
842 
843 	if (ibuf_get_n8(buf, &pfxlen) == -1)
844 		return (-1);
845 
846 	memset(prefix, 0, sizeof(struct bgpd_addr));
847 	prefix->aid = AID_VPN_IPv6;
848 
849 	/* label stack */
850 	do {
851 		if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
852 		    pfxlen < 3 * 8)
853 			return (-1);
854 		if (withdraw) {
855 			/* on withdraw ignore the labelstack all together */
856 			if (ibuf_skip(buf, 3) == -1)
857 				return (-1);
858 			pfxlen -= 3 * 8;
859 			break;
860 		}
861 
862 		if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
863 		    -1)
864 			return (-1);
865 		if (prefix->labelstack[prefix->labellen + 2] &
866 		    BGP_MPLS_BOS)
867 			done = 1;
868 		prefix->labellen += 3;
869 		pfxlen -= 3 * 8;
870 	} while (!done);
871 
872 	/* RD */
873 	if (pfxlen < sizeof(uint64_t) * 8 ||
874 	    ibuf_get_h64(buf, &prefix->rd) == -1)
875 		return (-1);
876 	pfxlen -= sizeof(uint64_t) * 8;
877 
878 	/* prefix */
879 	if (pfxlen > 128)
880 		return (-1);
881 	if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
882 	    sizeof(prefix->v6)) == -1)
883 		return (-1);
884 
885 	*prefixlen = pfxlen;
886 	return (0);
887 }
888 
889 int
nlri_get_evpn(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)890 nlri_get_evpn(struct ibuf *buf, struct bgpd_addr *prefix,
891     uint8_t *prefixlen)
892 {
893 	struct ibuf	evpnbuf;
894 	uint8_t		nlrilen, type, pfxlen = 0, maclen = 0;
895 
896 	if (ibuf_get_n8(buf, &type) == -1)
897 		return (-1);
898 	if (ibuf_get_n8(buf, &nlrilen) == -1)
899 		return (-1);
900 
901 	memset(prefix, 0, sizeof(struct bgpd_addr));
902 	prefix->aid = AID_EVPN;
903 
904 	switch (type) {
905 	case EVPN_ROUTE_TYPE_2:
906         	if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1)
907 	                return (-1);
908 		prefix->evpn.type = EVPN_ROUTE_TYPE_2;
909 		/* RD */
910 		if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1)
911 			return (-1);
912 		/* ESI */
913 		if (ibuf_get(&evpnbuf, &prefix->evpn.esi,
914 		    sizeof(prefix->evpn.esi)) == -1)
915 			return (-1);
916 		/* Ethernet Tag */
917 		if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1)
918 			return (-1);
919 		/* MAC length */
920 		if (ibuf_get_n8(&evpnbuf, &maclen) == -1)
921 			return (-1);
922 		if (maclen != 48)
923 			return (-1);
924 		/* MAC address */
925 		if (ibuf_get(&evpnbuf, &prefix->evpn.mac,
926 		    sizeof(prefix->evpn.mac)) == -1)
927 			return (-1);
928 		/* Prefix length */
929 		if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1)
930 			return (-1);
931 		/* Destination */
932 		if (pfxlen == 0) {
933 			/* nothing */
934 		} else if (pfxlen == 32) {
935 			prefix->evpn.aid = AID_INET;
936 			if (ibuf_get(&evpnbuf, &prefix->evpn.v4,
937 			    sizeof(prefix->evpn.v4)) == -1)
938 				return (-1);
939 		} else if (pfxlen == 128) {
940 			prefix->evpn.aid = AID_INET6;
941 			if (ibuf_get(&evpnbuf, &prefix->evpn.v6,
942 			    sizeof(prefix->evpn.v6)) == -1)
943 				return (-1);
944 		} else
945 			return (-1);
946 		/* VNI */
947 		if (ibuf_size(&evpnbuf) != 3 && ibuf_size(&evpnbuf) != 6)
948 			return (-1);
949 		prefix->labellen = ibuf_size(&evpnbuf);
950 		if (ibuf_get(&evpnbuf, prefix->labelstack,
951 		    prefix->labellen) == -1)
952 			return (-1);
953 		break;
954 	case EVPN_ROUTE_TYPE_3:
955         	if (ibuf_get_ibuf(buf, nlrilen, &evpnbuf) == -1)
956 	                return (-1);
957 		prefix->evpn.type = EVPN_ROUTE_TYPE_3;
958 		/* RD */
959 		if (ibuf_get_h64(&evpnbuf, &prefix->rd) == -1)
960 			return (-1);
961 		/* Ethernet Tag */
962 		if (ibuf_get_h32(&evpnbuf, &prefix->evpn.ethtag) == -1)
963 			return (-1);
964 		/* Prefix length */
965 		if (ibuf_get_n8(&evpnbuf, &pfxlen) == -1)
966 			return (-1);
967 		/* Destination */
968 		if (pfxlen == 32) {
969 			prefix->evpn.aid = AID_INET;
970 			if (ibuf_get(&evpnbuf, &prefix->evpn.v4,
971 			    sizeof(prefix->evpn.v4)) == -1)
972 				return (-1);
973 		} else if (pfxlen == 128) {
974 			prefix->evpn.aid = AID_INET6;
975 			if (ibuf_get(&evpnbuf, &prefix->evpn.v6,
976 			    sizeof(prefix->evpn.v6)) == -1)
977 				return (-1);
978 		} else
979 			return (-1);
980 		if (ibuf_size(&evpnbuf) != 0)
981 			return (-1);
982 		break;
983 	default:
984 		return (-1);
985 	}
986 
987 	*prefixlen = pfxlen;
988 	return (0);
989 }
990 
991 static in_addr_t
prefixlen2mask(uint8_t prefixlen)992 prefixlen2mask(uint8_t prefixlen)
993 {
994 	if (prefixlen == 0)
995 		return (0);
996 
997 	return (0xffffffff << (32 - prefixlen));
998 }
999 
1000 /*
1001  * This function will have undefined behaviour if the passed in prefixlen is
1002  * too large for the respective bgpd_addr address family.
1003  */
1004 int
prefix_compare(const struct bgpd_addr * a,const struct bgpd_addr * b,int prefixlen)1005 prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
1006     int prefixlen)
1007 {
1008 	in_addr_t	mask, aa, ba;
1009 	int		i;
1010 	uint8_t		m;
1011 
1012 	if (a->aid != b->aid)
1013 		return (a->aid - b->aid);
1014 
1015 	switch (a->aid) {
1016 	case AID_VPN_IPv4:
1017 		if (be64toh(a->rd) > be64toh(b->rd))
1018 			return (1);
1019 		if (be64toh(a->rd) < be64toh(b->rd))
1020 			return (-1);
1021 		/* FALLTHROUGH */
1022 	case AID_INET:
1023 		if (prefixlen == 0)
1024 			return (0);
1025 		if (prefixlen > 32)
1026 			return (-1);
1027 		mask = htonl(prefixlen2mask(prefixlen));
1028 		aa = ntohl(a->v4.s_addr & mask);
1029 		ba = ntohl(b->v4.s_addr & mask);
1030 		if (aa > ba)
1031 			return (1);
1032 		if (aa < ba)
1033 			return (-1);
1034 		break;
1035 	case AID_VPN_IPv6:
1036 		if (be64toh(a->rd) > be64toh(b->rd))
1037 			return (1);
1038 		if (be64toh(a->rd) < be64toh(b->rd))
1039 			return (-1);
1040 		/* FALLTHROUGH */
1041 	case AID_INET6:
1042 		if (prefixlen == 0)
1043 			return (0);
1044 		if (prefixlen > 128)
1045 			return (-1);
1046 		for (i = 0; i < prefixlen / 8; i++)
1047 			if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
1048 				return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
1049 		i = prefixlen % 8;
1050 		if (i) {
1051 			m = 0xff00 >> i;
1052 			if ((a->v6.s6_addr[prefixlen / 8] & m) !=
1053 			    (b->v6.s6_addr[prefixlen / 8] & m))
1054 				return ((a->v6.s6_addr[prefixlen / 8] & m) -
1055 				    (b->v6.s6_addr[prefixlen / 8] & m));
1056 		}
1057 		break;
1058 	default:
1059 		return (-1);
1060 	}
1061 
1062 	if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
1063 		if (a->labellen > b->labellen)
1064 			return (1);
1065 		if (a->labellen < b->labellen)
1066 			return (-1);
1067 		return (memcmp(a->labelstack, b->labelstack, a->labellen));
1068 	}
1069 	return (0);
1070 
1071 }
1072 
1073 void
inet4applymask(struct in_addr * dest,const struct in_addr * src,int prefixlen)1074 inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
1075 {
1076 	struct in_addr mask;
1077 
1078 	mask.s_addr = htonl(prefixlen2mask(prefixlen));
1079 	dest->s_addr = src->s_addr & mask.s_addr;
1080 }
1081 
1082 void
inet6applymask(struct in6_addr * dest,const struct in6_addr * src,int prefixlen)1083 inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
1084 {
1085 	struct in6_addr	mask;
1086 	int		i;
1087 
1088 	memset(&mask, 0, sizeof(mask));
1089 	for (i = 0; i < prefixlen / 8; i++)
1090 		mask.s6_addr[i] = 0xff;
1091 	i = prefixlen % 8;
1092 	if (i)
1093 		mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
1094 
1095 	for (i = 0; i < 16; i++)
1096 		dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
1097 }
1098 
1099 void
applymask(struct bgpd_addr * dest,const struct bgpd_addr * src,int prefixlen)1100 applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
1101 {
1102 	*dest = *src;
1103 	switch (src->aid) {
1104 	case AID_INET:
1105 	case AID_VPN_IPv4:
1106 		inet4applymask(&dest->v4, &src->v4, prefixlen);
1107 		break;
1108 	case AID_INET6:
1109 	case AID_VPN_IPv6:
1110 		inet6applymask(&dest->v6, &src->v6, prefixlen);
1111 		break;
1112 	}
1113 }
1114 
1115 /* address family translation functions */
1116 const struct aid aid_vals[AID_MAX] = AID_VALS;
1117 
1118 const char *
aid2str(uint8_t aid)1119 aid2str(uint8_t aid)
1120 {
1121 	if (aid < AID_MAX)
1122 		return (aid_vals[aid].name);
1123 	return ("unknown AID");
1124 }
1125 
1126 int
aid2afi(uint8_t aid,uint16_t * afi,uint8_t * safi)1127 aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
1128 {
1129 	if (aid != AID_UNSPEC && aid < AID_MAX) {
1130 		*afi = aid_vals[aid].afi;
1131 		*safi = aid_vals[aid].safi;
1132 		return (0);
1133 	}
1134 	return (-1);
1135 }
1136 
1137 int
afi2aid(uint16_t afi,uint8_t safi,uint8_t * aid)1138 afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
1139 {
1140 	uint8_t i;
1141 
1142 	for (i = AID_MIN; i < AID_MAX; i++)
1143 		if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
1144 			*aid = i;
1145 			return (0);
1146 		}
1147 
1148 	return (-1);
1149 }
1150 
1151 sa_family_t
aid2af(uint8_t aid)1152 aid2af(uint8_t aid)
1153 {
1154 	if (aid < AID_MAX)
1155 		return (aid_vals[aid].af);
1156 	return (AF_UNSPEC);
1157 }
1158 
1159 int
af2aid(sa_family_t af,uint8_t safi,uint8_t * aid)1160 af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
1161 {
1162 	uint8_t i;
1163 
1164 	if (safi == 0) /* default to unicast subclass */
1165 		safi = SAFI_UNICAST;
1166 
1167 	for (i = AID_UNSPEC; i < AID_MAX; i++)
1168 		if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
1169 			*aid = i;
1170 			return (0);
1171 		}
1172 
1173 	return (-1);
1174 }
1175 
1176 static socklen_t
addr2sa_in6(struct sockaddr_in6 * sin6,struct in6_addr in6,uint16_t port,uint32_t scope_id)1177 addr2sa_in6(struct sockaddr_in6 *sin6, struct in6_addr in6, uint16_t port,
1178     uint32_t scope_id)
1179 {
1180 	sin6->sin6_family = AF_INET6;
1181 	memcpy(&sin6->sin6_addr, &in6, sizeof(sin6->sin6_addr));
1182 	sin6->sin6_port = htons(port);
1183 	sin6->sin6_scope_id = scope_id;
1184 	return (sizeof(struct sockaddr_in6));
1185 }
1186 
1187 static socklen_t
addr2sa_in(struct sockaddr_in * sin,struct in_addr in,uint16_t port)1188 addr2sa_in(struct sockaddr_in *sin, struct in_addr in, uint16_t port)
1189 {
1190 	sin->sin_family = AF_INET;
1191 	sin->sin_addr.s_addr = in.s_addr;
1192 	sin->sin_port = htons(port);
1193 	return (sizeof(struct sockaddr_in));
1194 }
1195 
1196 /*
1197  * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
1198  * the included label stack is ignored and needs to be handled by the caller.
1199  */
1200 struct sockaddr *
addr2sa(const struct bgpd_addr * addr,uint16_t port,socklen_t * len)1201 addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
1202 {
1203 	static struct sockaddr_storage	 ss;
1204 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)&ss;
1205 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)&ss;
1206 
1207 	if (addr == NULL || addr->aid == AID_UNSPEC)
1208 		return (NULL);
1209 
1210 	memset(&ss, 0, sizeof(ss));
1211 	switch (addr->aid) {
1212 	case AID_INET:
1213 	case AID_VPN_IPv4:
1214 		*len = addr2sa_in(sa_in, addr->v4, port);
1215 		break;
1216 	case AID_INET6:
1217 	case AID_VPN_IPv6:
1218 		*len = addr2sa_in6(sa_in6, addr->v6, port, addr->scope_id);
1219 		break;
1220 	case AID_EVPN:
1221 		if (addr->evpn.aid == AID_INET)
1222 			*len = addr2sa_in(sa_in, addr->evpn.v4, port);
1223 		else if (addr->evpn.aid == AID_INET6)
1224 			*len = addr2sa_in6(sa_in6, addr->evpn.v6, port,
1225 			    addr->scope_id);
1226 		else {
1227 			*len = 0;
1228 			return (NULL);
1229 		}
1230 		break;
1231 	case AID_FLOWSPECv4:
1232 	case AID_FLOWSPECv6:
1233 	default:
1234 		return (NULL);
1235 	}
1236 
1237 	return ((struct sockaddr *)&ss);
1238 }
1239 
1240 void
sa2addr(struct sockaddr * sa,struct bgpd_addr * addr,uint16_t * port)1241 sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1242 {
1243 	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;
1244 	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa;
1245 
1246 	memset(addr, 0, sizeof(*addr));
1247 	switch (sa->sa_family) {
1248 	case AF_INET:
1249 		addr->aid = AID_INET;
1250 		memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
1251 		if (port)
1252 			*port = ntohs(sa_in->sin_port);
1253 		break;
1254 	case AF_INET6:
1255 		addr->aid = AID_INET6;
1256 #ifdef __KAME__
1257 		/*
1258 		 * XXX thanks, KAME, for this ugliness...
1259 		 * adopted from route/show.c
1260 		 */
1261 		if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
1262 		    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
1263 		    IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
1264 		    sa_in6->sin6_scope_id == 0) {
1265 			uint16_t tmp16;
1266 			memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
1267 			    sizeof(tmp16));
1268 			sa_in6->sin6_scope_id = ntohs(tmp16);
1269 			sa_in6->sin6_addr.s6_addr[2] = 0;
1270 			sa_in6->sin6_addr.s6_addr[3] = 0;
1271 		}
1272 #endif
1273 		memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
1274 		addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1275 		if (port)
1276 			*port = ntohs(sa_in6->sin6_port);
1277 		break;
1278 	}
1279 }
1280 
1281 const char *
get_baudrate(unsigned long long baudrate,char * unit)1282 get_baudrate(unsigned long long baudrate, char *unit)
1283 {
1284 	static char bbuf[16];
1285 	const unsigned long long kilo = 1000;
1286 	const unsigned long long mega = 1000ULL * kilo;
1287 	const unsigned long long giga = 1000ULL * mega;
1288 
1289 	if (baudrate > giga)
1290 		snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1291 		    baudrate / giga, unit);
1292 	else if (baudrate > mega)
1293 		snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1294 		    baudrate / mega, unit);
1295 	else if (baudrate > kilo)
1296 		snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1297 		    baudrate / kilo, unit);
1298 	else
1299 		snprintf(bbuf, sizeof(bbuf), "%llu %s",
1300 		    baudrate, unit);
1301 
1302 	return (bbuf);
1303 }
1304