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