Bug Summary

File:src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/../bgpd/util.c
Warning:line 222, column 7
Null pointer passed as 1st argument to string concatenation function

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name util.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/bgplg/bgpctl/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl -I /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/../bgpd -I /usr/src/usr.bin/bgplg/bgpctl -I /usr/src/usr.bin/bgplg/bgpctl/../bgpd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/bgplg/bgpctl/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/bgplg/bgpctl/../../../usr.sbin/bgpctl/../bgpd/util.c
1/* $OpenBSD: util.c,v 1.78 2024/01/10 13:31:09 claudio 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(*__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
35const char *aspath_delim(uint8_t, int);
36
37const char *
38log_addr(const struct bgpd_addr *addr)
39{
40 static char buf[74];
41 struct sockaddr *sa;
42 socklen_t len;
43
44 sa = addr2sa(addr, 0, &len);
45 switch (addr->aid) {
46 case AID_INET1:
47 case AID_INET62:
48 return log_sockaddr(sa, len);
49 case AID_VPN_IPv43:
50 case AID_VPN_IPv64:
51 snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
52 log_sockaddr(sa, len));
53 return (buf);
54 }
55 return ("???");
56}
57
58const char *
59log_in6addr(const struct in6_addr *addr)
60{
61 struct sockaddr_in6 sa_in6;
62
63 memset(&sa_in6, 0, sizeof(sa_in6));
64 sa_in6.sin6_family = AF_INET624;
65 memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
66
67#ifdef __KAME__
68 /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
69 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr)(((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
||
70 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)(((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
) && (((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8
[1] & 0x0f) == 0x02))
||
71 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)(((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
) && (((&sa_in6.sin6_addr)->__u6_addr.__u6_addr8
[1] & 0x0f) == 0x01))
) &&
72 sa_in6.sin6_scope_id == 0) {
73 uint16_t tmp16;
74 memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr__u6_addr.__u6_addr8[2], sizeof(tmp16));
75 sa_in6.sin6_scope_id = ntohs(tmp16)(__uint16_t)(__builtin_constant_p(tmp16) ? (__uint16_t)(((__uint16_t
)(tmp16) & 0xffU) << 8 | ((__uint16_t)(tmp16) &
0xff00U) >> 8) : __swap16md(tmp16))
;
76 sa_in6.sin6_addr.s6_addr__u6_addr.__u6_addr8[2] = 0;
77 sa_in6.sin6_addr.s6_addr__u6_addr.__u6_addr8[3] = 0;
78 }
79#endif
80
81 return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
82}
83
84const char *
85log_sockaddr(struct sockaddr *sa, socklen_t len)
86{
87 static char buf[NI_MAXHOST256];
88
89 if (sa == NULL((void *)0) || getnameinfo(sa, len, buf, sizeof(buf), NULL((void *)0), 0,
90 NI_NUMERICHOST1))
91 return ("(unknown)");
92 else
93 return (buf);
94}
95
96const char *
97log_as(uint32_t as)
98{
99 static char buf[11]; /* "4294967294\0" */
100
101 if (snprintf(buf, sizeof(buf), "%u", as) < 0)
102 return ("?");
103
104 return (buf);
105}
106
107const char *
108log_rd(uint64_t rd)
109{
110 static char buf[32];
111 struct in_addr addr;
112 uint32_t u32;
113 uint16_t u16;
114
115 rd = be64toh(rd)(__uint64_t)(__builtin_constant_p(rd) ? (__uint64_t)((((__uint64_t
)(rd) & 0xff) << 56) | ((__uint64_t)(rd) & 0xff00ULL
) << 40 | ((__uint64_t)(rd) & 0xff0000ULL) <<
24 | ((__uint64_t)(rd) & 0xff000000ULL) << 8 | ((__uint64_t
)(rd) & 0xff00000000ULL) >> 8 | ((__uint64_t)(rd) &
0xff0000000000ULL) >> 24 | ((__uint64_t)(rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(rd))
;
116 switch (rd >> 48) {
117 case EXT_COMMUNITY_TRANS_TWO_AS0x00:
118 u32 = rd & 0xffffffff;
119 u16 = (rd >> 32) & 0xffff;
120 snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
121 break;
122 case EXT_COMMUNITY_TRANS_FOUR_AS0x02:
123 u32 = (rd >> 16) & 0xffffffff;
124 u16 = rd & 0xffff;
125 snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
126 break;
127 case EXT_COMMUNITY_TRANS_IPV40x01:
128 u32 = (rd >> 16) & 0xffffffff;
129 u16 = rd & 0xffff;
130 addr.s_addr = htonl(u32)(__uint32_t)(__builtin_constant_p(u32) ? (__uint32_t)(((__uint32_t
)(u32) & 0xff) << 24 | ((__uint32_t)(u32) & 0xff00
) << 8 | ((__uint32_t)(u32) & 0xff0000) >> 8 |
((__uint32_t)(u32) & 0xff000000) >> 24) : __swap32md
(u32))
;
131 snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
132 break;
133 default:
134 snprintf(buf, sizeof(buf), "rd #%016llx",
135 (unsigned long long)rd);
136 break;
137 }
138 return (buf);
139}
140
141const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES{ { 0x00, 0x02, "rt" }, { 0x00, 0x03, "soo" }, { 0x00, 0x05, "odi"
}, { 0x00, 0x08, "bdc" }, { 0x00, 0x09, "srcas" }, { 0x00, 0x0a
, "l2vid" }, { 0x02, 0x02, "rt" }, { 0x02, 0x03, "soo" }, { 0x02
, 0x05, "odi" }, { 0x02, 0x08, "bdc" }, { 0x02, 0x09, "srcas"
}, { 0x01, 0x02, "rt" }, { 0x01, 0x03, "soo" }, { 0x01, 0x05
, "odi" }, { 0x01, 0x07, "ori" }, { 0x01, 0x0a, "l2vid" }, { 0x01
, 0x0b, "vrfri" }, { 0x03, 0x06, "ort" }, { 0x03, 0x0d, "defgw"
}, { 0x43, 0, "ovs" }, { 0x06, 0x00, "mac-mob" }, { 0x06, 0x01
, "esi-lab" }, { 0x06, 0x02, "esi-rt" }, { 0x80, 0x06, "flow-rate"
}, { 0x80, 0x0c, "flow-pps" }, { 0x80, 0x07, "flow-action" }
, { 0x80, 0x08, "flow-rt-redir" }, { 0x81, 0x08, "flow-rt-redir"
}, { 0x82, 0x08, "flow-rt-redir" }, { 0x80, 0x09, "flow-dscp"
}, { 0 } }
;
142
143/* NOTE: this function does not check if the type/subtype combo is
144 * actually valid. */
145const char *
146log_ext_subtype(int type, uint8_t subtype)
147{
148 static char etype[6];
149 const struct ext_comm_pairs *cp;
150
151 for (cp = iana_ext_comms; cp->subname != NULL((void *)0); cp++) {
152 if ((type == cp->type || type == -1) && subtype == cp->subtype)
153 return (cp->subname);
154 }
155 snprintf(etype, sizeof(etype), "[%u]", subtype);
156 return (etype);
157}
158
159const char *
160log_reason(const char *communication) {
161 static char buf[(REASON_LEN256 - 1) * 4 + 1];
162
163 strnvis(buf, communication, sizeof(buf), VIS_NL0x10 | VIS_OCTAL0x01);
164
165 return buf;
166}
167
168static const char *
169log_expires(time_t expires)
170{
171 static char buf[32];
172
173 buf[0] = '\0';
174 if (expires != 0)
175 snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
176 return buf;
177}
178
179const char *
180log_roa(struct roa *roa)
181{
182 static char buf[256];
183 struct bgpd_addr addr = { .aid = roa->aid, .v6ba.v6 = roa->prefix.inet6 };
184 char maxbuf[32];
185
186 maxbuf[0] = '\0';
187 if (roa->prefixlen != roa->maxlen)
188 snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
189 snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
190 roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
191 return buf;
192}
193
194const char *
195log_aspa(struct aspa_set *aspa)
196{
197 static char errbuf[256];
198 static char *buf;
1
'buf' initialized to a null pointer value
199 static size_t len;
200 char asbuf[16];
201 size_t needed;
202 uint32_t i;
203
204 /* include enough space for header and trailer */
205 if ((uint64_t)aspa->num > (SIZE_MAX0xffffffffffffffffUL / sizeof(asbuf) - 72))
2
Assuming the condition is false
3
Taking false branch
206 goto fail;
207 needed = aspa->num * sizeof(asbuf) + 72;
208 if (needed > len) {
4
Assuming 'needed' is <= 'len'
5
Taking false branch
209 char *nbuf;
210
211 if ((nbuf = realloc(buf, needed)) == NULL((void *)0))
212 goto fail;
213 len = needed;
214 buf = nbuf;
215 }
216
217 snprintf(buf, len, "customer-as %s%s provider-as { ",
218 log_as(aspa->as), log_expires(aspa->expires));
219
220 for (i = 0; i < aspa->num; i++) {
6
Assuming 'i' is < field 'num'
7
Loop condition is true. Entering loop body
221 snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
222 if (strlcat(buf, asbuf, len) >= len)
8
Null pointer passed as 1st argument to string concatenation function
223 goto fail;
224 }
225 if (strlcat(buf, "}", len) >= len)
226 goto fail;
227 return buf;
228
229 fail:
230 free(buf);
231 buf = NULL((void *)0);
232 len = 0;
233 snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
234 log_as(aspa->as), log_expires(aspa->expires));
235 return errbuf;
236}
237
238const char *
239log_rtr_error(enum rtr_error err)
240{
241 static char buf[20];
242
243 switch (err) {
244 case NO_ERROR:
245 return "No Error";
246 case CORRUPT_DATA:
247 return "Corrupt Data";
248 case INTERNAL_ERROR:
249 return "Internal Error";
250 case NO_DATA_AVAILABLE:
251 return "No Data Available";
252 case INVALID_REQUEST:
253 return "Invalid Request";
254 case UNSUPP_PROTOCOL_VERS:
255 return "Unsupported Protocol Version";
256 case UNSUPP_PDU_TYPE:
257 return "Unsupported PDU Type";
258 case UNK_REC_WDRAWL:
259 return "Withdrawal of Unknown Record";
260 case DUP_REC_RECV:
261 return "Duplicate Announcement Received";
262 case UNEXP_PROTOCOL_VERS:
263 return "Unexpected Protocol Version";
264 default:
265 snprintf(buf, sizeof(buf), "unknown %u", err);
266 return buf;
267 }
268}
269
270const char *
271log_policy(enum role role)
272{
273 switch (role) {
274 case ROLE_PROVIDER:
275 return "provider";
276 case ROLE_RS:
277 return "rs";
278 case ROLE_RS_CLIENT:
279 return "rs-client";
280 case ROLE_CUSTOMER:
281 return "customer";
282 case ROLE_PEER:
283 return "peer";
284 default:
285 return "unknown";
286 }
287}
288
289const char *
290aspath_delim(uint8_t seg_type, int closing)
291{
292 static char db[8];
293
294 switch (seg_type) {
295 case AS_SET1:
296 if (!closing)
297 return ("{ ");
298 else
299 return (" }");
300 case AS_SEQUENCE2:
301 return ("");
302 case AS_CONFED_SEQUENCE3:
303 if (!closing)
304 return ("( ");
305 else
306 return (" )");
307 case AS_CONFED_SET4:
308 if (!closing)
309 return ("[ ");
310 else
311 return (" ]");
312 default:
313 if (!closing)
314 snprintf(db, sizeof(db), "!%u ", seg_type);
315 else
316 snprintf(db, sizeof(db), " !%u", seg_type);
317 return (db);
318 }
319}
320
321int
322aspath_snprint(char *buf, size_t size, void *data, uint16_t len)
323{
324#define UPDATE() \
325 do { \
326 if (r < 0) \
327 return (-1); \
328 total_size += r; \
329 if ((unsigned int)r < size) { \
330 size -= r; \
331 buf += r; \
332 } else { \
333 buf += size; \
334 size = 0; \
335 } \
336 } while (0)
337 uint8_t *seg;
338 int r, total_size;
339 uint16_t seg_size;
340 uint8_t i, seg_type, seg_len;
341
342 total_size = 0;
343 seg = data;
344 for (; len > 0; len -= seg_size, seg += seg_size) {
345 seg_type = seg[0];
346 seg_len = seg[1];
347 seg_size = 2 + sizeof(uint32_t) * seg_len;
348
349 r = snprintf(buf, size, "%s%s",
350 total_size != 0 ? " " : "",
351 aspath_delim(seg_type, 0));
352 UPDATE();
353
354 for (i = 0; i < seg_len; i++) {
355 r = snprintf(buf, size, "%s",
356 log_as(aspath_extract(seg, i)));
357 UPDATE();
358 if (i + 1 < seg_len) {
359 r = snprintf(buf, size, " ");
360 UPDATE();
361 }
362 }
363 r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
364 UPDATE();
365 }
366 /* ensure that we have a valid C-string especially for empty as path */
367 if (size > 0)
368 *buf = '\0';
369
370 return (total_size);
371#undef UPDATE
372}
373
374int
375aspath_asprint(char **ret, void *data, uint16_t len)
376{
377 size_t slen;
378 int plen;
379
380 slen = aspath_strlen(data, len) + 1;
381 *ret = malloc(slen);
382 if (*ret == NULL((void *)0))
383 return (-1);
384
385 plen = aspath_snprint(*ret, slen, data, len);
386 if (plen == -1) {
387 free(*ret);
388 *ret = NULL((void *)0);
389 return (-1);
390 }
391
392 return (0);
393}
394
395size_t
396aspath_strlen(void *data, uint16_t len)
397{
398 uint8_t *seg;
399 int total_size;
400 uint32_t as;
401 uint16_t seg_size;
402 uint8_t i, seg_type, seg_len;
403
404 total_size = 0;
405 seg = data;
406 for (; len > 0; len -= seg_size, seg += seg_size) {
407 seg_type = seg[0];
408 seg_len = seg[1];
409 seg_size = 2 + sizeof(uint32_t) * seg_len;
410
411 if (seg_type == AS_SET1)
412 if (total_size != 0)
413 total_size += 3;
414 else
415 total_size += 2;
416 else if (total_size != 0)
417 total_size += 1;
418
419 for (i = 0; i < seg_len; i++) {
420 as = aspath_extract(seg, i);
421
422 do {
423 total_size++;
424 } while ((as = as / 10) != 0);
425
426 if (i + 1 < seg_len)
427 total_size += 1;
428 }
429
430 if (seg_type == AS_SET1)
431 total_size += 2;
432 }
433 return (total_size);
434}
435
436/*
437 * Extract the asnum out of the as segment at the specified position.
438 * Direct access is not possible because of non-aligned reads.
439 * Only works on verified 4-byte AS paths.
440 */
441uint32_t
442aspath_extract(const void *seg, int pos)
443{
444 const u_char *ptr = seg;
445 uint32_t as;
446
447 /* minimal pos check, return 0 since that is an invalid ASN */
448 if (pos < 0 || pos >= ptr[1])
449 return (0);
450 ptr += 2 + sizeof(uint32_t) * pos;
451 memcpy(&as, ptr, sizeof(uint32_t));
452 return (ntohl(as)(__uint32_t)(__builtin_constant_p(as) ? (__uint32_t)(((__uint32_t
)(as) & 0xff) << 24 | ((__uint32_t)(as) & 0xff00
) << 8 | ((__uint32_t)(as) & 0xff0000) >> 8 |
((__uint32_t)(as) & 0xff000000) >> 24) : __swap32md
(as))
);
453}
454
455/*
456 * Verify that the aspath is correctly encoded.
457 */
458int
459aspath_verify(void *data, uint16_t len, int as4byte, int noset)
460{
461 uint8_t *seg = data;
462 uint16_t seg_size, as_size = 2;
463 uint8_t seg_len, seg_type;
464 int error = 0;
465
466 if (len & 1)
467 /* odd length aspath are invalid */
468 return (AS_ERR_BAD-3);
469
470 if (as4byte)
471 as_size = 4;
472
473 for (; len > 0; len -= seg_size, seg += seg_size) {
474 const uint8_t *ptr;
475 int pos;
476
477 if (len < 2) /* header length check */
478 return (AS_ERR_BAD-3);
479 seg_type = seg[0];
480 seg_len = seg[1];
481
482 if (seg_len == 0)
483 /* empty aspath segments are not allowed */
484 return (AS_ERR_BAD-3);
485
486 /*
487 * BGP confederations should not show up but consider them
488 * as a soft error which invalidates the path but keeps the
489 * bgp session running.
490 */
491 if (seg_type == AS_CONFED_SEQUENCE3 || seg_type == AS_CONFED_SET4)
492 error = AS_ERR_SOFT-4;
493 /*
494 * If AS_SET filtering (RFC6472) is on, error out on AS_SET
495 * as well.
496 */
497 if (noset && seg_type == AS_SET1)
498 error = AS_ERR_SOFT-4;
499 if (seg_type != AS_SET1 && seg_type != AS_SEQUENCE2 &&
500 seg_type != AS_CONFED_SEQUENCE3 && seg_type != AS_CONFED_SET4)
501 return (AS_ERR_TYPE-2);
502
503 seg_size = 2 + as_size * seg_len;
504
505 if (seg_size > len)
506 return (AS_ERR_LEN-1);
507
508 /* RFC 7607 - AS 0 is considered malformed */
509 ptr = seg + 2;
510 for (pos = 0; pos < seg_len; pos++) {
511 uint32_t as;
512
513 memcpy(&as, ptr, as_size);
514 if (as == 0)
515 error = AS_ERR_SOFT-4;
516 ptr += as_size;
517 }
518 }
519 return (error); /* aspath is valid but probably not loop free */
520}
521
522/*
523 * convert a 2 byte aspath to a 4 byte one.
524 */
525u_char *
526aspath_inflate(void *data, uint16_t len, uint16_t *newlen)
527{
528 uint8_t *seg, *nseg, *ndata;
529 uint16_t seg_size, olen, nlen;
530 uint8_t seg_len;
531
532 /* first calculate the length of the aspath */
533 seg = data;
534 nlen = 0;
535 for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) {
536 seg_len = seg[1];
537 seg_size = 2 + sizeof(uint16_t) * seg_len;
538 nlen += 2 + sizeof(uint32_t) * seg_len;
539
540 if (seg_size > olen) {
541 errno(*__errno()) = ERANGE34;
542 return (NULL((void *)0));
543 }
544 }
545
546 *newlen = nlen;
547 if ((ndata = malloc(nlen)) == NULL((void *)0))
548 return (NULL((void *)0));
549
550 /* then copy the aspath */
551 seg = data;
552 for (nseg = ndata; nseg < ndata + nlen; ) {
553 *nseg++ = *seg++;
554 *nseg++ = seg_len = *seg++;
555 for (; seg_len > 0; seg_len--) {
556 *nseg++ = 0;
557 *nseg++ = 0;
558 *nseg++ = *seg++;
559 *nseg++ = *seg++;
560 }
561 }
562
563 return (ndata);
564}
565
566/* NLRI functions to extract prefixes from the NLRI blobs */
567int
568extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
569{
570 static u_char addrmask[] = {
571 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
572 u_char *a = va;
573 int plen;
574
575 plen = PREFIX_SIZE(pfxlen)(((pfxlen) + 7) / 8 + 1) - 1;
576 if (len < plen || max < plen)
577 return -1;
578
579 while (pfxlen > 0) {
580 if (pfxlen < 8) {
581 *a++ = *p++ & addrmask[pfxlen];
582 break;
583 } else {
584 *a++ = *p++;
585 pfxlen -= 8;
586 }
587 }
588 return (plen);
589}
590
591int
592nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix,
593 uint8_t *prefixlen)
594{
595 int plen;
596 uint8_t pfxlen;
597
598 if (len < 1)
599 return (-1);
600
601 pfxlen = *p++;
602 len--;
603
604 memset(prefix, 0, sizeof(struct bgpd_addr));
605 prefix->aid = AID_INET1;
606 *prefixlen = pfxlen;
607
608 if (pfxlen > 32)
609 return (-1);
610 if ((plen = extract_prefix(p, len, &prefix->v4ba.v4, pfxlen,
611 sizeof(prefix->v4ba.v4))) == -1)
612 return (-1);
613
614 return (plen + 1); /* pfxlen needs to be added */
615}
616
617int
618nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
619 uint8_t *prefixlen)
620{
621 int plen;
622 uint8_t pfxlen;
623
624 if (len < 1)
625 return (-1);
626
627 pfxlen = *p++;
628 len--;
629
630 memset(prefix, 0, sizeof(struct bgpd_addr));
631 prefix->aid = AID_INET62;
632 *prefixlen = pfxlen;
633
634 if (pfxlen > 128)
635 return (-1);
636 if ((plen = extract_prefix(p, len, &prefix->v6ba.v6, pfxlen,
637 sizeof(prefix->v6ba.v6))) == -1)
638 return (-1);
639
640 return (plen + 1); /* pfxlen needs to be added */
641}
642
643int
644nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix,
645 uint8_t *prefixlen, int withdraw)
646{
647 int rv, done = 0;
648 uint16_t plen;
649 uint8_t pfxlen;
650
651 if (len < 1)
652 return (-1);
653
654 memcpy(&pfxlen, p, 1);
655 p += 1;
656 plen = 1;
657
658 memset(prefix, 0, sizeof(struct bgpd_addr));
659
660 /* label stack */
661 do {
662 if (len - plen < 3 || pfxlen < 3 * 8)
663 return (-1);
664 if (prefix->labellen + 3U >
665 sizeof(prefix->labelstack))
666 return (-1);
667 if (withdraw) {
668 /* on withdraw ignore the labelstack all together */
669 p += 3;
670 plen += 3;
671 pfxlen -= 3 * 8;
672 break;
673 }
674 prefix->labelstack[prefix->labellen++] = *p++;
675 prefix->labelstack[prefix->labellen++] = *p++;
676 prefix->labelstack[prefix->labellen] = *p++;
677 if (prefix->labelstack[prefix->labellen] &
678 BGP_MPLS_BOS0x01)
679 done = 1;
680 prefix->labellen++;
681 plen += 3;
682 pfxlen -= 3 * 8;
683 } while (!done);
684
685 /* RD */
686 if (len - plen < (int)sizeof(uint64_t) ||
687 pfxlen < sizeof(uint64_t) * 8)
688 return (-1);
689 memcpy(&prefix->rd, p, sizeof(uint64_t));
690 pfxlen -= sizeof(uint64_t) * 8;
691 p += sizeof(uint64_t);
692 plen += sizeof(uint64_t);
693
694 /* prefix */
695 prefix->aid = AID_VPN_IPv43;
696 *prefixlen = pfxlen;
697
698 if (pfxlen > 32)
699 return (-1);
700 if ((rv = extract_prefix(p, len, &prefix->v4ba.v4,
701 pfxlen, sizeof(prefix->v4ba.v4))) == -1)
702 return (-1);
703
704 return (plen + rv);
705}
706
707int
708nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix,
709 uint8_t *prefixlen, int withdraw)
710{
711 int rv, done = 0;
712 uint16_t plen;
713 uint8_t pfxlen;
714
715 if (len < 1)
716 return (-1);
717
718 memcpy(&pfxlen, p, 1);
719 p += 1;
720 plen = 1;
721
722 memset(prefix, 0, sizeof(struct bgpd_addr));
723
724 /* label stack */
725 do {
726 if (len - plen < 3 || pfxlen < 3 * 8)
727 return (-1);
728 if (prefix->labellen + 3U >
729 sizeof(prefix->labelstack))
730 return (-1);
731 if (withdraw) {
732 /* on withdraw ignore the labelstack all together */
733 p += 3;
734 plen += 3;
735 pfxlen -= 3 * 8;
736 break;
737 }
738
739 prefix->labelstack[prefix->labellen++] = *p++;
740 prefix->labelstack[prefix->labellen++] = *p++;
741 prefix->labelstack[prefix->labellen] = *p++;
742 if (prefix->labelstack[prefix->labellen] &
743 BGP_MPLS_BOS0x01)
744 done = 1;
745 prefix->labellen++;
746 plen += 3;
747 pfxlen -= 3 * 8;
748 } while (!done);
749
750 /* RD */
751 if (len - plen < (int)sizeof(uint64_t) ||
752 pfxlen < sizeof(uint64_t) * 8)
753 return (-1);
754
755 memcpy(&prefix->rd, p, sizeof(uint64_t));
756 pfxlen -= sizeof(uint64_t) * 8;
757 p += sizeof(uint64_t);
758 plen += sizeof(uint64_t);
759
760 /* prefix */
761 prefix->aid = AID_VPN_IPv64;
762 *prefixlen = pfxlen;
763
764 if (pfxlen > 128)
765 return (-1);
766
767 if ((rv = extract_prefix(p, len, &prefix->v6ba.v6,
768 pfxlen, sizeof(prefix->v6ba.v6))) == -1)
769 return (-1);
770
771 return (plen + rv);
772}
773
774static in_addr_t
775prefixlen2mask(uint8_t prefixlen)
776{
777 if (prefixlen == 0)
778 return (0);
779
780 return (0xffffffff << (32 - prefixlen));
781}
782
783/*
784 * This function will have undefined behaviour if the passed in prefixlen is
785 * too large for the respective bgpd_addr address family.
786 */
787int
788prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
789 int prefixlen)
790{
791 in_addr_t mask, aa, ba;
792 int i;
793 uint8_t m;
794
795 if (a->aid != b->aid)
796 return (a->aid - b->aid);
797
798 switch (a->aid) {
799 case AID_VPN_IPv43:
800 if (be64toh(a->rd)(__uint64_t)(__builtin_constant_p(a->rd) ? (__uint64_t)(((
(__uint64_t)(a->rd) & 0xff) << 56) | ((__uint64_t
)(a->rd) & 0xff00ULL) << 40 | ((__uint64_t)(a->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(a->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(a->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(a->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(a->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(a->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(a->rd))
> be64toh(b->rd)(__uint64_t)(__builtin_constant_p(b->rd) ? (__uint64_t)(((
(__uint64_t)(b->rd) & 0xff) << 56) | ((__uint64_t
)(b->rd) & 0xff00ULL) << 40 | ((__uint64_t)(b->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(b->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(b->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(b->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(b->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(b->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(b->rd))
)
801 return (1);
802 if (be64toh(a->rd)(__uint64_t)(__builtin_constant_p(a->rd) ? (__uint64_t)(((
(__uint64_t)(a->rd) & 0xff) << 56) | ((__uint64_t
)(a->rd) & 0xff00ULL) << 40 | ((__uint64_t)(a->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(a->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(a->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(a->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(a->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(a->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(a->rd))
< be64toh(b->rd)(__uint64_t)(__builtin_constant_p(b->rd) ? (__uint64_t)(((
(__uint64_t)(b->rd) & 0xff) << 56) | ((__uint64_t
)(b->rd) & 0xff00ULL) << 40 | ((__uint64_t)(b->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(b->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(b->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(b->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(b->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(b->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(b->rd))
)
803 return (-1);
804 /* FALLTHROUGH */
805 case AID_INET1:
806 if (prefixlen == 0)
807 return (0);
808 if (prefixlen > 32)
809 return (-1);
810 mask = htonl(prefixlen2mask(prefixlen))(__uint32_t)(__builtin_constant_p(prefixlen2mask(prefixlen)) ?
(__uint32_t)(((__uint32_t)(prefixlen2mask(prefixlen)) & 0xff
) << 24 | ((__uint32_t)(prefixlen2mask(prefixlen)) &
0xff00) << 8 | ((__uint32_t)(prefixlen2mask(prefixlen)
) & 0xff0000) >> 8 | ((__uint32_t)(prefixlen2mask(prefixlen
)) & 0xff000000) >> 24) : __swap32md(prefixlen2mask
(prefixlen)))
;
811 aa = ntohl(a->v4.s_addr & mask)(__uint32_t)(__builtin_constant_p(a->ba.v4.s_addr & mask
) ? (__uint32_t)(((__uint32_t)(a->ba.v4.s_addr & mask)
& 0xff) << 24 | ((__uint32_t)(a->ba.v4.s_addr &
mask) & 0xff00) << 8 | ((__uint32_t)(a->ba.v4.s_addr
& mask) & 0xff0000) >> 8 | ((__uint32_t)(a->
ba.v4.s_addr & mask) & 0xff000000) >> 24) : __swap32md
(a->ba.v4.s_addr & mask))
;
812 ba = ntohl(b->v4.s_addr & mask)(__uint32_t)(__builtin_constant_p(b->ba.v4.s_addr & mask
) ? (__uint32_t)(((__uint32_t)(b->ba.v4.s_addr & mask)
& 0xff) << 24 | ((__uint32_t)(b->ba.v4.s_addr &
mask) & 0xff00) << 8 | ((__uint32_t)(b->ba.v4.s_addr
& mask) & 0xff0000) >> 8 | ((__uint32_t)(b->
ba.v4.s_addr & mask) & 0xff000000) >> 24) : __swap32md
(b->ba.v4.s_addr & mask))
;
813 if (aa > ba)
814 return (1);
815 if (aa < ba)
816 return (-1);
817 break;
818 case AID_VPN_IPv64:
819 if (be64toh(a->rd)(__uint64_t)(__builtin_constant_p(a->rd) ? (__uint64_t)(((
(__uint64_t)(a->rd) & 0xff) << 56) | ((__uint64_t
)(a->rd) & 0xff00ULL) << 40 | ((__uint64_t)(a->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(a->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(a->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(a->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(a->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(a->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(a->rd))
> be64toh(b->rd)(__uint64_t)(__builtin_constant_p(b->rd) ? (__uint64_t)(((
(__uint64_t)(b->rd) & 0xff) << 56) | ((__uint64_t
)(b->rd) & 0xff00ULL) << 40 | ((__uint64_t)(b->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(b->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(b->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(b->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(b->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(b->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(b->rd))
)
820 return (1);
821 if (be64toh(a->rd)(__uint64_t)(__builtin_constant_p(a->rd) ? (__uint64_t)(((
(__uint64_t)(a->rd) & 0xff) << 56) | ((__uint64_t
)(a->rd) & 0xff00ULL) << 40 | ((__uint64_t)(a->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(a->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(a->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(a->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(a->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(a->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(a->rd))
< be64toh(b->rd)(__uint64_t)(__builtin_constant_p(b->rd) ? (__uint64_t)(((
(__uint64_t)(b->rd) & 0xff) << 56) | ((__uint64_t
)(b->rd) & 0xff00ULL) << 40 | ((__uint64_t)(b->
rd) & 0xff0000ULL) << 24 | ((__uint64_t)(b->rd) &
0xff000000ULL) << 8 | ((__uint64_t)(b->rd) & 0xff00000000ULL
) >> 8 | ((__uint64_t)(b->rd) & 0xff0000000000ULL
) >> 24 | ((__uint64_t)(b->rd) & 0xff000000000000ULL
) >> 40 | ((__uint64_t)(b->rd) & 0xff00000000000000ULL
) >> 56) : __swap64md(b->rd))
)
822 return (-1);
823 /* FALLTHROUGH */
824 case AID_INET62:
825 if (prefixlen == 0)
826 return (0);
827 if (prefixlen > 128)
828 return (-1);
829 for (i = 0; i < prefixlen / 8; i++)
830 if (a->v6ba.v6.s6_addr__u6_addr.__u6_addr8[i] != b->v6ba.v6.s6_addr__u6_addr.__u6_addr8[i])
831 return (a->v6ba.v6.s6_addr__u6_addr.__u6_addr8[i] - b->v6ba.v6.s6_addr__u6_addr.__u6_addr8[i]);
832 i = prefixlen % 8;
833 if (i) {
834 m = 0xff00 >> i;
835 if ((a->v6ba.v6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] & m) !=
836 (b->v6ba.v6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] & m))
837 return ((a->v6ba.v6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] & m) -
838 (b->v6ba.v6.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] & m));
839 }
840 break;
841 default:
842 return (-1);
843 }
844
845 if (a->aid == AID_VPN_IPv43 || a->aid == AID_VPN_IPv64) {
846 if (a->labellen > b->labellen)
847 return (1);
848 if (a->labellen < b->labellen)
849 return (-1);
850 return (memcmp(a->labelstack, b->labelstack, a->labellen));
851 }
852 return (0);
853
854}
855
856void
857inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
858{
859 struct in_addr mask;
860
861 mask.s_addr = htonl(prefixlen2mask(prefixlen))(__uint32_t)(__builtin_constant_p(prefixlen2mask(prefixlen)) ?
(__uint32_t)(((__uint32_t)(prefixlen2mask(prefixlen)) & 0xff
) << 24 | ((__uint32_t)(prefixlen2mask(prefixlen)) &
0xff00) << 8 | ((__uint32_t)(prefixlen2mask(prefixlen)
) & 0xff0000) >> 8 | ((__uint32_t)(prefixlen2mask(prefixlen
)) & 0xff000000) >> 24) : __swap32md(prefixlen2mask
(prefixlen)))
;
862 dest->s_addr = src->s_addr & mask.s_addr;
863}
864
865void
866inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
867{
868 struct in6_addr mask;
869 int i;
870
871 memset(&mask, 0, sizeof(mask));
872 for (i = 0; i < prefixlen / 8; i++)
873 mask.s6_addr__u6_addr.__u6_addr8[i] = 0xff;
874 i = prefixlen % 8;
875 if (i)
876 mask.s6_addr__u6_addr.__u6_addr8[prefixlen / 8] = 0xff00 >> i;
877
878 for (i = 0; i < 16; i++)
879 dest->s6_addr__u6_addr.__u6_addr8[i] = src->s6_addr__u6_addr.__u6_addr8[i] & mask.s6_addr__u6_addr.__u6_addr8[i];
880}
881
882void
883applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
884{
885 *dest = *src;
886 switch (src->aid) {
887 case AID_INET1:
888 case AID_VPN_IPv43:
889 inet4applymask(&dest->v4ba.v4, &src->v4ba.v4, prefixlen);
890 break;
891 case AID_INET62:
892 case AID_VPN_IPv64:
893 inet6applymask(&dest->v6ba.v6, &src->v6ba.v6, prefixlen);
894 break;
895 }
896}
897
898/* address family translation functions */
899const struct aid aid_vals[AID_MAX7] = AID_VALS{ { 0, 0, 0, "unspec"}, { 1, 2, 1, "IPv4 unicast" }, { 2, 24,
1, "IPv6 unicast" }, { 1, 2, 128, "IPv4 vpn" }, { 2, 24, 128
, "IPv6 vpn" }, { 1, 2, 133, "IPv4 flowspec" }, { 2, 24, 133,
"IPv6 flowspec" }, }
;
900
901const char *
902aid2str(uint8_t aid)
903{
904 if (aid < AID_MAX7)
905 return (aid_vals[aid].name);
906 return ("unknown AID");
907}
908
909int
910aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
911{
912 if (aid < AID_MAX7) {
913 *afi = aid_vals[aid].afi;
914 *safi = aid_vals[aid].safi;
915 return (0);
916 }
917 return (-1);
918}
919
920int
921afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
922{
923 uint8_t i;
924
925 for (i = 0; i < AID_MAX7; i++)
926 if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
927 *aid = i;
928 return (0);
929 }
930
931 return (-1);
932}
933
934sa_family_t
935aid2af(uint8_t aid)
936{
937 if (aid < AID_MAX7)
938 return (aid_vals[aid].af);
939 return (AF_UNSPEC0);
940}
941
942int
943af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
944{
945 uint8_t i;
946
947 if (safi == 0) /* default to unicast subclass */
948 safi = SAFI_UNICAST1;
949
950 for (i = 0; i < AID_MAX7; i++)
951 if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
952 *aid = i;
953 return (0);
954 }
955
956 return (-1);
957}
958
959/*
960 * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
961 * the included label stack is ignored and needs to be handled by the caller.
962 */
963struct sockaddr *
964addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
965{
966 static struct sockaddr_storage ss;
967 struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
968 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
969
970 if (addr == NULL((void *)0) || addr->aid == AID_UNSPEC0)
971 return (NULL((void *)0));
972
973 memset(&ss, 0, sizeof(ss));
974 switch (addr->aid) {
975 case AID_INET1:
976 case AID_VPN_IPv43:
977 sa_in->sin_family = AF_INET2;
978 sa_in->sin_addr.s_addr = addr->v4ba.v4.s_addr;
979 sa_in->sin_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
980 *len = sizeof(struct sockaddr_in);
981 break;
982 case AID_INET62:
983 case AID_VPN_IPv64:
984 sa_in6->sin6_family = AF_INET624;
985 memcpy(&sa_in6->sin6_addr, &addr->v6ba.v6,
986 sizeof(sa_in6->sin6_addr));
987 sa_in6->sin6_port = htons(port)(__uint16_t)(__builtin_constant_p(port) ? (__uint16_t)(((__uint16_t
)(port) & 0xffU) << 8 | ((__uint16_t)(port) & 0xff00U
) >> 8) : __swap16md(port))
;
988 sa_in6->sin6_scope_id = addr->scope_id;
989 *len = sizeof(struct sockaddr_in6);
990 break;
991 case AID_FLOWSPECv45:
992 case AID_FLOWSPECv66:
993 return (NULL((void *)0));
994 }
995
996 return ((struct sockaddr *)&ss);
997}
998
999void
1000sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1001{
1002 struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
1003 struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
1004
1005 memset(addr, 0, sizeof(*addr));
1006 switch (sa->sa_family) {
1007 case AF_INET2:
1008 addr->aid = AID_INET1;
1009 memcpy(&addr->v4ba.v4, &sa_in->sin_addr, sizeof(addr->v4ba.v4));
1010 if (port)
1011 *port = ntohs(sa_in->sin_port)(__uint16_t)(__builtin_constant_p(sa_in->sin_port) ? (__uint16_t
)(((__uint16_t)(sa_in->sin_port) & 0xffU) << 8 |
((__uint16_t)(sa_in->sin_port) & 0xff00U) >> 8)
: __swap16md(sa_in->sin_port))
;
1012 break;
1013 case AF_INET624:
1014 addr->aid = AID_INET62;
1015#ifdef __KAME__
1016 /*
1017 * XXX thanks, KAME, for this ugliness...
1018 * adopted from route/show.c
1019 */
1020 if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr)(((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xfe
) && (((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0xc0) == 0x80))
||
1021 IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)(((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
) && (((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0x0f) == 0x02))
||
1022 IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)(((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
) && (((&sa_in6->sin6_addr)->__u6_addr.__u6_addr8
[1] & 0x0f) == 0x01))
) &&
1023 sa_in6->sin6_scope_id == 0) {
1024 uint16_t tmp16;
1025 memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr__u6_addr.__u6_addr8[2],
1026 sizeof(tmp16));
1027 sa_in6->sin6_scope_id = ntohs(tmp16)(__uint16_t)(__builtin_constant_p(tmp16) ? (__uint16_t)(((__uint16_t
)(tmp16) & 0xffU) << 8 | ((__uint16_t)(tmp16) &
0xff00U) >> 8) : __swap16md(tmp16))
;
1028 sa_in6->sin6_addr.s6_addr__u6_addr.__u6_addr8[2] = 0;
1029 sa_in6->sin6_addr.s6_addr__u6_addr.__u6_addr8[3] = 0;
1030 }
1031#endif
1032 memcpy(&addr->v6ba.v6, &sa_in6->sin6_addr, sizeof(addr->v6ba.v6));
1033 addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1034 if (port)
1035 *port = ntohs(sa_in6->sin6_port)(__uint16_t)(__builtin_constant_p(sa_in6->sin6_port) ? (__uint16_t
)(((__uint16_t)(sa_in6->sin6_port) & 0xffU) << 8
| ((__uint16_t)(sa_in6->sin6_port) & 0xff00U) >>
8) : __swap16md(sa_in6->sin6_port))
;
1036 break;
1037 }
1038}
1039
1040const char *
1041get_baudrate(unsigned long long baudrate, char *unit)
1042{
1043 static char bbuf[16];
1044 const unsigned long long kilo = 1000;
1045 const unsigned long long mega = 1000ULL * kilo;
1046 const unsigned long long giga = 1000ULL * mega;
1047
1048 if (baudrate > giga)
1049 snprintf(bbuf, sizeof(bbuf), "%llu G%s",
1050 baudrate / giga, unit);
1051 else if (baudrate > mega)
1052 snprintf(bbuf, sizeof(bbuf), "%llu M%s",
1053 baudrate / mega, unit);
1054 else if (baudrate > kilo)
1055 snprintf(bbuf, sizeof(bbuf), "%llu K%s",
1056 baudrate / kilo, unit);
1057 else
1058 snprintf(bbuf, sizeof(bbuf), "%llu %s",
1059 baudrate, unit);
1060
1061 return (bbuf);
1062}