1 /* $OpenBSD: lsreq.c,v 1.8 2013/03/22 14:26:35 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 <arpa/inet.h> 23 #include <stdlib.h> 24 25 #include "ospf6d.h" 26 #include "ospf6.h" 27 #include "log.h" 28 #include "ospfe.h" 29 30 extern struct imsgev *iev_rde; 31 32 /* link state request packet handling */ 33 int 34 send_ls_req(struct nbr *nbr) 35 { 36 struct in6_addr dst; 37 struct ls_req_hdr ls_req_hdr; 38 struct lsa_entry *le, *nle; 39 struct ibuf *buf; 40 int ret; 41 42 if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL) 43 fatal("send_ls_req"); 44 45 switch (nbr->iface->type) { 46 case IF_TYPE_POINTOPOINT: 47 inet_pton(AF_INET6, AllSPFRouters, &dst); 48 break; 49 case IF_TYPE_BROADCAST: 50 case IF_TYPE_NBMA: 51 case IF_TYPE_POINTOMULTIPOINT: 52 case IF_TYPE_VIRTUALLINK: 53 dst = nbr->addr; 54 break; 55 default: 56 fatalx("send_ls_req: unknown interface type"); 57 } 58 59 /* OSPF header */ 60 if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST)) 61 goto fail; 62 63 /* LSA header(s) */ 64 for (le = TAILQ_FIRST(&nbr->ls_req_list); le != NULL && 65 buf->wpos + sizeof(struct ls_req_hdr) < buf->max; le = nle) { 66 nbr->ls_req = nle = TAILQ_NEXT(le, entry); 67 ls_req_hdr.zero = 0; 68 ls_req_hdr.type = le->le_lsa->type; 69 ls_req_hdr.ls_id = le->le_lsa->ls_id; 70 ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr; 71 if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr))) 72 goto fail; 73 } 74 75 /* calculate checksum */ 76 if (upd_ospf_hdr(buf, nbr->iface)) 77 goto fail; 78 79 ret = send_packet(nbr->iface, buf->buf, buf->wpos, &dst); 80 81 ibuf_free(buf); 82 return (ret); 83 fail: 84 log_warn("send_ls_req"); 85 ibuf_free(buf); 86 return (-1); 87 } 88 89 void 90 recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len) 91 { 92 switch (nbr->state) { 93 case NBR_STA_DOWN: 94 case NBR_STA_ATTEMPT: 95 case NBR_STA_INIT: 96 case NBR_STA_2_WAY: 97 case NBR_STA_XSTRT: 98 case NBR_STA_SNAP: 99 log_debug("recv_ls_req: packet ignored in state %s, " 100 "neighbor ID %s", nbr_state_name(nbr->state), 101 inet_ntoa(nbr->id)); 102 break; 103 case NBR_STA_XCHNG: 104 case NBR_STA_LOAD: 105 case NBR_STA_FULL: 106 imsg_compose_event(iev_rde, IMSG_LS_REQ, nbr->peerid, 107 0, -1, buf, len); 108 break; 109 default: 110 fatalx("recv_ls_req: unknown neighbor state"); 111 } 112 } 113 114 /* link state request list */ 115 void 116 ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa) 117 { 118 struct lsa_entry *le; 119 120 if (lsa == NULL) 121 fatalx("ls_req_list_add: no LSA header"); 122 123 if ((le = calloc(1, sizeof(*le))) == NULL) 124 fatal("ls_req_list_add"); 125 126 TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry); 127 le->le_lsa = lsa; 128 nbr->ls_req_cnt++; 129 } 130 131 struct lsa_entry * 132 ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr) 133 { 134 struct lsa_entry *le; 135 136 TAILQ_FOREACH(le, &nbr->ls_req_list, entry) { 137 if ((lsa_hdr->type == le->le_lsa->type) && 138 (lsa_hdr->ls_id == le->le_lsa->ls_id) && 139 (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr)) 140 return (le); 141 } 142 return (NULL); 143 } 144 145 void 146 ls_req_list_free(struct nbr *nbr, struct lsa_entry *le) 147 { 148 if (nbr->ls_req == le) { 149 nbr->ls_req = TAILQ_NEXT(le, entry); 150 } 151 152 TAILQ_REMOVE(&nbr->ls_req_list, le, entry); 153 free(le->le_lsa); 154 free(le); 155 nbr->ls_req_cnt--; 156 157 /* received all requested LSA(s), send a new LS req */ 158 if (nbr->ls_req != NULL && 159 nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) { 160 start_ls_req_tx_timer(nbr); 161 } 162 163 /* we might not have received all DDs and are still in XCHNG */ 164 if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 && 165 nbr->state != NBR_STA_XCHNG) 166 nbr_fsm(nbr, NBR_EVT_LOAD_DONE); 167 } 168 169 void 170 ls_req_list_clr(struct nbr *nbr) 171 { 172 struct lsa_entry *le; 173 174 while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) { 175 TAILQ_REMOVE(&nbr->ls_req_list, le, entry); 176 free(le->le_lsa); 177 free(le); 178 } 179 180 nbr->ls_req_cnt = 0; 181 nbr->ls_req = NULL; 182 } 183 184 int 185 ls_req_list_empty(struct nbr *nbr) 186 { 187 return (TAILQ_EMPTY(&nbr->ls_req_list)); 188 } 189 190 /* timers */ 191 /* ARGSUSED */ 192 void 193 ls_req_tx_timer(int fd, short event, void *arg) 194 { 195 struct nbr *nbr = arg; 196 struct timeval tv; 197 198 switch (nbr->state) { 199 case NBR_STA_DOWN: 200 case NBR_STA_ATTEMPT: 201 case NBR_STA_INIT: 202 case NBR_STA_2_WAY: 203 case NBR_STA_SNAP: 204 case NBR_STA_XSTRT: 205 case NBR_STA_XCHNG: 206 return; 207 case NBR_STA_LOAD: 208 send_ls_req(nbr); 209 break; 210 case NBR_STA_FULL: 211 return; 212 default: 213 log_debug("ls_req_tx_timer: unknown neighbor state, " 214 "neighbor ID %s", inet_ntoa(nbr->id)); 215 break; 216 } 217 218 /* reschedule lsreq_tx_timer */ 219 if (nbr->state == NBR_STA_LOAD) { 220 timerclear(&tv); 221 tv.tv_sec = nbr->iface->rxmt_interval; 222 if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1) 223 fatal("ls_req_tx_timer"); 224 } 225 } 226 227 void 228 start_ls_req_tx_timer(struct nbr *nbr) 229 { 230 struct timeval tv; 231 232 if (nbr == nbr->iface->self) 233 return; 234 235 timerclear(&tv); 236 if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1) 237 fatal("start_ls_req_tx_timer"); 238 } 239 240 void 241 stop_ls_req_tx_timer(struct nbr *nbr) 242 { 243 if (nbr == nbr->iface->self) 244 return; 245 246 if (evtimer_del(&nbr->lsreq_tx_timer) == -1) 247 fatal("stop_ls_req_tx_timer"); 248 } 249