File: | src/usr.sbin/ldpd/hello.c |
Warning: | line 397, column 19 Access to field 'hello_holdtime' results in a dereference of a null pointer (loaded from variable 'tnbr') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: hello.c,v 1.59 2023/07/03 11:51:27 claudio 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 | |||||
28 | static int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t); | ||||
29 | static int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t); | ||||
30 | static int gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *); | ||||
31 | static int gen_ds_hello_prms_tlv(struct ibuf *, uint32_t); | ||||
32 | static int tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *); | ||||
33 | static int tlv_decode_opt_hello_prms(char *, uint16_t, int *, int, | ||||
34 | union ldpd_addr *, uint32_t *, uint16_t *); | ||||
35 | |||||
36 | int | ||||
37 | send_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, ibuf_data(buf), ibuf_size(buf)); | ||||
143 | ibuf_free(buf); | ||||
144 | |||||
145 | return (0); | ||||
146 | } | ||||
147 | |||||
148 | void | ||||
149 | recv_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); | ||||
165 | struct tnbr *tnbr = NULL((void *)0); | ||||
| |||||
166 | |||||
167 | r = tlv_decode_hello_prms(buf, len, &holdtime, &flags); | ||||
168 | if (r == -1) { | ||||
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) { | ||||
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)) { | ||||
180 | log_debug("%s: lsr-id %s: multicast targeted hello", __func__, | ||||
181 | inet_ntoa(lsr_id)); | ||||
182 | return; | ||||
183 | } | ||||
184 | if (!multicast
| ||||
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) { | ||||
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) { | ||||
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)) | ||||
207 | trans_addr = *src; | ||||
208 | if (bad_addr(af, &trans_addr)) { | ||||
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 ))))) { | ||||
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) { | ||||
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 == 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) && | ||||
250 | !((flags & F_HELLO_REQ_TARG0x4000))) { | ||||
251 | tnbr->flags &= ~F_TNBR_DYNAMIC0x02; | ||||
252 | tnbr = tnbr_check(tnbr); | ||||
253 | } | ||||
254 | |||||
255 | if (!tnbr) { | ||||
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; | ||||
281 | if (ds_tlv
| ||||
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) { | ||||
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
| ||||
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
| ||||
340 | nbrt = nbr_find_addr(af, &trans_addr); | ||||
341 | if (nbrt) { | ||||
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)) { | ||||
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
| ||||
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) { | ||||
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
| ||||
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) { | ||||
387 | case HELLO_LINK: | ||||
388 | if (holdtime == 0) | ||||
389 | holdtime = LINK_DFLT_HOLDTIME15; | ||||
390 | |||||
391 | adj->holdtime = min(ia->hello_holdtime, holdtime)((ia->hello_holdtime) <= (holdtime) ? (ia->hello_holdtime ) : (holdtime)); | ||||
392 | break; | ||||
393 | case HELLO_TARGETED: | ||||
394 | if (holdtime
| ||||
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 | |||||
409 | static int | ||||
410 | gen_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 | |||||
423 | static int | ||||
424 | gen_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 | |||||
436 | static int | ||||
437 | gen_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 | |||||
449 | static int | ||||
450 | gen_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 | |||||
460 | static int | ||||
461 | tlv_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 | |||||
481 | static int | ||||
482 | tlv_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 | } |