1 /* $OpenBSD: hello.c,v 1.14 2007/10/11 12:19:31 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@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 <sys/socket.h> 22 #include <netinet/in.h> 23 #include <arpa/inet.h> 24 #include <sys/time.h> 25 #include <sys/socket.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <event.h> 29 30 #include "ospfd.h" 31 #include "ospf.h" 32 #include "log.h" 33 #include "ospfe.h" 34 35 extern struct ospfd_conf *oeconf; 36 37 /* hello packet handling */ 38 int 39 send_hello(struct iface *iface) 40 { 41 struct sockaddr_in dst; 42 struct hello_hdr hello; 43 struct nbr *nbr; 44 struct buf *buf; 45 int ret; 46 47 dst.sin_family = AF_INET; 48 dst.sin_len = sizeof(struct sockaddr_in); 49 50 switch (iface->type) { 51 case IF_TYPE_POINTOPOINT: 52 case IF_TYPE_BROADCAST: 53 inet_aton(AllSPFRouters, &dst.sin_addr); 54 break; 55 case IF_TYPE_NBMA: 56 case IF_TYPE_POINTOMULTIPOINT: 57 log_debug("send_hello: type %s not supported, interface %s", 58 if_type_name(iface->type), iface->name); 59 return (-1); 60 case IF_TYPE_VIRTUALLINK: 61 dst.sin_addr = iface->dst; 62 break; 63 default: 64 fatalx("send_hello: unknown interface type"); 65 } 66 67 /* XXX READ_BUF_SIZE */ 68 if ((buf = buf_dynamic(PKG_DEF_SIZE, READ_BUF_SIZE)) == NULL) 69 fatal("send_hello"); 70 71 /* OSPF header */ 72 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_HELLO)) 73 goto fail; 74 75 /* hello header */ 76 hello.mask = iface->mask.s_addr; 77 hello.hello_interval = htons(iface->hello_interval); 78 hello.opts = area_ospf_options(iface->area); 79 hello.rtr_priority = iface->priority; 80 hello.rtr_dead_interval = htonl(iface->dead_interval); 81 82 if (iface->dr) { 83 hello.d_rtr = iface->dr->addr.s_addr; 84 iface->self->dr.s_addr = iface->dr->addr.s_addr; 85 } else 86 hello.d_rtr = 0; 87 if (iface->bdr) { 88 hello.bd_rtr = iface->bdr->addr.s_addr; 89 iface->self->bdr.s_addr = iface->bdr->addr.s_addr; 90 } else 91 hello.bd_rtr = 0; 92 93 if (buf_add(buf, &hello, sizeof(hello))) 94 goto fail; 95 96 /* active neighbor(s) */ 97 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 98 if ((nbr->state >= NBR_STA_INIT) && (nbr != iface->self)) 99 if (buf_add(buf, &nbr->id, sizeof(nbr->id))) 100 goto fail; 101 } 102 103 /* update authentication and calculate checksum */ 104 if (auth_gen(buf, iface)) 105 goto fail; 106 107 ret = send_packet(iface, buf->buf, buf->wpos, &dst); 108 buf_free(buf); 109 return (ret); 110 fail: 111 log_warn("send_hello"); 112 buf_free(buf); 113 return (-1); 114 } 115 116 void 117 recv_hello(struct iface *iface, struct in_addr src, u_int32_t rtr_id, char *buf, 118 u_int16_t len) 119 { 120 struct hello_hdr hello; 121 struct nbr *nbr = NULL, *dr; 122 u_int32_t nbr_id; 123 int nbr_change = 0; 124 125 if (len < sizeof(hello) && (len & 0x03)) { 126 log_warnx("recv_hello: bad packet size, interface %s", 127 iface->name); 128 return; 129 } 130 131 memcpy(&hello, buf, sizeof(hello)); 132 buf += sizeof(hello); 133 len -= sizeof(hello); 134 135 if (iface->type != IF_TYPE_POINTOPOINT && 136 iface->type != IF_TYPE_VIRTUALLINK) 137 if (hello.mask != iface->mask.s_addr) { 138 log_warnx("recv_hello: invalid netmask, interface %s", 139 iface->name); 140 return; 141 } 142 143 if (ntohs(hello.hello_interval) != iface->hello_interval) { 144 log_warnx("recv_hello: invalid hello-interval %d, " 145 "interface %s", ntohs(hello.hello_interval), 146 iface->name); 147 return; 148 } 149 150 if (ntohl(hello.rtr_dead_interval) != iface->dead_interval) { 151 log_warnx("recv_hello: invalid router-dead-interval %d, " 152 "interface %s", ntohl(hello.rtr_dead_interval), 153 iface->name); 154 return; 155 } 156 157 if ((hello.opts & OSPF_OPTION_E && iface->area->stub) || 158 ((hello.opts & OSPF_OPTION_E) == 0 && !iface->area->stub)) { 159 log_warnx("recv_hello: ExternalRoutingCapability mismatch, " 160 "interface %s", iface->name); 161 return; 162 } 163 164 switch (iface->type) { 165 case IF_TYPE_POINTOPOINT: 166 case IF_TYPE_VIRTUALLINK: 167 /* match router-id */ 168 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 169 if (nbr == iface->self) 170 continue; 171 if (nbr->id.s_addr == rtr_id) 172 break; 173 } 174 break; 175 case IF_TYPE_BROADCAST: 176 case IF_TYPE_NBMA: 177 case IF_TYPE_POINTOMULTIPOINT: 178 /* match src IP */ 179 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 180 if (nbr == iface->self) 181 continue; 182 if (nbr->addr.s_addr == src.s_addr) 183 break; 184 } 185 break; 186 default: 187 fatalx("recv_hello: unknown interface type"); 188 } 189 190 if (!nbr) { 191 nbr = nbr_new(rtr_id, iface, 0); 192 /* set neighbor parameters */ 193 nbr->dr.s_addr = hello.d_rtr; 194 nbr->bdr.s_addr = hello.bd_rtr; 195 nbr->priority = hello.rtr_priority; 196 nbr_change = 1; 197 } 198 199 /* actually the neighbor address shouldn't be stored on virtual links */ 200 nbr->addr.s_addr = src.s_addr; 201 nbr->options = hello.opts; 202 203 nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); 204 205 while (len >= sizeof(nbr_id)) { 206 memcpy(&nbr_id, buf, sizeof(nbr_id)); 207 if (nbr_id == ospfe_router_id()) { 208 /* seen myself */ 209 if (nbr->state & NBR_STA_PRELIM) 210 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 211 break; 212 } 213 buf += sizeof(nbr_id); 214 len -= sizeof(nbr_id); 215 } 216 217 if (len == 0) { 218 nbr_fsm(nbr, NBR_EVT_1_WAY_RCVD); 219 /* set neighbor parameters */ 220 nbr->dr.s_addr = hello.d_rtr; 221 nbr->bdr.s_addr = hello.bd_rtr; 222 nbr->priority = hello.rtr_priority; 223 return; 224 } 225 226 if (nbr->priority != hello.rtr_priority) { 227 nbr->priority = hello.rtr_priority; 228 nbr_change = 1; 229 } 230 231 if (iface->state & IF_STA_WAITING && 232 hello.d_rtr == nbr->addr.s_addr && hello.bd_rtr == 0) 233 if_fsm(iface, IF_EVT_BACKUP_SEEN); 234 235 if (iface->state & IF_STA_WAITING && hello.bd_rtr == nbr->addr.s_addr) { 236 /* 237 * In case we see the BDR make sure that the DR is around 238 * with a bidirectional (2_WAY or better) connection 239 */ 240 LIST_FOREACH(dr, &iface->nbr_list, entry) 241 if (hello.d_rtr == dr->addr.s_addr && 242 dr->state & NBR_STA_BIDIR) 243 if_fsm(iface, IF_EVT_BACKUP_SEEN); 244 } 245 246 if ((nbr->addr.s_addr == nbr->dr.s_addr && 247 nbr->addr.s_addr != hello.d_rtr) || 248 (nbr->addr.s_addr != nbr->dr.s_addr && 249 nbr->addr.s_addr == hello.d_rtr)) 250 /* neighbor changed from or to DR */ 251 nbr_change = 1; 252 if ((nbr->addr.s_addr == nbr->bdr.s_addr && 253 nbr->addr.s_addr != hello.bd_rtr) || 254 (nbr->addr.s_addr != nbr->bdr.s_addr && 255 nbr->addr.s_addr == hello.bd_rtr)) 256 /* neighbor changed from or to BDR */ 257 nbr_change = 1; 258 259 nbr->dr.s_addr = hello.d_rtr; 260 nbr->bdr.s_addr = hello.bd_rtr; 261 262 if (nbr_change) 263 if_fsm(iface, IF_EVT_NBR_CHNG); 264 265 /* TODO NBMA needs some special handling */ 266 } 267