Bug Summary

File:src/usr.sbin/ldpd/hello.c
Warning:line 391, column 19
Access to field 'hello_holdtime' results in a dereference of a null pointer (loaded from variable 'ia')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name hello.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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.sbin/ldpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/ldpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ldpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -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/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/ldpd/hello.c
1/* $OpenBSD: hello.c,v 1.58 2019/12/12 00:10:29 yasuoka Exp $ */
2
3/*
4 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
5 * Copyright (c) 2009 Michele Marchetto <michele@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
20#include <sys/types.h>
21#include <arpa/inet.h>
22#include <string.h>
23
24#include "ldpd.h"
25#include "ldpe.h"
26#include "log.h"
27
28static int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);
29static int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t);
30static int gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *);
31static int gen_ds_hello_prms_tlv(struct ibuf *, uint32_t);
32static int tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *);
33static int tlv_decode_opt_hello_prms(char *, uint16_t, int *, int,
34 union ldpd_addr *, uint32_t *, uint16_t *);
35
36int
37send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
38{
39 int af;
40 union ldpd_addr dst;
41 uint16_t size, holdtime = 0, flags = 0;
42 int fd = 0;
43 struct ibuf *buf;
44 int err = 0;
45
46 switch (type) {
47 case HELLO_LINK:
48 af = ia->af;
49 holdtime = ia->hello_holdtime;
50 flags = 0;
51 fd = (ldp_af_global_get(&global, af))->ldp_disc_socket;
52
53 /* multicast destination address */
54 switch (af) {
55 case AF_INET2:
56 if (!(leconf->ipv4.flags & F_LDPD_AF_NO_GTSM0x0008))
57 flags |= F_HELLO_GTSM0x2000;
58 dst.v4 = global.mcast_addr_v4;
59 break;
60 case AF_INET624:
61 dst.v6 = global.mcast_addr_v6;
62 break;
63 default:
64 fatalx("send_hello: unknown af");
65 }
66 break;
67 case HELLO_TARGETED:
68 af = tnbr->af;
69 holdtime = tnbr->hello_holdtime;
70 flags = F_HELLO_TARGETED0x8000;
71 if ((tnbr->flags & F_TNBR_CONFIGURED0x01) || tnbr->pw_count)
72 flags |= F_HELLO_REQ_TARG0x4000;
73 fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
74
75 /* unicast destination address */
76 dst = tnbr->addr;
77 break;
78 default:
79 fatalx("send_hello: unknown hello type");
80 }
81
82 /* calculate message size */
83 size = LDP_HDR_SIZE10 + LDP_MSG_SIZE8 + sizeof(struct hello_prms_tlv);
84 switch (af) {
85 case AF_INET2:
86 size += sizeof(struct hello_prms_opt4_tlv);
87 break;
88 case AF_INET624:
89 size += sizeof(struct hello_prms_opt16_tlv);
90 break;
91 default:
92 fatalx("send_hello: unknown af");
93 }
94 size += sizeof(struct hello_prms_opt4_tlv);
95 if (ldp_is_dual_stack(leconf))
96 size += sizeof(struct hello_prms_opt4_tlv);
97
98 /* generate message */
99 if ((buf = ibuf_open(size)) == NULL((void *)0))
100 fatal(__func__);
101
102 err |= gen_ldp_hdr(buf, size);
103 size -= LDP_HDR_SIZE10;
104 err |= gen_msg_hdr(buf, MSG_TYPE_HELLO0x0100, size);
105 err |= gen_hello_prms_tlv(buf, holdtime, flags);
106
107 /*
108 * RFC 7552 - Section 6.1:
109 * "An LSR MUST include only the transport address whose address
110 * family is the same as that of the IP packet carrying the Hello
111 * message".
112 */
113 switch (af) {
114 case AF_INET2:
115 err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR0x0401,
116 leconf->ipv4.trans_addr.v4.s_addr);
117 break;
118 case AF_INET624:
119 err |= gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR0x0403,
120 leconf->ipv6.trans_addr.v6.s6_addr__u6_addr.__u6_addr8);
121 break;
122 default:
123 fatalx("send_hello: unknown af");
124 }
125
126 err |= gen_opt4_hello_prms_tlv(buf, TLV_TYPE_CONFIG0x0402,
127 htonl(global.conf_seqnum)(__uint32_t)(__builtin_constant_p(global.conf_seqnum) ? (__uint32_t
)(((__uint32_t)(global.conf_seqnum) & 0xff) << 24 |
((__uint32_t)(global.conf_seqnum) & 0xff00) << 8 |
((__uint32_t)(global.conf_seqnum) & 0xff0000) >> 8
| ((__uint32_t)(global.conf_seqnum) & 0xff000000) >>
24) : __swap32md(global.conf_seqnum))
);
128
129 /*
130 * RFC 7552 - Section 6.1.1:
131 * "A Dual-stack LSR (i.e., an LSR supporting Dual-stack LDP for a peer)
132 * MUST include the Dual-Stack capability TLV in all of its LDP Hellos".
133 */
134 if (ldp_is_dual_stack(leconf))
135 err |= gen_ds_hello_prms_tlv(buf, leconf->trans_pref);
136
137 if (err) {
138 ibuf_free(buf);
139 return (-1);
140 }
141
142 send_packet(fd, af, &dst, ia, buf->buf, buf->wpos);
143 ibuf_free(buf);
144
145 return (0);
146}
147
148void
149recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
150 union ldpd_addr *src, struct iface *iface, int multicast, char *buf,
151 uint16_t len)
152{
153 struct adj *adj = NULL((void *)0);
154 struct nbr *nbr, *nbrt;
155 uint16_t holdtime, flags;
156 int tlvs_rcvd;
157 int ds_tlv;
158 union ldpd_addr trans_addr;
159 uint32_t scope_id = 0;
160 uint32_t conf_seqnum;
161 uint16_t trans_pref;
162 int r;
163 struct hello_source source;
164 struct iface_af *ia = NULL((void *)0);
1
'ia' initialized to a null pointer value
165 struct tnbr *tnbr = NULL((void *)0);
166
167 r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
168 if (r == -1) {
2
Taking false branch
169 log_debug("%s: lsr-id %s: failed to decode params", __func__,
170 inet_ntoa(lsr_id));
171 return;
172 }
173 /* safety checks */
174 if (holdtime != 0 && holdtime < MIN_HOLDTIME3) {
3
Assuming 'holdtime' is equal to 0
175 log_debug("%s: lsr-id %s: invalid hello holdtime (%u)",
176 __func__, inet_ntoa(lsr_id), holdtime);
177 return;
178 }
179 if (multicast && (flags & F_HELLO_TARGETED0x8000)) {
4
Assuming 'multicast' is 0
180 log_debug("%s: lsr-id %s: multicast targeted hello", __func__,
181 inet_ntoa(lsr_id));
182 return;
183 }
184 if (!multicast
4.1
'multicast' is 0
&& !((flags & F_HELLO_TARGETED0x8000))) {
5
Assuming the condition is false
6
Taking false branch
185 log_debug("%s: lsr-id %s: unicast link hello", __func__,
186 inet_ntoa(lsr_id));
187 return;
188 }
189 buf += r;
190 len -= r;
191
192 r = tlv_decode_opt_hello_prms(buf, len, &tlvs_rcvd, af, &trans_addr,
193 &conf_seqnum, &trans_pref);
194 if (r == -1) {
7
Taking false branch
195 log_debug("%s: lsr-id %s: failed to decode optional params",
196 __func__, inet_ntoa(lsr_id));
197 return;
198 }
199 if (r != len) {
8
Assuming 'r' is equal to 'len'
9
Taking false branch
200 log_debug("%s: lsr-id %s: unexpected data in message",
201 __func__, inet_ntoa(lsr_id));
202 return;
203 }
204
205 /* implicit transport address */
206 if (!(tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR0x01))
10
Taking true branch
207 trans_addr = *src;
208 if (bad_addr(af, &trans_addr)) {
11
Assuming the condition is false
12
Taking false branch
209 log_debug("%s: lsr-id %s: invalid transport address %s",
210 __func__, inet_ntoa(lsr_id), log_addr(af, &trans_addr));
211 return;
212 }
213 if (af == AF_INET624 && IN6_IS_SCOPE_EMBED(&trans_addr.v6)(((((&trans_addr.v6)->__u6_addr.__u6_addr8[0] == 0xfe)
&& (((&trans_addr.v6)->__u6_addr.__u6_addr8[1
] & 0xc0) == 0x80))) || ((((&trans_addr.v6)->__u6_addr
.__u6_addr8[0] == 0xff) && (((&trans_addr.v6)->
__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))) || ((((&trans_addr
.v6)->__u6_addr.__u6_addr8[0] == 0xff) && (((&
trans_addr.v6)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01
))))
) {
13
Assuming 'af' is not equal to AF_INET6
214 /*
215 * RFC 7552 - Section 6.1:
216 * "An LSR MUST use a global unicast IPv6 address in an IPv6
217 * Transport Address optional object of outgoing targeted
218 * Hellos and check for the same in incoming targeted Hellos
219 * (i.e., MUST discard the targeted Hello if it failed the
220 * check)".
221 */
222 if (flags & F_HELLO_TARGETED0x8000) {
223 log_debug("%s: lsr-id %s: invalid targeted hello "
224 "transport address %s", __func__, inet_ntoa(lsr_id),
225 log_addr(af, &trans_addr));
226 return;
227 }
228 scope_id = iface->ifindex;
229 }
230
231 memset(&source, 0, sizeof(source));
232 source.lsr_id = lsr_id;
233 if (flags & F_HELLO_TARGETED0x8000) {
14
Taking true branch
234 /*
235 * RFC 7552 - Section 5.2:
236 * "The link-local IPv6 addresses MUST NOT be used as the
237 * targeted LDP Hello packet's source or destination addresses".
238 */
239 if (af
14.1
'af' is not equal to AF_INET6
== AF_INET624 && IN6_IS_SCOPE_EMBED(&src->v6)(((((&src->v6)->__u6_addr.__u6_addr8[0] == 0xfe) &&
(((&src->v6)->__u6_addr.__u6_addr8[1] & 0xc0) ==
0x80))) || ((((&src->v6)->__u6_addr.__u6_addr8[0] ==
0xff) && (((&src->v6)->__u6_addr.__u6_addr8
[1] & 0x0f) == 0x02))) || ((((&src->v6)->__u6_addr
.__u6_addr8[0] == 0xff) && (((&src->v6)->__u6_addr
.__u6_addr8[1] & 0x0f) == 0x01))))
) {
240 log_debug("%s: lsr-id %s: targeted hello with "
241 "link-local source address", __func__,
242 inet_ntoa(lsr_id));
243 return;
244 }
245
246 tnbr = tnbr_find(leconf, af, src);
247
248 /* remove the dynamic tnbr if the 'R' bit was cleared */
249 if (tnbr && (tnbr->flags & F_TNBR_DYNAMIC0x02) &&
15
Assuming 'tnbr' is non-null
16
Assuming the condition is false
250 !((flags & F_HELLO_REQ_TARG0x4000))) {
251 tnbr->flags &= ~F_TNBR_DYNAMIC0x02;
252 tnbr = tnbr_check(tnbr);
253 }
254
255 if (!tnbr
16.1
'tnbr' is non-null
) {
17
Taking false branch
256 if (!((flags & F_HELLO_REQ_TARG0x4000) &&
257 ((ldp_af_conf_get(leconf, af))->flags &
258 F_LDPD_AF_THELLO_ACCEPT0x0002)))
259 return;
260
261 tnbr = tnbr_new(leconf, af, src);
262 tnbr->flags |= F_TNBR_DYNAMIC0x02;
263 tnbr_update(tnbr);
264 LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry)do { if (((tnbr)->entry.le_next = (&leconf->tnbr_list
)->lh_first) != ((void *)0)) (&leconf->tnbr_list)->
lh_first->entry.le_prev = &(tnbr)->entry.le_next; (
&leconf->tnbr_list)->lh_first = (tnbr); (tnbr)->
entry.le_prev = &(&leconf->tnbr_list)->lh_first
; } while (0)
;
265 }
266
267 source.type = HELLO_TARGETED;
268 source.target = tnbr;
269 } else {
270 ia = iface_af_get(iface, af);
271 source.type = HELLO_LINK;
272 source.link.ia = ia;
273 source.link.src_addr = *src;
274 }
275
276 adj = adj_find(&source);
277 nbr = nbr_find_ldpid(lsr_id.s_addr);
278
279 /* check dual-stack tlv */
280 ds_tlv = (tlvs_rcvd & F_HELLO_TLV_RCVD_DS0x04) ? 1 : 0;
18
'?' condition is false
281 if (ds_tlv
18.1
'ds_tlv' is 0
&& trans_pref != leconf->trans_pref) {
282 /*
283 * RFC 7552 - Section 6.1.1:
284 * "If the Dual-Stack capability TLV is present and the remote
285 * preference does not match the local preference (or does not
286 * get recognized), then the LSR MUST discard the Hello message
287 * and log an error.
288 * If an LDP session was already in place, then the LSR MUST
289 * send a fatal Notification message with status code of
290 * 'Transport Connection Mismatch' and reset the session".
291 */
292 log_debug("%s: lsr-id %s: remote transport preference does not "
293 "match the local preference", __func__, inet_ntoa(lsr_id));
294 if (nbr)
295 session_shutdown(nbr, S_TRANS_MISMTCH0x80000032, msg->id,
296 msg->type);
297 if (adj)
298 adj_del(adj, S_SHUTDOWN0x8000000A);
299 return;
300 }
301
302 /*
303 * Check for noncompliant dual-stack neighbor according to
304 * RFC 7552 section 6.1.1.
305 */
306 if (nbr && !ds_tlv) {
19
Assuming 'nbr' is null
307 switch (af) {
308 case AF_INET2:
309 if (nbr_adj_count(nbr, AF_INET624) > 0) {
310 session_shutdown(nbr, S_DS_NONCMPLNCE0x80000033,
311 msg->id, msg->type);
312 return;
313 }
314 break;
315 case AF_INET624:
316 if (nbr_adj_count(nbr, AF_INET2) > 0) {
317 session_shutdown(nbr, S_DS_NONCMPLNCE0x80000033,
318 msg->id, msg->type);
319 return;
320 }
321 break;
322 default:
323 fatalx("recv_hello: unknown af");
324 }
325 }
326
327 /*
328 * Protections against misconfigured networks and buggy implementations.
329 */
330 if (nbr
19.1
'nbr' is null
&& nbr->af == af &&
331 (ldp_addrcmp(af, &nbr->raddr, &trans_addr) ||
332 nbr->raddr_scope != scope_id)) {
333 log_warnx("%s: lsr-id %s: hello packet advertising a different "
334 "transport address", __func__, inet_ntoa(lsr_id));
335 if (adj)
336 adj_del(adj, S_SHUTDOWN0x8000000A);
337 return;
338 }
339 if (nbr
19.2
'nbr' is equal to NULL
== NULL((void *)0)) {
20
Taking true branch
340 nbrt = nbr_find_addr(af, &trans_addr);
341 if (nbrt) {
21
Assuming 'nbrt' is null
22
Taking false branch
342 log_debug("%s: transport address %s is already being "
343 "used by lsr-id %s", __func__, log_addr(af,
344 &trans_addr), inet_ntoa(nbrt->id));
345 if (adj)
346 adj_del(adj, S_SHUTDOWN0x8000000A);
347 return;
348 }
349 }
350
351 if (adj == NULL((void *)0)) {
23
Assuming 'adj' is not equal to NULL
24
Taking false branch
352 adj = adj_new(lsr_id, &source, &trans_addr);
353 if (nbr) {
354 adj->nbr = nbr;
355 LIST_INSERT_HEAD(&nbr->adj_list, adj, nbr_entry)do { if (((adj)->nbr_entry.le_next = (&nbr->adj_list
)->lh_first) != ((void *)0)) (&nbr->adj_list)->lh_first
->nbr_entry.le_prev = &(adj)->nbr_entry.le_next; (&
nbr->adj_list)->lh_first = (adj); (adj)->nbr_entry.le_prev
= &(&nbr->adj_list)->lh_first; } while (0)
;
356 }
357 }
358
359 /*
360 * If the hello adjacency's address-family doesn't match the local
361 * preference, then an adjacency is still created but we don't attempt
362 * to start an LDP session.
363 */
364 if (nbr
24.1
'nbr' is equal to NULL
== NULL((void *)0) && (!ds_tlv
24.2
'ds_tlv' is 0
||
365 ((trans_pref == DUAL_STACK_LDPOV44 && af == AF_INET2) ||
366 (trans_pref == DUAL_STACK_LDPOV66 && af == AF_INET624))))
367 nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id);
368
369 /* dynamic LDPv4 GTSM negotiation as per RFC 6720 */
370 if (nbr) {
25
Assuming 'nbr' is null
26
Taking false branch
371 if (flags & F_HELLO_GTSM0x2000)
372 nbr->flags |= F_NBR_GTSM_NEGOTIATED0x01;
373 else
374 nbr->flags &= ~F_NBR_GTSM_NEGOTIATED0x01;
375 }
376
377 /* update neighbor's configuration sequence number */
378 if (nbr
26.1
'nbr' is null
&& (tlvs_rcvd & F_HELLO_TLV_RCVD_CONF0x02)) {
379 if (conf_seqnum > nbr->conf_seqnum &&
380 nbr_pending_idtimer(nbr))
381 nbr_stop_idtimer(nbr);
382 nbr->conf_seqnum = conf_seqnum;
383 }
384
385 /* always update the holdtime to properly handle runtime changes */
386 switch (source.type) {
27
Control jumps to 'case HELLO_LINK:' at line 387
387 case HELLO_LINK:
388 if (holdtime
27.1
'holdtime' is equal to 0
== 0)
28
Taking true branch
389 holdtime = LINK_DFLT_HOLDTIME15;
390
391 adj->holdtime = min(ia->hello_holdtime, holdtime)((ia->hello_holdtime) <= (holdtime) ? (ia->hello_holdtime
) : (holdtime))
;
29
Access to field 'hello_holdtime' results in a dereference of a null pointer (loaded from variable 'ia')
392 break;
393 case HELLO_TARGETED:
394 if (holdtime == 0)
395 holdtime = TARGETED_DFLT_HOLDTIME45;
396
397 adj->holdtime = min(tnbr->hello_holdtime, holdtime)((tnbr->hello_holdtime) <= (holdtime) ? (tnbr->hello_holdtime
) : (holdtime))
;
398 }
399 if (adj->holdtime != INFINITE_HOLDTIME0xffff)
400 adj_start_itimer(adj);
401 else
402 adj_stop_itimer(adj);
403
404 if (nbr && nbr->state == NBR_STA_PRESENT0x0001 && !nbr_pending_idtimer(nbr) &&
405 nbr_session_active_role(nbr) && !nbr_pending_connect(nbr))
406 nbr_establish_connection(nbr);
407}
408
409static int
410gen_hello_prms_tlv(struct ibuf *buf, uint16_t holdtime, uint16_t flags)
411{
412 struct hello_prms_tlv parms;
413
414 memset(&parms, 0, sizeof(parms));
415 parms.type = htons(TLV_TYPE_COMMONHELLO)(__uint16_t)(__builtin_constant_p(0x0400) ? (__uint16_t)(((__uint16_t
)(0x0400) & 0xffU) << 8 | ((__uint16_t)(0x0400) &
0xff00U) >> 8) : __swap16md(0x0400))
;
416 parms.length = htons(sizeof(parms.holdtime) + sizeof(parms.flags))(__uint16_t)(__builtin_constant_p(sizeof(parms.holdtime) + sizeof
(parms.flags)) ? (__uint16_t)(((__uint16_t)(sizeof(parms.holdtime
) + sizeof(parms.flags)) & 0xffU) << 8 | ((__uint16_t
)(sizeof(parms.holdtime) + sizeof(parms.flags)) & 0xff00U
) >> 8) : __swap16md(sizeof(parms.holdtime) + sizeof(parms
.flags)))
;
417 parms.holdtime = htons(holdtime)(__uint16_t)(__builtin_constant_p(holdtime) ? (__uint16_t)(((
__uint16_t)(holdtime) & 0xffU) << 8 | ((__uint16_t)
(holdtime) & 0xff00U) >> 8) : __swap16md(holdtime))
;
418 parms.flags = htons(flags)(__uint16_t)(__builtin_constant_p(flags) ? (__uint16_t)(((__uint16_t
)(flags) & 0xffU) << 8 | ((__uint16_t)(flags) &
0xff00U) >> 8) : __swap16md(flags))
;
419
420 return (ibuf_add(buf, &parms, sizeof(parms)));
421}
422
423static int
424gen_opt4_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint32_t value)
425{
426 struct hello_prms_opt4_tlv parms;
427
428 memset(&parms, 0, sizeof(parms));
429 parms.type = htons(type)(__uint16_t)(__builtin_constant_p(type) ? (__uint16_t)(((__uint16_t
)(type) & 0xffU) << 8 | ((__uint16_t)(type) & 0xff00U
) >> 8) : __swap16md(type))
;
430 parms.length = htons(sizeof(parms.value))(__uint16_t)(__builtin_constant_p(sizeof(parms.value)) ? (__uint16_t
)(((__uint16_t)(sizeof(parms.value)) & 0xffU) << 8 |
((__uint16_t)(sizeof(parms.value)) & 0xff00U) >> 8
) : __swap16md(sizeof(parms.value)))
;
431 parms.value = value;
432
433 return (ibuf_add(buf, &parms, sizeof(parms)));
434}
435
436static int
437gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value)
438{
439 struct hello_prms_opt16_tlv parms;
440
441 memset(&parms, 0, sizeof(parms));
442 parms.type = htons(type)(__uint16_t)(__builtin_constant_p(type) ? (__uint16_t)(((__uint16_t
)(type) & 0xffU) << 8 | ((__uint16_t)(type) & 0xff00U
) >> 8) : __swap16md(type))
;
443 parms.length = htons(sizeof(parms.value))(__uint16_t)(__builtin_constant_p(sizeof(parms.value)) ? (__uint16_t
)(((__uint16_t)(sizeof(parms.value)) & 0xffU) << 8 |
((__uint16_t)(sizeof(parms.value)) & 0xff00U) >> 8
) : __swap16md(sizeof(parms.value)))
;
444 memcpy(&parms.value, value, sizeof(parms.value));
445
446 return (ibuf_add(buf, &parms, sizeof(parms)));
447}
448
449static int
450gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value)
451{
452 if (leconf->flags & F_LDPD_DS_CISCO_INTEROP0x0002)
453 value = htonl(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t
)(value) & 0xff) << 24 | ((__uint32_t)(value) &
0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >>
8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md
(value))
;
454 else
455 value = htonl(value << 28)(__uint32_t)(__builtin_constant_p(value << 28) ? (__uint32_t
)(((__uint32_t)(value << 28) & 0xff) << 24 | (
(__uint32_t)(value << 28) & 0xff00) << 8 | ((
__uint32_t)(value << 28) & 0xff0000) >> 8 | (
(__uint32_t)(value << 28) & 0xff000000) >> 24
) : __swap32md(value << 28))
;
456
457 return (gen_opt4_hello_prms_tlv(buf, TLV_TYPE_DUALSTACK0x8701, value));
458}
459
460static int
461tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime,
462 uint16_t *flags)
463{
464 struct hello_prms_tlv tlv;
465
466 if (len < sizeof(tlv))
467 return (-1);
468 memcpy(&tlv, buf, sizeof(tlv));
469
470 if (tlv.type != htons(TLV_TYPE_COMMONHELLO)(__uint16_t)(__builtin_constant_p(0x0400) ? (__uint16_t)(((__uint16_t
)(0x0400) & 0xffU) << 8 | ((__uint16_t)(0x0400) &
0xff00U) >> 8) : __swap16md(0x0400))
)
471 return (-1);
472 if (ntohs(tlv.length)(__uint16_t)(__builtin_constant_p(tlv.length) ? (__uint16_t)(
((__uint16_t)(tlv.length) & 0xffU) << 8 | ((__uint16_t
)(tlv.length) & 0xff00U) >> 8) : __swap16md(tlv.length
))
!= sizeof(tlv) - TLV_HDR_SIZE4)
473 return (-1);
474
475 *holdtime = ntohs(tlv.holdtime)(__uint16_t)(__builtin_constant_p(tlv.holdtime) ? (__uint16_t
)(((__uint16_t)(tlv.holdtime) & 0xffU) << 8 | ((__uint16_t
)(tlv.holdtime) & 0xff00U) >> 8) : __swap16md(tlv.holdtime
))
;
476 *flags = ntohs(tlv.flags)(__uint16_t)(__builtin_constant_p(tlv.flags) ? (__uint16_t)((
(__uint16_t)(tlv.flags) & 0xffU) << 8 | ((__uint16_t
)(tlv.flags) & 0xff00U) >> 8) : __swap16md(tlv.flags
))
;
477
478 return (sizeof(tlv));
479}
480
481static int
482tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
483 union ldpd_addr *addr, uint32_t *conf_number, uint16_t *trans_pref)
484{
485 struct tlv tlv;
486 uint16_t tlv_len;
487 int total = 0;
488
489 *tlvs_rcvd = 0;
490 memset(addr, 0, sizeof(*addr));
491 *conf_number = 0;
492 *trans_pref = 0;
493
494 /*
495 * RFC 7552 - Section 6.1:
496 * "An LSR SHOULD accept the Hello message that contains both IPv4 and
497 * IPv6 Transport Address optional objects but MUST use only the
498 * transport address whose address family is the same as that of the
499 * IP packet carrying the Hello message. An LSR SHOULD accept only
500 * the first Transport Address optional object for a given address
501 * family in the received Hello message and ignore the rest if the
502 * LSR receives more than one Transport Address optional object for a
503 * given address family".
504 */
505 while (len >= sizeof(tlv)) {
506 memcpy(&tlv, buf, TLV_HDR_SIZE4);
507 tlv_len = ntohs(tlv.length)(__uint16_t)(__builtin_constant_p(tlv.length) ? (__uint16_t)(
((__uint16_t)(tlv.length) & 0xffU) << 8 | ((__uint16_t
)(tlv.length) & 0xff00U) >> 8) : __swap16md(tlv.length
))
;
508 if (tlv_len + TLV_HDR_SIZE4 > len)
509 return (-1);
510 buf += TLV_HDR_SIZE4;
511 len -= TLV_HDR_SIZE4;
512 total += TLV_HDR_SIZE4;
513
514 switch (ntohs(tlv.type)(__uint16_t)(__builtin_constant_p(tlv.type) ? (__uint16_t)(((
__uint16_t)(tlv.type) & 0xffU) << 8 | ((__uint16_t)
(tlv.type) & 0xff00U) >> 8) : __swap16md(tlv.type))
) {
515 case TLV_TYPE_IPV4TRANSADDR0x0401:
516 if (tlv_len != sizeof(addr->v4))
517 return (-1);
518 if (af != AF_INET2)
519 return (-1);
520 if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR0x01)
521 break;
522 memcpy(&addr->v4, buf, sizeof(addr->v4));
523 *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR0x01;
524 break;
525 case TLV_TYPE_IPV6TRANSADDR0x0403:
526 if (tlv_len != sizeof(addr->v6))
527 return (-1);
528 if (af != AF_INET624)
529 return (-1);
530 if (*tlvs_rcvd & F_HELLO_TLV_RCVD_ADDR0x01)
531 break;
532 memcpy(&addr->v6, buf, sizeof(addr->v6));
533 *tlvs_rcvd |= F_HELLO_TLV_RCVD_ADDR0x01;
534 break;
535 case TLV_TYPE_CONFIG0x0402:
536 if (tlv_len != sizeof(uint32_t))
537 return (-1);
538 memcpy(conf_number, buf, sizeof(uint32_t));
539 *tlvs_rcvd |= F_HELLO_TLV_RCVD_CONF0x02;
540 break;
541 case TLV_TYPE_DUALSTACK0x8701:
542 if (tlv_len != sizeof(uint32_t))
543 return (-1);
544 /*
545 * RFC 7552 - Section 6.1:
546 * "A Single-stack LSR does not need to use the
547 * Dual-Stack capability in Hello messages and SHOULD
548 * ignore this capability if received".
549 */
550 if (!ldp_is_dual_stack(leconf))
551 break;
552 /* Shame on you, Cisco! */
553 if (leconf->flags & F_LDPD_DS_CISCO_INTEROP0x0002) {
554 memcpy(trans_pref, buf + sizeof(uint16_t),
555 sizeof(uint16_t));
556 *trans_pref = ntohs(*trans_pref)(__uint16_t)(__builtin_constant_p(*trans_pref) ? (__uint16_t)
(((__uint16_t)(*trans_pref) & 0xffU) << 8 | ((__uint16_t
)(*trans_pref) & 0xff00U) >> 8) : __swap16md(*trans_pref
))
;
557 } else {
558 memcpy(trans_pref, buf , sizeof(uint16_t));
559 *trans_pref = ntohs(*trans_pref)(__uint16_t)(__builtin_constant_p(*trans_pref) ? (__uint16_t)
(((__uint16_t)(*trans_pref) & 0xffU) << 8 | ((__uint16_t
)(*trans_pref) & 0xff00U) >> 8) : __swap16md(*trans_pref
))
>> 12;
560 }
561 *tlvs_rcvd |= F_HELLO_TLV_RCVD_DS0x04;
562 break;
563 default:
564 /* if unknown flag set, ignore TLV */
565 if (!(ntohs(tlv.type)(__uint16_t)(__builtin_constant_p(tlv.type) ? (__uint16_t)(((
__uint16_t)(tlv.type) & 0xffU) << 8 | ((__uint16_t)
(tlv.type) & 0xff00U) >> 8) : __swap16md(tlv.type))
& UNKNOWN_FLAG0x8000))
566 return (-1);
567 break;
568 }
569 buf += tlv_len;
570 len -= tlv_len;
571 total += tlv_len;
572 }
573
574 return (total);
575}