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