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