1 /* $OpenBSD: hello.c,v 1.12 2011/03/12 01:57:13 claudio 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 int tlv_decode_hello_prms(char *, u_int16_t, u_int16_t *, u_int16_t *); 40 int tlv_decode_opt_hello_prms(char *, u_int16_t, struct in_addr *, 41 u_int32_t *); 42 int gen_hello_prms_tlv(struct iface *, struct ibuf *, u_int16_t); 43 44 int 45 send_hello(struct iface *iface) 46 { 47 struct sockaddr_in dst; 48 struct ibuf *buf; 49 u_int16_t size; 50 51 dst.sin_port = htons(LDP_PORT); 52 dst.sin_family = AF_INET; 53 dst.sin_len = sizeof(struct sockaddr_in); 54 inet_aton(AllRouters, &dst.sin_addr); 55 56 if (iface->passive) 57 return (0); 58 59 if ((buf = ibuf_open(LDP_MAX_LEN)) == NULL) 60 fatal("send_hello"); 61 62 size = LDP_HDR_SIZE + sizeof(struct ldp_msg) + 63 sizeof(struct hello_prms_tlv); 64 65 gen_ldp_hdr(buf, iface, size); 66 67 size -= LDP_HDR_SIZE; 68 69 gen_msg_tlv(buf, MSG_TYPE_HELLO, size); 70 71 size -= sizeof(struct ldp_msg); 72 73 gen_hello_prms_tlv(iface, buf, size); 74 75 send_packet(iface, buf->buf, buf->wpos, &dst); 76 ibuf_free(buf); 77 78 return (0); 79 } 80 81 void 82 recv_hello(struct iface *iface, struct in_addr src, char *buf, u_int16_t len) 83 { 84 struct ldp_msg hello; 85 struct ldp_hdr ldp; 86 struct nbr *nbr = NULL; 87 struct in_addr address; 88 u_int32_t conf_number; 89 u_int16_t holdtime, flags; 90 int r; 91 92 bcopy(buf, &ldp, sizeof(ldp)); 93 buf += LDP_HDR_SIZE; 94 len -= LDP_HDR_SIZE; 95 96 bcopy(buf, &hello, sizeof(hello)); 97 buf += sizeof(struct ldp_msg); 98 len -= sizeof(struct ldp_msg); 99 100 r = tlv_decode_hello_prms(buf, len, &holdtime, &flags); 101 if (r == -1) { 102 address.s_addr = ldp.lsr_id; 103 log_debug("recv_hello: neighbor %s: failed to decode params", 104 inet_ntoa(address)); 105 return; 106 } 107 108 buf += r; 109 len -= r; 110 111 r = tlv_decode_opt_hello_prms(buf, len, &address, &conf_number); 112 if (r == -1) { 113 address.s_addr = ldp.lsr_id; 114 log_debug("recv_hello: neighbor %s: failed to decode " 115 "optional params", inet_ntoa(address)); 116 return; 117 } 118 if (r != len) { 119 address.s_addr = ldp.lsr_id; 120 log_debug("recv_hello: neighbor %s: unexpected data in message", 121 inet_ntoa(address)); 122 return; 123 } 124 125 nbr = nbr_find_ldpid(ldp.lsr_id, ldp.lspace_id); 126 if (!nbr) { 127 struct in_addr a; 128 129 if (address.s_addr == INADDR_ANY) 130 a = src; 131 else 132 a = address; 133 134 nbr = nbr_new(ldp.lsr_id, ldp.lspace_id, iface, a); 135 136 /* set neighbor parameters */ 137 nbr->hello_type = flags; 138 139 if (holdtime == 0) { 140 /* XXX: lacks support for targeted hellos */ 141 if (iface->holdtime < LINK_DFLT_HOLDTIME) 142 nbr->holdtime = iface->holdtime; 143 else 144 nbr->holdtime = LINK_DFLT_HOLDTIME; 145 } else if (holdtime == INFINITE_HOLDTIME) { 146 /* No timeout for this neighbor */ 147 nbr->holdtime = iface->holdtime; 148 } else { 149 if (iface->holdtime < holdtime) 150 nbr->holdtime = iface->holdtime; 151 else 152 nbr->holdtime = holdtime; 153 } 154 } 155 156 nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); 157 158 if (ntohl(nbr->addr.s_addr) < ntohl(nbr->iface->addr.s_addr) && 159 nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr)) 160 nbr_act_session_establish(nbr, 1); 161 } 162 163 int 164 gen_hello_prms_tlv(struct iface *iface, struct ibuf *buf, u_int16_t size) 165 { 166 struct hello_prms_tlv parms; 167 168 /* We want just the size of the value */ 169 size -= TLV_HDR_LEN; 170 171 bzero(&parms, sizeof(parms)); 172 parms.type = htons(TLV_TYPE_COMMONHELLO); 173 parms.length = htons(size); 174 /* XXX */ 175 parms.holdtime = htons(iface->holdtime); 176 parms.flags = 0; 177 178 return (ibuf_add(buf, &parms, sizeof(parms))); 179 } 180 181 int 182 tlv_decode_hello_prms(char *buf, u_int16_t len, u_int16_t *holdtime, 183 u_int16_t *flags) 184 { 185 struct hello_prms_tlv tlv; 186 187 if (len < sizeof(tlv)) 188 return (-1); 189 bcopy(buf, &tlv, sizeof(tlv)); 190 191 if (ntohs(tlv.length) != sizeof(tlv) - TLV_HDR_LEN) 192 return (-1); 193 194 if (tlv.type != htons(TLV_TYPE_COMMONHELLO)) 195 return (-1); 196 197 *holdtime = ntohs(tlv.holdtime); 198 *flags = ntohs(tlv.flags); 199 200 return (sizeof(tlv)); 201 } 202 203 int 204 tlv_decode_opt_hello_prms(char *buf, u_int16_t len, struct in_addr *addr, 205 u_int32_t *conf_number) 206 { 207 struct tlv tlv; 208 int cons = 0; 209 u_int16_t tlv_len; 210 211 bzero(addr, sizeof(*addr)); 212 *conf_number = 0; 213 214 while (len >= sizeof(tlv)) { 215 bcopy(buf, &tlv, sizeof(tlv)); 216 tlv_len = ntohs(tlv.length); 217 switch (ntohs(tlv.type)) { 218 case TLV_TYPE_IPV4TRANSADDR: 219 if (tlv_len != sizeof(u_int32_t)) 220 return (-1); 221 bcopy(buf + TLV_HDR_LEN, addr, sizeof(u_int32_t)); 222 break; 223 case TLV_TYPE_CONFIG: 224 if (tlv_len != sizeof(u_int32_t)) 225 return (-1); 226 bcopy(buf + TLV_HDR_LEN, conf_number, 227 sizeof(u_int32_t)); 228 break; 229 default: 230 /* if unknown flag set, ignore TLV */ 231 if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) 232 return (-1); 233 break; 234 } 235 buf += TLV_HDR_LEN + tlv_len; 236 len -= TLV_HDR_LEN + tlv_len; 237 cons += TLV_HDR_LEN + tlv_len; 238 } 239 240 return (cons); 241 } 242