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