1 /* $OpenBSD: hello.c,v 1.18 2018/02/22 07:43:29 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 <stdlib.h> 26 #include <string.h> 27 #include <event.h> 28 29 #include "ospf6d.h" 30 #include "ospf6.h" 31 #include "log.h" 32 #include "ospfe.h" 33 34 extern struct ospfd_conf *oeconf; 35 36 /* hello packet handling */ 37 int 38 send_hello(struct iface *iface) 39 { 40 struct in6_addr dst; 41 struct hello_hdr hello; 42 struct nbr *nbr; 43 struct ibuf *buf; 44 int ret; 45 u_int32_t opts; 46 47 switch (iface->type) { 48 case IF_TYPE_POINTOPOINT: 49 case IF_TYPE_BROADCAST: 50 inet_pton(AF_INET6, AllSPFRouters, &dst); 51 break; 52 case IF_TYPE_NBMA: 53 case IF_TYPE_POINTOMULTIPOINT: 54 log_debug("send_hello: type %s not supported, interface %s", 55 if_type_name(iface->type), iface->name); 56 return (-1); 57 case IF_TYPE_VIRTUALLINK: 58 dst = iface->dst; 59 break; 60 default: 61 fatalx("send_hello: unknown interface type"); 62 } 63 64 /* XXX IBUF_READ_SIZE */ 65 if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_SIZE)) == NULL) 66 fatal("send_hello"); 67 68 /* OSPF header */ 69 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_HELLO)) 70 goto fail; 71 72 /* hello header */ 73 hello.iface_id = htonl(iface->ifindex); 74 LSA_24_SETHI(hello.opts, iface->priority); 75 opts = area_ospf_options(area_find(oeconf, iface->area_id)); 76 LSA_24_SETLO(hello.opts, opts); 77 hello.opts = htonl(hello.opts); 78 79 hello.hello_interval = htons(iface->hello_interval); 80 hello.rtr_dead_interval = htons(iface->dead_interval); 81 82 if (iface->dr) { 83 hello.d_rtr = iface->dr->id.s_addr; 84 iface->self->dr.s_addr = iface->dr->id.s_addr; 85 } else 86 hello.d_rtr = 0; 87 if (iface->bdr) { 88 hello.bd_rtr = iface->bdr->id.s_addr; 89 iface->self->bdr.s_addr = iface->bdr->id.s_addr; 90 } else 91 hello.bd_rtr = 0; 92 93 if (ibuf_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 (ibuf_add(buf, &nbr->id, sizeof(nbr->id))) 100 goto fail; 101 } 102 103 /* calculate checksum */ 104 if (upd_ospf_hdr(buf, iface)) 105 goto fail; 106 107 ret = send_packet(iface, buf->buf, buf->wpos, &dst); 108 109 ibuf_free(buf); 110 return (ret); 111 fail: 112 log_warn("send_hello"); 113 ibuf_free(buf); 114 return (-1); 115 } 116 117 void 118 recv_hello(struct iface *iface, struct in6_addr *src, u_int32_t rtr_id, 119 char *buf, u_int16_t len) 120 { 121 struct hello_hdr hello; 122 struct nbr *nbr = NULL, *dr; 123 struct area *area; 124 u_int32_t nbr_id, opts; 125 int nbr_change = 0; 126 127 if (len < sizeof(hello) || (len & 0x03)) { 128 log_warnx("recv_hello: bad packet size, interface %s", 129 iface->name); 130 return; 131 } 132 133 memcpy(&hello, buf, sizeof(hello)); 134 buf += sizeof(hello); 135 len -= sizeof(hello); 136 137 if (ntohs(hello.hello_interval) != iface->hello_interval) { 138 log_warnx("recv_hello: invalid hello-interval %d, " 139 "interface %s", ntohs(hello.hello_interval), 140 iface->name); 141 return; 142 } 143 144 if (ntohs(hello.rtr_dead_interval) != iface->dead_interval) { 145 log_warnx("recv_hello: invalid router-dead-interval %d, " 146 "interface %s", ntohl(hello.rtr_dead_interval), 147 iface->name); 148 return; 149 } 150 151 if ((area = area_find(oeconf, iface->area_id)) == NULL) 152 fatalx("interface lost area"); 153 154 opts = LSA_24_GETLO(ntohl(hello.opts)); 155 if ((opts & OSPF_OPTION_E && area->stub) || 156 ((opts & OSPF_OPTION_E) == 0 && !area->stub)) { 157 log_warnx("recv_hello: ExternalRoutingCapability mismatch, " 158 "interface %s", iface->name); 159 return; 160 } 161 162 /* match router-id */ 163 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 164 if (nbr == iface->self) 165 continue; 166 if (nbr->id.s_addr == rtr_id) 167 break; 168 } 169 170 if (!nbr) { 171 nbr = nbr_new(rtr_id, iface, ntohl(hello.iface_id), 0, src); 172 /* set neighbor parameters */ 173 nbr->dr.s_addr = hello.d_rtr; 174 nbr->bdr.s_addr = hello.bd_rtr; 175 nbr->priority = LSA_24_GETHI(ntohl(hello.opts)); 176 } 177 178 /* actually the neighbor address shouldn't be stored on virtual links */ 179 nbr->addr = *src; 180 nbr->options = opts; 181 182 nbr_fsm(nbr, NBR_EVT_HELLO_RCVD); 183 184 while (len >= sizeof(nbr_id)) { 185 memcpy(&nbr_id, buf, sizeof(nbr_id)); 186 if (nbr_id == ospfe_router_id()) { 187 /* seen myself */ 188 if (nbr->state & NBR_STA_PRELIM) { 189 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 190 nbr_change = 1; 191 } 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