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