1 /* $OpenBSD: lsack.c,v 1.9 2021/11/03 21:40:03 sthen Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@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 <netinet/in.h> 22 #include <netinet/ip6.h> 23 #include <arpa/inet.h> 24 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include "ospf6d.h" 29 #include "ospf6.h" 30 #include "log.h" 31 #include "ospfe.h" 32 33 int send_ls_ack(struct iface *, struct in6_addr, struct ibuf *); 34 struct ibuf *prepare_ls_ack(struct iface *); 35 void start_ls_ack_tx_timer_now(struct iface *); 36 37 /* link state acknowledgement packet handling */ 38 struct ibuf * 39 prepare_ls_ack(struct iface *iface) 40 { 41 struct ibuf *buf; 42 43 if ((buf = ibuf_open(iface->mtu - sizeof(struct ip6_hdr))) == NULL) { 44 log_warn("prepare_ls_ack"); 45 return (NULL); 46 } 47 48 /* OSPF header */ 49 if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK)) { 50 log_warn("prepare_ls_ack"); 51 ibuf_free(buf); 52 return (NULL); 53 } 54 55 return (buf); 56 } 57 58 int 59 send_ls_ack(struct iface *iface, struct in6_addr addr, struct ibuf *buf) 60 { 61 /* calculate checksum */ 62 if (upd_ospf_hdr(buf, iface)) { 63 log_warn("send_ls_ack"); 64 return (-1); 65 } 66 67 if (send_packet(iface, buf, &addr) == -1) { 68 log_warn("send_ls_ack"); 69 return (-1); 70 } 71 return (0); 72 } 73 74 int 75 send_direct_ack(struct iface *iface, struct in6_addr addr, void *d, size_t len) 76 { 77 struct ibuf *buf; 78 int ret; 79 80 if ((buf = prepare_ls_ack(iface)) == NULL) 81 return (-1); 82 83 /* LS ack(s) */ 84 if (ibuf_add(buf, d, len)) { 85 log_warn("send_direct_ack"); 86 ibuf_free(buf); 87 return (-1); 88 } 89 90 ret = send_ls_ack(iface, addr, buf); 91 ibuf_free(buf); 92 return (ret); 93 } 94 95 void 96 recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len) 97 { 98 struct lsa_hdr lsa_hdr; 99 100 switch (nbr->state) { 101 case NBR_STA_DOWN: 102 case NBR_STA_ATTEMPT: 103 case NBR_STA_INIT: 104 case NBR_STA_2_WAY: 105 case NBR_STA_XSTRT: 106 case NBR_STA_SNAP: 107 log_debug("recv_ls_ack: packet ignored in state %s, " 108 "neighbor ID %s (%s)", nbr_state_name(nbr->state), 109 inet_ntoa(nbr->id), nbr->iface->name); 110 break; 111 case NBR_STA_XCHNG: 112 case NBR_STA_LOAD: 113 case NBR_STA_FULL: 114 while (len >= sizeof(lsa_hdr)) { 115 memcpy(&lsa_hdr, buf, sizeof(lsa_hdr)); 116 117 if (lsa_hdr_check(nbr, &lsa_hdr)) { 118 /* try both list in case of DROTHER */ 119 if (nbr->iface->state & IF_STA_DROTHER) 120 (void)ls_retrans_list_del( 121 nbr->iface->self, &lsa_hdr); 122 (void)ls_retrans_list_del(nbr, &lsa_hdr); 123 } 124 125 buf += sizeof(lsa_hdr); 126 len -= sizeof(lsa_hdr); 127 } 128 if (len > 0) { 129 log_warnx("recv_ls_ack: bad packet size, " 130 "neighbor ID %s (%s)", inet_ntoa(nbr->id), 131 nbr->iface->name); 132 return; 133 } 134 break; 135 default: 136 fatalx("recv_ls_ack: unknown neighbor state"); 137 } 138 } 139 140 int 141 lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr) 142 { 143 /* invalid age */ 144 if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) { 145 log_debug("lsa_hdr_check: invalid age, neighbor ID %s (%s)", 146 inet_ntoa(nbr->id), nbr->iface->name); 147 return (0); 148 } 149 150 /* invalid type */ 151 switch (ntohs(lsa_hdr->type)) { 152 case LSA_TYPE_LINK: 153 case LSA_TYPE_ROUTER: 154 case LSA_TYPE_NETWORK: 155 case LSA_TYPE_INTER_A_PREFIX: 156 case LSA_TYPE_INTER_A_ROUTER: 157 case LSA_TYPE_INTRA_A_PREFIX: 158 case LSA_TYPE_EXTERNAL: 159 break; 160 default: 161 log_debug("lsa_hdr_check: invalid LSA type %d, " 162 "neighbor ID %s (%s)", 163 lsa_hdr->type, inet_ntoa(nbr->id), nbr->iface->name); 164 return (0); 165 } 166 167 /* invalid sequence number */ 168 if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) { 169 log_debug("ls_hdr_check: invalid seq num, " 170 "neighbor ID %s (%s)", inet_ntoa(nbr->id), 171 nbr->iface->name); 172 return (0); 173 } 174 175 return (1); 176 } 177 178 /* link state ack list */ 179 void 180 ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa) 181 { 182 struct lsa_entry *le; 183 184 if (lsa == NULL) 185 fatalx("ls_ack_list_add: no LSA header"); 186 187 if ((le = calloc(1, sizeof(*le))) == NULL) 188 fatal("ls_ack_list_add"); 189 190 if (ls_ack_list_empty(iface)) 191 start_ls_ack_tx_timer(iface); 192 193 TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry); 194 le->le_lsa = lsa; 195 iface->ls_ack_cnt++; 196 197 /* reschedule now if we have enough for a full packet */ 198 if (iface->ls_ack_cnt > 199 ((iface->mtu - PACKET_HDR) / sizeof(struct lsa_hdr))) { 200 start_ls_ack_tx_timer_now(iface); 201 } 202 } 203 204 void 205 ls_ack_list_free(struct iface *iface, struct lsa_entry *le) 206 { 207 TAILQ_REMOVE(&iface->ls_ack_list, le, entry); 208 free(le->le_lsa); 209 free(le); 210 211 iface->ls_ack_cnt--; 212 } 213 214 void 215 ls_ack_list_clr(struct iface *iface) 216 { 217 struct lsa_entry *le; 218 219 while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) { 220 TAILQ_REMOVE(&iface->ls_ack_list, le, entry); 221 free(le->le_lsa); 222 free(le); 223 } 224 iface->ls_ack_cnt = 0; 225 } 226 227 int 228 ls_ack_list_empty(struct iface *iface) 229 { 230 return (TAILQ_EMPTY(&iface->ls_ack_list)); 231 } 232 233 /* timers */ 234 /* ARGSUSED */ 235 void 236 ls_ack_tx_timer(int fd, short event, void *arg) 237 { 238 struct in6_addr addr; 239 struct iface *iface = arg; 240 struct lsa_entry *le, *nle; 241 struct nbr *nbr; 242 struct ibuf *buf; 243 int cnt; 244 245 while (!ls_ack_list_empty(iface)) { 246 if ((buf = prepare_ls_ack(iface)) == NULL) 247 fatal("ls_ack_tx_timer"); 248 cnt = 0; 249 250 for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL; 251 le = nle) { 252 nle = TAILQ_NEXT(le, entry); 253 if (ibuf_left(buf) < sizeof(struct lsa_hdr)) 254 break; 255 if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr))) 256 break; 257 ls_ack_list_free(iface, le); 258 cnt++; 259 } 260 if (cnt == 0) { 261 log_warnx("ls_ack_tx_timer: lost in space"); 262 ibuf_free(buf); 263 return; 264 } 265 266 /* send LS ack(s) but first set correct destination */ 267 switch (iface->type) { 268 case IF_TYPE_POINTOPOINT: 269 inet_pton(AF_INET6, AllSPFRouters, &addr); 270 send_ls_ack(iface, addr, buf); 271 break; 272 case IF_TYPE_BROADCAST: 273 if (iface->state & IF_STA_DRORBDR) 274 inet_pton(AF_INET6, AllSPFRouters, &addr); 275 else 276 inet_pton(AF_INET6, AllDRouters, &addr); 277 send_ls_ack(iface, addr, buf); 278 break; 279 case IF_TYPE_NBMA: 280 case IF_TYPE_POINTOMULTIPOINT: 281 case IF_TYPE_VIRTUALLINK: 282 LIST_FOREACH(nbr, &iface->nbr_list, entry) { 283 if (nbr == iface->self) 284 continue; 285 if (!(nbr->state & NBR_STA_FLOOD)) 286 continue; 287 send_ls_ack(iface, nbr->addr, buf); 288 } 289 break; 290 default: 291 fatalx("lsa_ack_tx_timer: unknown interface type"); 292 } 293 ibuf_free(buf); 294 } 295 } 296 297 void 298 start_ls_ack_tx_timer(struct iface *iface) 299 { 300 struct timeval tv; 301 302 timerclear(&tv); 303 tv.tv_sec = iface->rxmt_interval / 2; 304 305 if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1) 306 fatal("start_ls_ack_tx_timer"); 307 } 308 309 void 310 start_ls_ack_tx_timer_now(struct iface *iface) 311 { 312 struct timeval tv; 313 314 timerclear(&tv); 315 if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1) 316 fatal("start_ls_ack_tx_timer_now"); 317 } 318 319 void 320 stop_ls_ack_tx_timer(struct iface *iface) 321 { 322 if (evtimer_del(&iface->lsack_tx_timer) == -1) 323 fatal("stop_ls_ack_tx_timer"); 324 } 325