1 /* $OpenBSD: hello.c,v 1.16 2010/05/26 13:56:08 nicm 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 ibuf *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 IBUF_READ_SIZE */ 66 if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_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 = htonl(iface->ifindex); 75 LSA_24_SETHI(hello.opts, iface->priority); 76 opts = area_ospf_options(area_find(oeconf, iface->area_id)); 77 LSA_24_SETLO(hello.opts, opts); 78 hello.opts = htonl(hello.opts); 79 80 hello.hello_interval = htons(iface->hello_interval); 81 hello.rtr_dead_interval = htons(iface->dead_interval); 82 83 if (iface->dr) { 84 hello.d_rtr = iface->dr->id.s_addr; 85 iface->self->dr.s_addr = iface->dr->id.s_addr; 86 } else 87 hello.d_rtr = 0; 88 if (iface->bdr) { 89 hello.bd_rtr = iface->bdr->id.s_addr; 90 iface->self->bdr.s_addr = iface->bdr->id.s_addr; 91 } else 92 hello.bd_rtr = 0; 93 94 if (ibuf_add(buf, &hello, sizeof(hello))) 95 goto fail; 96 97 /* active neighbor(s) */ 98 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 99 if ((nbr->state >= NBR_STA_INIT) && (nbr != iface->self)) 100 if (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 101 goto fail; 102 } 103 104 /* calculate checksum */ 105 if (upd_ospf_hdr(buf, iface)) 106 goto fail; 107 108 ret = send_packet(iface, buf->buf, buf->wpos, &dst); 109 110 ibuf_free(buf); 111 return (ret); 112 fail: 113 log_warn("send_hello"); 114 ibuf_free(buf); 115 return (-1); 116 } 117 118 void 119 recv_hello(struct iface *iface, struct in6_addr *src, u_int32_t rtr_id, 120 char *buf, u_int16_t len) 121 { 122 struct hello_hdr hello; 123 struct nbr *nbr = NULL, *dr; 124 struct area *area; 125 u_int32_t nbr_id, opts; 126 int nbr_change = 0; 127 128 if (len < sizeof(hello) || (len & 0x03)) { 129 log_warnx("recv_hello: bad packet size, interface %s", 130 iface->name); 131 return; 132 } 133 134 memcpy(&hello, buf, sizeof(hello)); 135 buf += sizeof(hello); 136 len -= sizeof(hello); 137 138 if (ntohs(hello.hello_interval) != iface->hello_interval) { 139 log_warnx("recv_hello: invalid hello-interval %d, " 140 "interface %s", ntohs(hello.hello_interval), 141 iface->name); 142 return; 143 } 144 145 if (ntohs(hello.rtr_dead_interval) != iface->dead_interval) { 146 log_warnx("recv_hello: invalid router-dead-interval %d, " 147 "interface %s", ntohl(hello.rtr_dead_interval), 148 iface->name); 149 return; 150 } 151 152 if ((area = area_find(oeconf, iface->area_id)) == NULL) 153 fatalx("interface lost area"); 154 155 opts = LSA_24_GETLO(ntohl(hello.opts)); 156 if ((opts & OSPF_OPTION_E && area->stub) || 157 ((opts & OSPF_OPTION_E) == 0 && !area->stub)) { 158 log_warnx("recv_hello: ExternalRoutingCapability mismatch, " 159 "interface %s", iface->name); 160 return; 161 } 162 163 /* match router-id */ 164 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 165 if (nbr == iface->self) 166 continue; 167 if (nbr->id.s_addr == rtr_id) 168 break; 169 } 170 171 if (!nbr) { 172 nbr = nbr_new(rtr_id, iface, ntohl(hello.iface_id), 0, src); 173 /* set neighbor parameters */ 174 nbr->dr.s_addr = hello.d_rtr; 175 nbr->bdr.s_addr = hello.bd_rtr; 176 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 177 nbr_change = 1; 178 } 179 180 /* actually the neighbor address shouldn't be stored on virtual links */ 181 nbr->addr = *src; 182 nbr->options = opts; 183 184 nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); 185 186 while (len >= sizeof(nbr_id)) { 187 memcpy(&nbr_id, buf, sizeof(nbr_id)); 188 if (nbr_id == ospfe_router_id()) { 189 /* seen myself */ 190 if (nbr->state & NBR_STA_PRELIM) 191 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 192 break; 193 } 194 buf += sizeof(nbr_id); 195 len -= sizeof(nbr_id); 196 } 197 198 if (len == 0) { 199 nbr_fsm(nbr, NBR_EVT_1_WAY_RCVD); 200 /* set neighbor parameters */ 201 nbr->dr.s_addr = hello.d_rtr; 202 nbr->bdr.s_addr = hello.bd_rtr; 203 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 204 return; 205 } 206 207 if (nbr->priority != LSA_24_GETHI(ntohl(hello.opts))) { 208 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 209 nbr_change = 1; 210 } 211 212 if (iface->state & IF_STA_WAITING && 213 hello.d_rtr == nbr->id.s_addr && hello.bd_rtr == 0) 214 if_fsm(iface, IF_EVT_BACKUP_SEEN); 215 216 if (iface->state & IF_STA_WAITING && hello.bd_rtr == nbr->id.s_addr) { 217 /* 218 * In case we see the BDR make sure that the DR is around 219 * with a bidirectional (2_WAY or better) connection 220 */ 221 LIST_FOREACH(dr, &iface->nbr_list, entry) 222 if (hello.d_rtr == dr->id.s_addr && 223 dr->state & NBR_STA_BIDIR) 224 if_fsm(iface, IF_EVT_BACKUP_SEEN); 225 } 226 227 if ((nbr->id.s_addr == nbr->dr.s_addr && 228 nbr->id.s_addr != hello.d_rtr) || 229 (nbr->id.s_addr != nbr->dr.s_addr && 230 nbr->id.s_addr == hello.d_rtr)) 231 /* neighbor changed from or to DR */ 232 nbr_change = 1; 233 if ((nbr->id.s_addr == nbr->bdr.s_addr && 234 nbr->id.s_addr != hello.bd_rtr) || 235 (nbr->id.s_addr != nbr->bdr.s_addr && 236 nbr->id.s_addr == hello.bd_rtr)) 237 /* neighbor changed from or to BDR */ 238 nbr_change = 1; 239 240 nbr->dr.s_addr = hello.d_rtr; 241 nbr->bdr.s_addr = hello.bd_rtr; 242 243 if (nbr_change) 244 if_fsm(iface, IF_EVT_NBR_CHNG); 245 246 /* TODO NBMA needs some special handling */ 247 } 248