1 /* $OpenBSD: hello.c,v 1.25 2015/04/04 15:09:47 renato Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Michele Marchetto <michele@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/uio.h> 22 23 #include <netinet/in.h> 24 #include <netinet/ip.h> 25 #include <arpa/inet.h> 26 #include <net/if_dl.h> 27 28 #include <errno.h> 29 #include <event.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "ldpd.h" 34 #include "ldp.h" 35 #include "log.h" 36 #include "ldpe.h" 37 38 extern struct ldpd_conf *leconf; 39 40 int tlv_decode_hello_prms(char *, u_int16_t, u_int16_t *, u_int16_t *); 41 int tlv_decode_opt_hello_prms(char *, u_int16_t, struct in_addr *, 42 u_int32_t *); 43 int gen_hello_prms_tlv(struct ibuf *buf, u_int16_t, u_int16_t); 44 int gen_opt4_hello_prms_tlv(struct ibuf *, u_int16_t, u_int32_t); 45 46 int 47 send_hello(enum hello_type type, struct iface *iface, struct tnbr *tnbr) 48 { 49 struct sockaddr_in dst; 50 struct ibuf *buf; 51 u_int16_t size, holdtime = 0, flags = 0; 52 int fd = 0; 53 54 dst.sin_port = htons(LDP_PORT); 55 dst.sin_family = AF_INET; 56 dst.sin_len = sizeof(struct sockaddr_in); 57 58 switch (type) { 59 case HELLO_LINK: 60 inet_aton(AllRouters, &dst.sin_addr); 61 holdtime = iface->hello_holdtime; 62 flags = 0; 63 fd = iface->discovery_fd; 64 break; 65 case HELLO_TARGETED: 66 dst.sin_addr.s_addr = tnbr->addr.s_addr; 67 holdtime = tnbr->hello_holdtime; 68 flags = TARGETED_HELLO; 69 if (tnbr->flags & F_TNBR_CONFIGURED) 70 flags |= REQUEST_TARG_HELLO; 71 fd = tnbr->discovery_fd; 72 break; 73 } 74 75 if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) 76 fatal("send_hello"); 77 78 size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + 79 sizeof(struct hello_prms_tlv) + 80 sizeof(struct hello_prms_opt4_tlv); 81 82 gen_ldp_hdr(buf, size); 83 84 size -= LDP_HDR_SIZE; 85 86 gen_msg_tlv(buf, MSG_TYPE_HELLO, size); 87 88 gen_hello_prms_tlv(buf, holdtime, flags); 89 gen_opt4_hello_prms_tlv(buf, TLV_TYPE_IPV4TRANSADDR, ldpe_router_id()); 90 91 send_packet(fd, iface, buf->buf, buf->wpos, &dst); 92 ibuf_free(buf); 93 94 return (0); 95 } 96 97 void 98 recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len) 99 { 100 struct ldp_msg hello; 101 struct ldp_hdr ldp; 102 struct adj *adj; 103 struct nbr *nbr; 104 struct in_addr lsr_id; 105 struct in_addr transport_addr; 106 u_int32_t conf_number; 107 u_int16_t holdtime, flags; 108 int r; 109 struct hello_source source; 110 struct tnbr *tnbr = NULL; 111 112 bcopy(buf, &ldp, sizeof(ldp)); 113 buf += LDP_HDR_SIZE; 114 len -= LDP_HDR_SIZE; 115 116 bcopy(buf, &hello, sizeof(hello)); 117 buf += sizeof(struct ldp_msg); 118 len -= sizeof(struct ldp_msg); 119 120 lsr_id.s_addr = ldp.lsr_id; 121 122 r = tlv_decode_hello_prms(buf, len, &holdtime, &flags); 123 if (r == -1) { 124 log_debug("recv_hello: neighbor %s: failed to decode params", 125 inet_ntoa(lsr_id)); 126 return; 127 } 128 129 bzero(&source, sizeof(source)); 130 if (flags & TARGETED_HELLO) { 131 tnbr = tnbr_find(src); 132 if (!tnbr) { 133 if (!((flags & REQUEST_TARG_HELLO) && 134 leconf->flags & LDPD_FLAG_TH_ACCEPT)) 135 return; 136 137 tnbr = tnbr_new(leconf, src, 0); 138 if (!tnbr) 139 return; 140 tnbr_init(leconf, tnbr); 141 LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); 142 } 143 source.type = HELLO_TARGETED; 144 source.target = tnbr; 145 } else { 146 if (ldp.lspace_id != 0) { 147 log_debug("recv_hello: invalid label space " 148 "ID %u, interface %s", ldp.lspace_id, 149 iface->name); 150 return; 151 } 152 source.type = HELLO_LINK; 153 source.link.iface = iface; 154 source.link.src_addr.s_addr = src.s_addr; 155 } 156 157 buf += r; 158 len -= r; 159 160 r = tlv_decode_opt_hello_prms(buf, len, &transport_addr, 161 &conf_number); 162 if (r == -1) { 163 log_debug("recv_hello: neighbor %s: failed to decode " 164 "optional params", inet_ntoa(lsr_id)); 165 return; 166 } 167 if (transport_addr.s_addr == INADDR_ANY) 168 transport_addr.s_addr = src.s_addr; 169 170 if (r != len) { 171 log_debug("recv_hello: neighbor %s: unexpected data in message", 172 inet_ntoa(lsr_id)); 173 return; 174 } 175 176 nbr = nbr_find_ldpid(ldp.lsr_id); 177 if (!nbr) { 178 /* create new adjacency and new neighbor */ 179 nbr = nbr_new(lsr_id, transport_addr); 180 adj = adj_new(nbr, &source, transport_addr); 181 } else { 182 adj = adj_find(nbr, &source); 183 if (!adj) { 184 /* create new adjacency for existing neighbor */ 185 adj = adj_new(nbr, &source, transport_addr); 186 187 if (nbr->addr.s_addr != transport_addr.s_addr) 188 log_warnx("recv_hello: neighbor %s: multiple " 189 "adjacencies advertising different " 190 "transport addresses", inet_ntoa(lsr_id)); 191 } 192 } 193 194 /* always update the holdtime to properly handle runtime changes */ 195 switch (source.type) { 196 case HELLO_LINK: 197 if (holdtime == 0) 198 holdtime = LINK_DFLT_HOLDTIME; 199 200 adj->holdtime = min(iface->hello_holdtime, holdtime); 201 break; 202 case HELLO_TARGETED: 203 if (holdtime == 0) 204 holdtime = TARGETED_DFLT_HOLDTIME; 205 206 adj->holdtime = min(tnbr->hello_holdtime, holdtime); 207 } 208 209 if (adj->holdtime != INFINITE_HOLDTIME) 210 adj_start_itimer(adj); 211 else 212 adj_stop_itimer(adj); 213 214 if (nbr->state == NBR_STA_PRESENT && nbr_session_active_role(nbr) && 215 !nbr_pending_connect(nbr) && !nbr_pending_idtimer(nbr)) 216 nbr_establish_connection(nbr); 217 } 218 219 int 220 gen_hello_prms_tlv(struct ibuf *buf, u_int16_t holdtime, u_int16_t flags) 221 { 222 struct hello_prms_tlv parms; 223 224 bzero(&parms, sizeof(parms)); 225 parms.type = htons(TLV_TYPE_COMMONHELLO); 226 parms.length = htons(sizeof(parms.holdtime) + sizeof(parms.flags)); 227 parms.holdtime = htons(holdtime); 228 parms.flags = htons(flags); 229 230 return (ibuf_add(buf, &parms, sizeof(parms))); 231 } 232 233 int 234 gen_opt4_hello_prms_tlv(struct ibuf *buf, u_int16_t type, u_int32_t value) 235 { 236 struct hello_prms_opt4_tlv parms; 237 238 bzero(&parms, sizeof(parms)); 239 parms.type = htons(type); 240 parms.length = htons(4); 241 parms.value = value; 242 243 return (ibuf_add(buf, &parms, sizeof(parms))); 244 } 245 246 int 247 tlv_decode_hello_prms(char *buf, u_int16_t len, u_int16_t *holdtime, 248 u_int16_t *flags) 249 { 250 struct hello_prms_tlv tlv; 251 252 if (len < sizeof(tlv)) 253 return (-1); 254 bcopy(buf, &tlv, sizeof(tlv)); 255 256 if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN) 257 return (-1); 258 259 if (tlv.type != htons(TLV_TYPE_COMMONHELLO)) 260 return (-1); 261 262 *holdtime = ntohs(tlv.holdtime); 263 *flags = ntohs(tlv.flags); 264 265 return (sizeof(tlv)); 266 } 267 268 int 269 tlv_decode_opt_hello_prms(char *buf, u_int16_t len, struct in_addr *addr, 270 u_int32_t *conf_number) 271 { 272 struct tlv tlv; 273 int cons = 0; 274 u_int16_t tlv_len; 275 276 bzero(addr, sizeof(*addr)); 277 *conf_number = 0; 278 279 while (len >= sizeof(tlv)) { 280 bcopy(buf, &tlv, sizeof(tlv)); 281 tlv_len = ntohs(tlv.length); 282 switch (ntohs(tlv.type)) { 283 case TLV_TYPE_IPV4TRANSADDR: 284 if (tlv_len != sizeof(u_int32_t)) 285 return (-1); 286 bcopy(buf + TLV_HDR_LEN, addr, sizeof(u_int32_t)); 287 break; 288 case TLV_TYPE_CONFIG: 289 if (tlv_len != sizeof(u_int32_t)) 290 return (-1); 291 bcopy(buf + TLV_HDR_LEN, conf_number, 292 sizeof(u_int32_t)); 293 break; 294 default: 295 /* if unknown flag set, ignore TLV */ 296 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 297 return (-1); 298 break; 299 } 300 buf += TLV_HDR_LEN + tlv_len; 301 len -= TLV_HDR_LEN + tlv_len; 302 cons += TLV_HDR_LEN + tlv_len; 303 } 304 305 return (cons); 306 } 307