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