]> git.proxmox.com Git - mirror_frr.git/blame - ldpd/hello.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / ldpd / hello.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: ISC
8429abe0
RW
2/* $OpenBSD$ */
3
4/*
5 * Copyright (c) 2013, 2016 Renato Westphal <renato@openbsd.org>
6 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
8429abe0
RW
7 */
8
eac6e3f0 9#include <zebra.h>
8429abe0
RW
10
11#include "ldpd.h"
12#include "ldpe.h"
13#include "log.h"
eac6e3f0 14#include "ldp_debug.h"
8429abe0
RW
15
16static int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);
17static int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t);
18static int gen_opt16_hello_prms_tlv(struct ibuf *, uint16_t, uint8_t *);
19static int gen_ds_hello_prms_tlv(struct ibuf *, uint32_t);
20static int tlv_decode_hello_prms(char *, uint16_t, uint16_t *, uint16_t *);
21static int tlv_decode_opt_hello_prms(char *, uint16_t, int *, int,
22 union ldpd_addr *, uint32_t *, uint16_t *);
23
24int
25send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
26{
27 int af;
28 union ldpd_addr dst;
29 uint16_t size, holdtime = 0, flags = 0;
30 int fd = 0;
31 struct ibuf *buf;
32 int err = 0;
33
34 switch (type) {
35 case HELLO_LINK:
36 af = ia->af;
eac6e3f0 37 holdtime = if_get_hello_holdtime(ia);
8429abe0
RW
38 flags = 0;
39 fd = (ldp_af_global_get(&global, af))->ldp_disc_socket;
40
41 /* multicast destination address */
42 switch (af) {
43 case AF_INET:
bcffa759 44 if (!CHECK_FLAG(leconf->ipv4.flags, F_LDPD_AF_NO_GTSM))
45 SET_FLAG(flags, F_HELLO_GTSM);
8429abe0
RW
46 dst.v4 = global.mcast_addr_v4;
47 break;
48 case AF_INET6:
49 dst.v6 = global.mcast_addr_v6;
50 break;
51 default:
52 fatalx("send_hello: unknown af");
53 }
54 break;
55 case HELLO_TARGETED:
56 af = tnbr->af;
eac6e3f0 57 holdtime = tnbr_get_hello_holdtime(tnbr);
8429abe0 58 flags = F_HELLO_TARGETED;
bcffa759 59 if (CHECK_FLAG(tnbr->flags, F_TNBR_CONFIGURED) ||
60 tnbr->pw_count ||
61 tnbr->rlfa_count)
8429abe0 62 flags |= F_HELLO_REQ_TARG;
bcffa759 63
8429abe0
RW
64 fd = (ldp_af_global_get(&global, af))->ldp_edisc_socket;
65
66 /* unicast destination address */
67 dst = tnbr->addr;
68 break;
69 default:
70 fatalx("send_hello: unknown hello type");
71 }
72
73 /* calculate message size */
74 size = LDP_HDR_SIZE + LDP_MSG_SIZE + sizeof(struct hello_prms_tlv);
75 switch (af) {
76 case AF_INET:
77 size += sizeof(struct hello_prms_opt4_tlv);
78 break;
79 case AF_INET6:
80 size += sizeof(struct hello_prms_opt16_tlv);
81 break;
82 default:
83 fatalx("send_hello: unknown af");
84 }
85 size += sizeof(struct hello_prms_opt4_tlv);
86 if (ldp_is_dual_stack(leconf))
87 size += sizeof(struct hello_prms_opt4_tlv);
88
89 /* generate message */
90 if ((buf = ibuf_open(size)) == NULL)
91 fatal(__func__);
92
bcffa759 93 SET_FLAG(err, gen_ldp_hdr(buf, size));
8429abe0 94 size -= LDP_HDR_SIZE;
bcffa759 95 SET_FLAG(err, gen_msg_hdr(buf, MSG_TYPE_HELLO, size));
96 SET_FLAG(err, gen_hello_prms_tlv(buf, holdtime, flags));
8429abe0
RW
97
98 /*
99 * RFC 7552 - Section 6.1:
100 * "An LSR MUST include only the transport address whose address
101 * family is the same as that of the IP packet carrying the Hello
102 * message".
103 */
104 switch (af) {
105 case AF_INET:
bcffa759 106 SET_FLAG(err, gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR,
107 leconf->ipv4.trans_addr.v4.s_addr));
8429abe0
RW
108 break;
109 case AF_INET6:
bcffa759 110 SET_FLAG(err, gen_opt16_hello_prms_tlv(buf, TLV_TYPE_IPV6TRANSADDR,
111 leconf->ipv6.trans_addr.v6.s6_addr));
8429abe0
RW
112 break;
113 default:
114 fatalx("send_hello: unknown af");
115 }
116
bcffa759 117 SET_FLAG(err, gen_opt4_hello_prms_tlv(buf, TLV_TYPE_CONFIG,
118 htonl(global.conf_seqnum)));
8429abe0
RW
119
120 /*
121 * RFC 7552 - Section 6.1.1:
122 * "A Dual-stack LSR (i.e., an LSR supporting Dual-stack LDP for a peer)
123 * MUST include the Dual-Stack capability TLV in all of its LDP Hellos".
124 */
125 if (ldp_is_dual_stack(leconf))
bcffa759 126 SET_FLAG(err, gen_ds_hello_prms_tlv(buf, leconf->trans_pref));
8429abe0
RW
127
128 if (err) {
129 ibuf_free(buf);
130 return (-1);
131 }
132
eac6e3f0
RW
133 switch (type) {
134 case HELLO_LINK:
135 debug_hello_send("iface %s (%s) holdtime %u", ia->iface->name,
136 af_name(ia->af), holdtime);
137 break;
138 case HELLO_TARGETED:
139 debug_hello_send("targeted-neighbor %s (%s) holdtime %u",
140 log_addr(tnbr->af, &tnbr->addr), af_name(tnbr->af),
141 holdtime);
142 break;
143 default:
144 fatalx("send_hello: unknown hello type");
145 }
146
8429abe0
RW
147 send_packet(fd, af, &dst, ia, buf->buf, buf->wpos);
148 ibuf_free(buf);
149
150 return (0);
151}
152
153void
154recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
155 union ldpd_addr *src, struct iface *iface, int multicast, char *buf,
156 uint16_t len)
157{
158 struct adj *adj = NULL;
159 struct nbr *nbr, *nbrt;
eac6e3f0 160 uint16_t holdtime = 0, flags = 0;
8429abe0
RW
161 int tlvs_rcvd;
162 int ds_tlv;
163 union ldpd_addr trans_addr;
6cd8093d 164 ifindex_t scope_id = 0;
8429abe0
RW
165 uint32_t conf_seqnum;
166 uint16_t trans_pref;
167 int r;
168 struct hello_source source;
169 struct iface_af *ia = NULL;
170 struct tnbr *tnbr = NULL;
171
172 r = tlv_decode_hello_prms(buf, len, &holdtime, &flags);
173 if (r == -1) {
bcffa759 174 log_debug("%s: lsr-id %pI4: failed to decode params", __func__, &lsr_id);
8429abe0
RW
175 return;
176 }
177 /* safety checks */
178 if (holdtime != 0 && holdtime < MIN_HOLDTIME) {
903a7226
MS
179 log_debug("%s: lsr-id %pI4: invalid hello holdtime (%u)",
180 __func__, &lsr_id, holdtime);
8429abe0
RW
181 return;
182 }
bcffa759 183 if (multicast && CHECK_FLAG(flags, F_HELLO_TARGETED)) {
184 log_debug("%s: lsr-id %pI4: multicast targeted hello", __func__, &lsr_id);
8429abe0
RW
185 return;
186 }
bcffa759 187 if (!multicast && !CHECK_FLAG(flags, F_HELLO_TARGETED)) {
188 log_debug("%s: lsr-id %pI4: unicast link hello", __func__, &lsr_id);
8429abe0
RW
189 return;
190 }
191 buf += r;
192 len -= r;
193
194 r = tlv_decode_opt_hello_prms(buf, len, &tlvs_rcvd, af, &trans_addr,
195 &conf_seqnum, &trans_pref);
196 if (r == -1) {
903a7226
MS
197 log_debug("%s: lsr-id %pI4: failed to decode optional params",
198 __func__, &lsr_id);
8429abe0
RW
199 return;
200 }
201 if (r != len) {
903a7226
MS
202 log_debug("%s: lsr-id %pI4: unexpected data in message",
203 __func__, &lsr_id);
8429abe0
RW
204 return;
205 }
bcffa759 206 ds_tlv = CHECK_FLAG(tlvs_rcvd, F_HELLO_TLV_RCVD_DS) ? 1 : 0;
8429abe0
RW
207
208 /* implicit transport address */
bcffa759 209 if (!CHECK_FLAG(tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
8429abe0
RW
210 trans_addr = *src;
211 if (bad_addr(af, &trans_addr)) {
903a7226
MS
212 log_debug("%s: lsr-id %pI4: invalid transport address %s",
213 __func__, &lsr_id, log_addr(af, &trans_addr));
8429abe0
RW
214 return;
215 }
216 if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&trans_addr.v6)) {
217 /*
218 * RFC 7552 - Section 6.1:
219 * "An LSR MUST use a global unicast IPv6 address in an IPv6
220 * Transport Address optional object of outgoing targeted
221 * Hellos and check for the same in incoming targeted Hellos
222 * (i.e., MUST discard the targeted Hello if it failed the
223 * check)".
224 */
bcffa759 225 if (CHECK_FLAG(flags, F_HELLO_TARGETED)) {
903a7226 226 log_debug("%s: lsr-id %pI4: invalid targeted hello transport address %s", __func__, &lsr_id,
8429abe0
RW
227 log_addr(af, &trans_addr));
228 return;
229 }
230 scope_id = iface->ifindex;
231 }
232
233 memset(&source, 0, sizeof(source));
bcffa759 234 if (CHECK_FLAG(flags, F_HELLO_TARGETED)) {
8429abe0
RW
235 /*
236 * RFC 7552 - Section 5.2:
237 * "The link-local IPv6 addresses MUST NOT be used as the
238 * targeted LDP Hello packet's source or destination addresses".
239 */
240 if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&src->v6)) {
903a7226
MS
241 log_debug("%s: lsr-id %pI4: targeted hello with link-local source address", __func__,
242 &lsr_id);
8429abe0
RW
243 return;
244 }
245
246 tnbr = tnbr_find(leconf, af, src);
247
248 /* remove the dynamic tnbr if the 'R' bit was cleared */
bcffa759 249 if (tnbr &&
250 CHECK_FLAG(tnbr->flags, F_TNBR_DYNAMIC) &&
251 !CHECK_FLAG(flags, F_HELLO_REQ_TARG)) {
252 UNSET_FLAG(tnbr->flags, F_TNBR_DYNAMIC);
7989cdba 253 tnbr = tnbr_check(leconf, tnbr);
8429abe0
RW
254 }
255
256 if (!tnbr) {
45a8eba9
RW
257 struct ldpd_af_conf *af_conf;
258
bcffa759 259 if (!CHECK_FLAG(flags, F_HELLO_REQ_TARG))
45a8eba9
RW
260 return;
261 af_conf = ldp_af_conf_get(leconf, af);
bcffa759 262 if (!CHECK_FLAG(af_conf->flags, F_LDPD_AF_THELLO_ACCEPT))
45a8eba9
RW
263 return;
264 if (ldpe_acl_check(af_conf->acl_thello_accept_from, af,
265 src, (af == AF_INET) ? 32 : 128) != FILTER_PERMIT)
8429abe0
RW
266 return;
267
eac6e3f0 268 tnbr = tnbr_new(af, src);
bcffa759 269 SET_FLAG(tnbr->flags, F_TNBR_DYNAMIC);
8429abe0 270 tnbr_update(tnbr);
7989cdba 271 RB_INSERT(tnbr_head, &leconf->tnbr_tree, tnbr);
8429abe0
RW
272 }
273
274 source.type = HELLO_TARGETED;
275 source.target = tnbr;
276 } else {
277 ia = iface_af_get(iface, af);
278 source.type = HELLO_LINK;
279 source.link.ia = ia;
280 source.link.src_addr = *src;
281 }
282
903a7226
MS
283 debug_hello_recv("%s lsr-id %pI4 transport-address %s holdtime %u%s",
284 log_hello_src(&source), &lsr_id, log_addr(af, &trans_addr),
0e3451e5
RW
285 holdtime, (ds_tlv) ? " (dual stack TLV present)" : "");
286
f2725627 287 adj = adj_find(lsr_id, &source);
0e3451e5
RW
288 if (adj && adj->ds_tlv != ds_tlv) {
289 /*
290 * Transient condition, ignore packet and wait until adjacency
291 * times out.
292 */
293 return;
294 }
8429abe0
RW
295 nbr = nbr_find_ldpid(lsr_id.s_addr);
296
297 /* check dual-stack tlv */
8429abe0
RW
298 if (ds_tlv && trans_pref != leconf->trans_pref) {
299 /*
300 * RFC 7552 - Section 6.1.1:
301 * "If the Dual-Stack capability TLV is present and the remote
302 * preference does not match the local preference (or does not
303 * get recognized), then the LSR MUST discard the Hello message
304 * and log an error.
305 * If an LDP session was already in place, then the LSR MUST
306 * send a fatal Notification message with status code of
307 * 'Transport Connection Mismatch' and reset the session".
308 */
903a7226 309 log_debug("%s: lsr-id %pI4: remote transport preference does not match the local preference", __func__, &lsr_id);
8429abe0 310 if (nbr)
bcffa759 311 session_shutdown(nbr, S_TRANS_MISMTCH, msg->id, msg->type);
8429abe0
RW
312 if (adj)
313 adj_del(adj, S_SHUTDOWN);
314 return;
315 }
316
317 /*
318 * Check for noncompliant dual-stack neighbor according to
319 * RFC 7552 section 6.1.1.
320 */
321 if (nbr && !ds_tlv) {
322 switch (af) {
323 case AF_INET:
324 if (nbr_adj_count(nbr, AF_INET6) > 0) {
bcffa759 325 session_shutdown(nbr, S_DS_NONCMPLNCE, msg->id, msg->type);
8429abe0
RW
326 return;
327 }
328 break;
329 case AF_INET6:
330 if (nbr_adj_count(nbr, AF_INET) > 0) {
bcffa759 331 session_shutdown(nbr, S_DS_NONCMPLNCE, msg->id, msg->type);
8429abe0
RW
332 return;
333 }
334 break;
335 default:
336 fatalx("recv_hello: unknown af");
337 }
338 }
339
340 /*
341 * Protections against misconfigured networks and buggy implementations.
342 */
343 if (nbr && nbr->af == af &&
344 (ldp_addrcmp(af, &nbr->raddr, &trans_addr) ||
345 nbr->raddr_scope != scope_id)) {
903a7226 346 log_warnx("%s: lsr-id %pI4: hello packet advertising a different transport address", __func__, &lsr_id);
8429abe0
RW
347 if (adj)
348 adj_del(adj, S_SHUTDOWN);
349 return;
350 }
351 if (nbr == NULL) {
352 nbrt = nbr_find_addr(af, &trans_addr);
353 if (nbrt) {
903a7226
MS
354 log_debug("%s: transport address %s is already being used by lsr-id %pI4", __func__, log_addr(af,
355 &trans_addr), &nbrt->id);
8429abe0
RW
356 if (adj)
357 adj_del(adj, S_SHUTDOWN);
358 return;
359 }
360 }
361
362 if (adj == NULL) {
363 adj = adj_new(lsr_id, &source, &trans_addr);
364 if (nbr) {
365 adj->nbr = nbr;
057d48bd 366 RB_INSERT(nbr_adj_head, &nbr->adj_tree, adj);
8429abe0 367 }
e1894ff7 368 ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_NEW);
8429abe0 369 }
0f7b5df9 370 adj->ds_tlv = ds_tlv;
8429abe0
RW
371
372 /*
373 * If the hello adjacency's address-family doesn't match the local
374 * preference, then an adjacency is still created but we don't attempt
375 * to start an LDP session.
376 */
377 if (nbr == NULL && (!ds_tlv ||
378 ((trans_pref == DUAL_STACK_LDPOV4 && af == AF_INET) ||
379 (trans_pref == DUAL_STACK_LDPOV6 && af == AF_INET6))))
380 nbr = nbr_new(lsr_id, af, ds_tlv, &trans_addr, scope_id);
381
382 /* dynamic LDPv4 GTSM negotiation as per RFC 6720 */
383 if (nbr) {
bcffa759 384 if (CHECK_FLAG(flags, F_HELLO_GTSM))
385 SET_FLAG(nbr->flags, F_NBR_GTSM_NEGOTIATED);
8429abe0 386 else
bcffa759 387 UNSET_FLAG(nbr->flags, F_NBR_GTSM_NEGOTIATED);
8429abe0
RW
388 }
389
390 /* update neighbor's configuration sequence number */
391 if (nbr && (tlvs_rcvd & F_HELLO_TLV_RCVD_CONF)) {
bcffa759 392 if (conf_seqnum > nbr->conf_seqnum && nbr_pending_idtimer(nbr))
8429abe0
RW
393 nbr_stop_idtimer(nbr);
394 nbr->conf_seqnum = conf_seqnum;
395 }
396
397 /* always update the holdtime to properly handle runtime changes */
398 switch (source.type) {
399 case HELLO_LINK:
400 if (holdtime == 0)
401 holdtime = LINK_DFLT_HOLDTIME;
402
7a8ce9d5 403 adj->holdtime = MIN(if_get_hello_holdtime(ia), holdtime);
8429abe0
RW
404 break;
405 case HELLO_TARGETED:
406 if (holdtime == 0)
407 holdtime = TARGETED_DFLT_HOLDTIME;
408
7a8ce9d5 409 adj->holdtime = MIN(tnbr_get_hello_holdtime(tnbr), holdtime);
8429abe0
RW
410 }
411 if (adj->holdtime != INFINITE_HOLDTIME)
412 adj_start_itimer(adj);
413 else
414 adj_stop_itimer(adj);
415
416 if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) &&
417 nbr_session_active_role(nbr) && !nbr_pending_connect(nbr))
418 nbr_establish_connection(nbr);
419}
420
421static int
422gen_hello_prms_tlv(struct ibuf *buf, uint16_t holdtime, uint16_t flags)
423{
424 struct hello_prms_tlv parms;
425
426 memset(&parms, 0, sizeof(parms));
427 parms.type = htons(TLV_TYPE_COMMONHELLO);
428 parms.length = htons(sizeof(parms.holdtime) + sizeof(parms.flags));
429 parms.holdtime = htons(holdtime);
430 parms.flags = htons(flags);
431
432 return (ibuf_add(buf, &parms, sizeof(parms)));
433}
434
435static int
436gen_opt4_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint32_t value)
437{
438 struct hello_prms_opt4_tlv parms;
439
440 memset(&parms, 0, sizeof(parms));
441 parms.type = htons(type);
442 parms.length = htons(sizeof(parms.value));
443 parms.value = value;
444
445 return (ibuf_add(buf, &parms, sizeof(parms)));
446}
447
448static int
449gen_opt16_hello_prms_tlv(struct ibuf *buf, uint16_t type, uint8_t *value)
450{
451 struct hello_prms_opt16_tlv parms;
452
453 memset(&parms, 0, sizeof(parms));
454 parms.type = htons(type);
455 parms.length = htons(sizeof(parms.value));
456 memcpy(&parms.value, value, sizeof(parms.value));
457
458 return (ibuf_add(buf, &parms, sizeof(parms)));
459}
460
461static int
462gen_ds_hello_prms_tlv(struct ibuf *buf, uint32_t value)
463{
bcffa759 464 if (CHECK_FLAG(leconf->flags, F_LDPD_DS_CISCO_INTEROP))
8429abe0
RW
465 value = htonl(value);
466 else
467 value = htonl(value << 28);
468
469 return (gen_opt4_hello_prms_tlv(buf, TLV_TYPE_DUALSTACK, value));
470}
471
472static int
473tlv_decode_hello_prms(char *buf, uint16_t len, uint16_t *holdtime,
474 uint16_t *flags)
475{
476 struct hello_prms_tlv tlv;
477
478 if (len < sizeof(tlv))
479 return (-1);
480 memcpy(&tlv, buf, sizeof(tlv));
481
482 if (tlv.type != htons(TLV_TYPE_COMMONHELLO))
483 return (-1);
484 if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_SIZE)
485 return (-1);
486
487 *holdtime = ntohs(tlv.holdtime);
488 *flags = ntohs(tlv.flags);
489
490 return (sizeof(tlv));
491}
492
493static int
494tlv_decode_opt_hello_prms(char *buf, uint16_t len, int *tlvs_rcvd, int af,
495 union ldpd_addr *addr, uint32_t *conf_number, uint16_t *trans_pref)
496{
497 struct tlv tlv;
498 uint16_t tlv_len;
499 int total = 0;
500
501 *tlvs_rcvd = 0;
502 memset(addr, 0, sizeof(*addr));
503 *conf_number = 0;
504 *trans_pref = 0;
505
506 /*
507 * RFC 7552 - Section 6.1:
508 * "An LSR SHOULD accept the Hello message that contains both IPv4 and
509 * IPv6 Transport Address optional objects but MUST use only the
510 * transport address whose address family is the same as that of the
511 * IP packet carrying the Hello message. An LSR SHOULD accept only
512 * the first Transport Address optional object for a given address
513 * family in the received Hello message and ignore the rest if the
514 * LSR receives more than one Transport Address optional object for a
515 * given address family".
516 */
517 while (len >= sizeof(tlv)) {
518 memcpy(&tlv, buf, TLV_HDR_SIZE);
519 tlv_len = ntohs(tlv.length);
520 if (tlv_len + TLV_HDR_SIZE > len)
521 return (-1);
522 buf += TLV_HDR_SIZE;
523 len -= TLV_HDR_SIZE;
524 total += TLV_HDR_SIZE;
525
526 switch (ntohs(tlv.type)) {
527 case TLV_TYPE_IPV4TRANSADDR:
528 if (tlv_len != sizeof(addr->v4))
529 return (-1);
530 if (af != AF_INET)
531 return (-1);
bcffa759 532 if (CHECK_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
8429abe0
RW
533 break;
534 memcpy(&addr->v4, buf, sizeof(addr->v4));
bcffa759 535 SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR);
8429abe0
RW
536 break;
537 case TLV_TYPE_IPV6TRANSADDR:
538 if (tlv_len != sizeof(addr->v6))
539 return (-1);
540 if (af != AF_INET6)
541 return (-1);
bcffa759 542 if (CHECK_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR))
8429abe0
RW
543 break;
544 memcpy(&addr->v6, buf, sizeof(addr->v6));
bcffa759 545 SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_ADDR);
8429abe0
RW
546 break;
547 case TLV_TYPE_CONFIG:
548 if (tlv_len != sizeof(uint32_t))
549 return (-1);
550 memcpy(conf_number, buf, sizeof(uint32_t));
bcffa759 551 SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_CONF);
8429abe0
RW
552 break;
553 case TLV_TYPE_DUALSTACK:
554 if (tlv_len != sizeof(uint32_t))
555 return (-1);
556 /*
557 * RFC 7552 - Section 6.1:
558 * "A Single-stack LSR does not need to use the
559 * Dual-Stack capability in Hello messages and SHOULD
560 * ignore this capability if received".
561 */
562 if (!ldp_is_dual_stack(leconf))
563 break;
564 /* Shame on you, Cisco! */
bcffa759 565 if (CHECK_FLAG(leconf->flags, F_LDPD_DS_CISCO_INTEROP)) {
566 memcpy(trans_pref, buf + sizeof(uint16_t), sizeof(uint16_t));
8429abe0
RW
567 *trans_pref = ntohs(*trans_pref);
568 } else {
569 memcpy(trans_pref, buf , sizeof(uint16_t));
570 *trans_pref = ntohs(*trans_pref) >> 12;
571 }
bcffa759 572 SET_FLAG(*tlvs_rcvd, F_HELLO_TLV_RCVD_DS);
8429abe0
RW
573 break;
574 default:
575 /* if unknown flag set, ignore TLV */
bcffa759 576 if (!CHECK_FLAG(ntohs(tlv.type), UNKNOWN_FLAG))
8429abe0
RW
577 return (-1);
578 break;
579 }
580 buf += tlv_len;
581 len -= tlv_len;
582 total += tlv_len;
583 }
584
585 return (total);
586}