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