1 /* $OpenBSD: hello.c,v 1.9 2007/12/13 08:54:05 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 "ospf6d.h" 31 #include "ospf6.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 in6_addr dst; 42 struct hello_hdr hello; 43 struct nbr *nbr; 44 struct buf *buf; 45 int ret; 46 u_int32_t opts; 47 48 switch (iface->type) { 49 case IF_TYPE_POINTOPOINT: 50 case IF_TYPE_BROADCAST: 51 inet_pton(AF_INET6, AllSPFRouters, &dst); 52 break; 53 case IF_TYPE_NBMA: 54 case IF_TYPE_POINTOMULTIPOINT: 55 log_debug("send_hello: type %s not supported, interface %s", 56 if_type_name(iface->type), iface->name); 57 return (-1); 58 case IF_TYPE_VIRTUALLINK: 59 dst = iface->dst; 60 break; 61 default: 62 fatalx("send_hello: unknown interface type"); 63 } 64 65 /* XXX READ_BUF_SIZE */ 66 if ((buf = buf_dynamic(PKG_DEF_SIZE, READ_BUF_SIZE)) == NULL) 67 fatal("send_hello"); 68 69 /* OSPF header */ 70 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_HELLO)) 71 goto fail; 72 73 /* hello header */ 74 hello.iface_id = iface->ifindex; 75 hello.rtr_priority = iface->priority; 76 77 opts = ntohl(area_ospf_options(area_find(oeconf, iface->area_id))); 78 hello.opts1 = (opts >> 16) & 0xff; 79 hello.opts2 = (opts >> 8) & 0xff; 80 hello.opts3 = opts & 0xff; 81 82 hello.hello_interval = htons(iface->hello_interval); 83 hello.rtr_dead_interval = htons(iface->dead_interval); 84 85 if (iface->dr) { 86 hello.d_rtr = iface->dr->id.s_addr; 87 iface->self->dr.s_addr = iface->dr->id.s_addr; 88 } else 89 hello.d_rtr = 0; 90 if (iface->bdr) { 91 hello.bd_rtr = iface->bdr->id.s_addr; 92 iface->self->bdr.s_addr = iface->bdr->id.s_addr; 93 } else 94 hello.bd_rtr = 0; 95 96 if (buf_add(buf, &hello, sizeof(hello))) 97 goto fail; 98 99 /* active neighbor(s) */ 100 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 101 if ((nbr->state >= NBR_STA_INIT) && (nbr != iface->self)) 102 if (buf_add(buf, &nbr->id, sizeof(nbr->id))) 103 goto fail; 104 } 105 106 /* calculate checksum */ 107 if (upd_ospf_hdr(buf, iface)) 108 goto fail; 109 110 ret = send_packet(iface, buf->buf, buf->wpos, &dst); 111 112 buf_free(buf); 113 return (ret); 114 fail: 115 log_warn("send_hello"); 116 buf_free(buf); 117 return (-1); 118 } 119 120 void 121 recv_hello(struct iface *iface, struct in6_addr *src, u_int32_t rtr_id, 122 char *buf, u_int16_t len) 123 { 124 struct hello_hdr hello; 125 struct nbr *nbr = NULL, *dr; 126 struct area *area; 127 u_int32_t nbr_id; 128 int nbr_change = 0; 129 130 if (len < sizeof(hello) && (len & 0x03)) { 131 log_warnx("recv_hello: bad packet size, interface %s", 132 iface->name); 133 return; 134 } 135 136 memcpy(&hello, buf, sizeof(hello)); 137 buf += sizeof(hello); 138 len -= sizeof(hello); 139 140 if (ntohs(hello.hello_interval) != iface->hello_interval) { 141 log_warnx("recv_hello: invalid hello-interval %d, " 142 "interface %s", ntohs(hello.hello_interval), 143 iface->name); 144 return; 145 } 146 147 if (ntohs(hello.rtr_dead_interval) != iface->dead_interval) { 148 log_warnx("recv_hello: invalid router-dead-interval %d, " 149 "interface %s", ntohl(hello.rtr_dead_interval), 150 iface->name); 151 return; 152 } 153 154 if ((area = area_find(oeconf, iface->area_id)) == NULL) 155 fatalx("interface lost area"); 156 157 if ((hello.opts3 & OSPF_OPTION_E && area->stub) || /* XXX */ 158 ((hello.opts3 & OSPF_OPTION_E) == 0 && !area->stub)) { /* XXX */ 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 (IN6_ARE_ADDR_EQUAL(&nbr->addr, src)) 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 = *src; 201 nbr->options = (hello.opts1 << 16) | (hello.opts2 << 8) | hello.opts3; 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->id.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->id.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->id.s_addr && 242 dr->state & NBR_STA_BIDIR) 243 if_fsm(iface, IF_EVT_BACKUP_SEEN); 244 } 245 246 if ((nbr->id.s_addr == nbr->dr.s_addr && 247 nbr->id.s_addr != hello.d_rtr) || 248 (nbr->id.s_addr != nbr->dr.s_addr && 249 nbr->id.s_addr == hello.d_rtr)) 250 /* neighbor changed from or to DR */ 251 nbr_change = 1; 252 if ((nbr->id.s_addr == nbr->bdr.s_addr && 253 nbr->id.s_addr != hello.bd_rtr) || 254 (nbr->id.s_addr != nbr->bdr.s_addr && 255 nbr->id.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