1*4f4fe40bSflorian /* $OpenBSD: lsreq.c,v 1.25 2024/08/21 15:18:00 florian Exp $ */ 2204df0f8Sclaudio 3204df0f8Sclaudio /* 4367f601bSnorby * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 5204df0f8Sclaudio * 6204df0f8Sclaudio * Permission to use, copy, modify, and distribute this software for any 7204df0f8Sclaudio * purpose with or without fee is hereby granted, provided that the above 8204df0f8Sclaudio * copyright notice and this permission notice appear in all copies. 9204df0f8Sclaudio * 10204df0f8Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11204df0f8Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12204df0f8Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13204df0f8Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14204df0f8Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15204df0f8Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16204df0f8Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17204df0f8Sclaudio */ 18204df0f8Sclaudio 19204df0f8Sclaudio #include <sys/types.h> 20204df0f8Sclaudio #include <sys/socket.h> 21204df0f8Sclaudio #include <netinet/in.h> 22204df0f8Sclaudio #include <arpa/inet.h> 23204df0f8Sclaudio #include <stdlib.h> 24204df0f8Sclaudio 25204df0f8Sclaudio #include "ospfd.h" 26204df0f8Sclaudio #include "ospf.h" 27204df0f8Sclaudio #include "log.h" 28204df0f8Sclaudio #include "ospfe.h" 29204df0f8Sclaudio 30204df0f8Sclaudio /* link state request packet handling */ 31204df0f8Sclaudio int 32204df0f8Sclaudio send_ls_req(struct nbr *nbr) 33204df0f8Sclaudio { 34204df0f8Sclaudio struct sockaddr_in dst; 350491ce75Sclaudio struct ls_req_hdr ls_req_hdr; 36204df0f8Sclaudio struct lsa_entry *le, *nle; 37e39620e5Snicm struct ibuf *buf; 38204df0f8Sclaudio 39e39620e5Snicm if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL) 40204df0f8Sclaudio fatal("send_ls_req"); 41204df0f8Sclaudio 42204df0f8Sclaudio /* set destination */ 43204df0f8Sclaudio dst.sin_family = AF_INET; 44204df0f8Sclaudio dst.sin_len = sizeof(struct sockaddr_in); 45204df0f8Sclaudio 46204df0f8Sclaudio switch (nbr->iface->type) { 47204df0f8Sclaudio case IF_TYPE_POINTOPOINT: 48*4f4fe40bSflorian inet_pton(AF_INET, AllSPFRouters, &dst.sin_addr); 49204df0f8Sclaudio break; 50204df0f8Sclaudio case IF_TYPE_BROADCAST: 51204df0f8Sclaudio case IF_TYPE_NBMA: 52204df0f8Sclaudio case IF_TYPE_POINTOMULTIPOINT: 53204df0f8Sclaudio case IF_TYPE_VIRTUALLINK: 54204df0f8Sclaudio dst.sin_addr.s_addr = nbr->addr.s_addr; 55204df0f8Sclaudio break; 56204df0f8Sclaudio default: 57204df0f8Sclaudio fatalx("send_ls_req: unknown interface type"); 58204df0f8Sclaudio } 59204df0f8Sclaudio 60204df0f8Sclaudio /* OSPF header */ 610491ce75Sclaudio if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST)) 620491ce75Sclaudio goto fail; 63204df0f8Sclaudio 640491ce75Sclaudio /* LSA header(s), keep space for a possible md5 sum */ 65204df0f8Sclaudio for (le = TAILQ_FIRST(&nbr->ls_req_list); le != NULL && 66e39620e5Snicm ibuf_left(buf) >= sizeof(struct ls_req_hdr) + MD5_DIGEST_LENGTH; 679627de93Sclaudio le = nle) { 68204df0f8Sclaudio nbr->ls_req = nle = TAILQ_NEXT(le, entry); 690491ce75Sclaudio ls_req_hdr.type = htonl(le->le_lsa->type); 700491ce75Sclaudio ls_req_hdr.ls_id = le->le_lsa->ls_id; 710491ce75Sclaudio ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr; 72e39620e5Snicm if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr))) 730491ce75Sclaudio goto fail; 74204df0f8Sclaudio } 75204df0f8Sclaudio 76204df0f8Sclaudio /* update authentication and calculate checksum */ 770491ce75Sclaudio if (auth_gen(buf, nbr->iface)) 780491ce75Sclaudio goto fail; 79204df0f8Sclaudio 8025a742ccSremi if (send_packet(nbr->iface, buf, &dst) == -1) 8125a742ccSremi goto fail; 820491ce75Sclaudio 83e39620e5Snicm ibuf_free(buf); 8425a742ccSremi return (0); 850491ce75Sclaudio fail: 8625a742ccSremi log_warn("%s", __func__); 87e39620e5Snicm ibuf_free(buf); 880491ce75Sclaudio return (-1); 89204df0f8Sclaudio } 90204df0f8Sclaudio 91204df0f8Sclaudio void 92204df0f8Sclaudio recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len) 93204df0f8Sclaudio { 94204df0f8Sclaudio switch (nbr->state) { 95204df0f8Sclaudio case NBR_STA_DOWN: 96204df0f8Sclaudio case NBR_STA_ATTEMPT: 97204df0f8Sclaudio case NBR_STA_INIT: 98204df0f8Sclaudio case NBR_STA_2_WAY: 99204df0f8Sclaudio case NBR_STA_XSTRT: 100204df0f8Sclaudio case NBR_STA_SNAP: 101204df0f8Sclaudio log_debug("recv_ls_req: packet ignored in state %s, " 1029cc19ef1Ssthen "neighbor ID %s (%s)", nbr_state_name(nbr->state), 1039cc19ef1Ssthen inet_ntoa(nbr->id), nbr->iface->name); 104204df0f8Sclaudio break; 105204df0f8Sclaudio case NBR_STA_XCHNG: 106204df0f8Sclaudio case NBR_STA_LOAD: 107204df0f8Sclaudio case NBR_STA_FULL: 1086efdfed8Sclaudio ospfe_imsg_compose_rde(IMSG_LS_REQ, nbr->peerid, 0, buf, len); 109204df0f8Sclaudio break; 110204df0f8Sclaudio default: 111204df0f8Sclaudio fatalx("recv_ls_req: unknown neighbor state"); 112204df0f8Sclaudio } 113204df0f8Sclaudio } 114204df0f8Sclaudio 115204df0f8Sclaudio /* link state request list */ 116204df0f8Sclaudio void 117204df0f8Sclaudio ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa) 118204df0f8Sclaudio { 119204df0f8Sclaudio struct lsa_entry *le; 120204df0f8Sclaudio 121204df0f8Sclaudio if (lsa == NULL) 122204df0f8Sclaudio fatalx("ls_req_list_add: no LSA header"); 123204df0f8Sclaudio 124204df0f8Sclaudio if ((le = calloc(1, sizeof(*le))) == NULL) 125204df0f8Sclaudio fatal("ls_req_list_add"); 126204df0f8Sclaudio 127204df0f8Sclaudio TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry); 128204df0f8Sclaudio le->le_lsa = lsa; 129204df0f8Sclaudio nbr->ls_req_cnt++; 130204df0f8Sclaudio } 131204df0f8Sclaudio 132204df0f8Sclaudio struct lsa_entry * 133204df0f8Sclaudio ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr) 134204df0f8Sclaudio { 135204df0f8Sclaudio struct lsa_entry *le; 136204df0f8Sclaudio 137204df0f8Sclaudio TAILQ_FOREACH(le, &nbr->ls_req_list, entry) { 138204df0f8Sclaudio if ((lsa_hdr->type == le->le_lsa->type) && 139204df0f8Sclaudio (lsa_hdr->ls_id == le->le_lsa->ls_id) && 140204df0f8Sclaudio (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr)) 141204df0f8Sclaudio return (le); 142204df0f8Sclaudio } 143204df0f8Sclaudio return (NULL); 144204df0f8Sclaudio } 145204df0f8Sclaudio 146204df0f8Sclaudio void 147204df0f8Sclaudio ls_req_list_free(struct nbr *nbr, struct lsa_entry *le) 148204df0f8Sclaudio { 149204df0f8Sclaudio if (nbr->ls_req == le) { 150204df0f8Sclaudio nbr->ls_req = TAILQ_NEXT(le, entry); 151204df0f8Sclaudio } 152204df0f8Sclaudio 153204df0f8Sclaudio TAILQ_REMOVE(&nbr->ls_req_list, le, entry); 154204df0f8Sclaudio free(le->le_lsa); 155204df0f8Sclaudio free(le); 156204df0f8Sclaudio nbr->ls_req_cnt--; 157204df0f8Sclaudio 158204df0f8Sclaudio /* received all requested LSA(s), send a new LS req */ 159204df0f8Sclaudio if (nbr->ls_req != NULL && 160204df0f8Sclaudio nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) { 161204df0f8Sclaudio start_ls_req_tx_timer(nbr); 162204df0f8Sclaudio } 163204df0f8Sclaudio 164b24d9cd1Smarkus /* we might not have received all DDs and are still in XCHNG */ 165b24d9cd1Smarkus if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 && 166b24d9cd1Smarkus nbr->state != NBR_STA_XCHNG) 167204df0f8Sclaudio nbr_fsm(nbr, NBR_EVT_LOAD_DONE); 168204df0f8Sclaudio } 169204df0f8Sclaudio 170204df0f8Sclaudio void 171204df0f8Sclaudio ls_req_list_clr(struct nbr *nbr) 172204df0f8Sclaudio { 173204df0f8Sclaudio struct lsa_entry *le; 174204df0f8Sclaudio 175204df0f8Sclaudio while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) { 176204df0f8Sclaudio TAILQ_REMOVE(&nbr->ls_req_list, le, entry); 177204df0f8Sclaudio free(le->le_lsa); 178204df0f8Sclaudio free(le); 179204df0f8Sclaudio } 180204df0f8Sclaudio 181204df0f8Sclaudio nbr->ls_req_cnt = 0; 182204df0f8Sclaudio nbr->ls_req = NULL; 183204df0f8Sclaudio } 184204df0f8Sclaudio 1855c6e55e9Snorby int 186204df0f8Sclaudio ls_req_list_empty(struct nbr *nbr) 187204df0f8Sclaudio { 188204df0f8Sclaudio return (TAILQ_EMPTY(&nbr->ls_req_list)); 189204df0f8Sclaudio } 190204df0f8Sclaudio 191204df0f8Sclaudio /* timers */ 192204df0f8Sclaudio void 193204df0f8Sclaudio ls_req_tx_timer(int fd, short event, void *arg) 194204df0f8Sclaudio { 195204df0f8Sclaudio struct nbr *nbr = arg; 196204df0f8Sclaudio struct timeval tv; 197204df0f8Sclaudio 198204df0f8Sclaudio switch (nbr->state) { 199204df0f8Sclaudio case NBR_STA_DOWN: 200204df0f8Sclaudio case NBR_STA_ATTEMPT: 201204df0f8Sclaudio case NBR_STA_INIT: 202204df0f8Sclaudio case NBR_STA_2_WAY: 203204df0f8Sclaudio case NBR_STA_SNAP: 204204df0f8Sclaudio case NBR_STA_XSTRT: 205204df0f8Sclaudio case NBR_STA_XCHNG: 206204df0f8Sclaudio return; 207204df0f8Sclaudio case NBR_STA_LOAD: 208204df0f8Sclaudio send_ls_req(nbr); 209204df0f8Sclaudio break; 210204df0f8Sclaudio case NBR_STA_FULL: 211204df0f8Sclaudio return; 212204df0f8Sclaudio default: 213204df0f8Sclaudio log_debug("ls_req_tx_timer: unknown neighbor state, " 2149cc19ef1Ssthen "neighbor ID %s (%s)", inet_ntoa(nbr->id), 2159cc19ef1Ssthen nbr->iface->name); 216204df0f8Sclaudio break; 217204df0f8Sclaudio } 218204df0f8Sclaudio 219204df0f8Sclaudio /* reschedule lsreq_tx_timer */ 220204df0f8Sclaudio if (nbr->state == NBR_STA_LOAD) { 221204df0f8Sclaudio timerclear(&tv); 222204df0f8Sclaudio tv.tv_sec = nbr->iface->rxmt_interval; 2233aede346Sclaudio if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1) 2243aede346Sclaudio fatal("ls_req_tx_timer"); 225204df0f8Sclaudio } 226204df0f8Sclaudio } 227204df0f8Sclaudio 2283aede346Sclaudio void 229204df0f8Sclaudio start_ls_req_tx_timer(struct nbr *nbr) 230204df0f8Sclaudio { 231204df0f8Sclaudio struct timeval tv; 232204df0f8Sclaudio 233204df0f8Sclaudio if (nbr == nbr->iface->self) 2343aede346Sclaudio return; 235204df0f8Sclaudio 236204df0f8Sclaudio timerclear(&tv); 2373aede346Sclaudio if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1) 2383aede346Sclaudio fatal("start_ls_req_tx_timer"); 239204df0f8Sclaudio } 240204df0f8Sclaudio 2413aede346Sclaudio void 242204df0f8Sclaudio stop_ls_req_tx_timer(struct nbr *nbr) 243204df0f8Sclaudio { 244204df0f8Sclaudio if (nbr == nbr->iface->self) 2453aede346Sclaudio return; 246204df0f8Sclaudio 2473aede346Sclaudio if (evtimer_del(&nbr->lsreq_tx_timer) == -1) 2483aede346Sclaudio fatal("stop_ls_req_tx_timer"); 249204df0f8Sclaudio } 250