| 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.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 | |||||
| 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, buf->buf, buf->wpos); | ||||
| 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 | } |