summaryrefslogtreecommitdiff
path: root/usr.sbin/ospfd/lsreq.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/ospfd/lsreq.c')
-rw-r--r--usr.sbin/ospfd/lsreq.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/usr.sbin/ospfd/lsreq.c b/usr.sbin/ospfd/lsreq.c
new file mode 100644
index 00000000000..8018c240ad5
--- /dev/null
+++ b/usr.sbin/ospfd/lsreq.c
@@ -0,0 +1,259 @@
+/* $OpenBSD: lsreq.c,v 1.1 2005/01/28 14:05:40 claudio Exp $ */
+
+/*
+ * Copyright (c) 2004, 2005 Esben Norby <esben.norby@ericsson.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#include "ospfd.h"
+#include "ospf.h"
+#include "log.h"
+#include "ospfe.h"
+
+extern struct imsgbuf *ibuf_rde;
+
+/* link state request packet handling */
+int
+send_ls_req(struct nbr *nbr)
+{
+ struct sockaddr_in dst;
+ struct ls_req_hdr *ls_req_hdr;
+ struct lsa_entry *le, *nle;
+ char *buf = NULL;
+ char *ptr;
+ int ret = 0;
+
+ log_debug("send_ls_req: neighbor ID %s", inet_ntoa(nbr->id));
+
+ if (nbr->iface->passive)
+ return (0);
+
+ /* XXX use buffer API instead for better decoupling */
+ if ((ptr = buf = calloc(1, READ_BUF_SIZE)) == NULL)
+ fatal("send_ls_req");
+
+ /* set destination */
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ switch (nbr->iface->type) {
+ case IF_TYPE_POINTOPOINT:
+ inet_aton(AllSPFRouters, &dst.sin_addr);
+ break;
+ case IF_TYPE_BROADCAST:
+ case IF_TYPE_NBMA:
+ case IF_TYPE_POINTOMULTIPOINT:
+ case IF_TYPE_VIRTUALLINK:
+ dst.sin_addr.s_addr = nbr->addr.s_addr;
+ break;
+ default:
+ fatalx("send_ls_req: unknown interface type");
+ }
+
+ /* OSPF header */
+ gen_ospf_hdr(ptr, nbr->iface, PACKET_TYPE_LS_REQUEST);
+ ptr += sizeof(struct ospf_hdr);
+
+ /* LSA header(s) */
+ for (le = TAILQ_FIRST(&nbr->ls_req_list); le != NULL &&
+ (ptr - buf) < nbr->iface->mtu - PACKET_HDR; le = nle) {
+ nbr->ls_req = nle = TAILQ_NEXT(le, entry);
+ ls_req_hdr = (struct ls_req_hdr *)ptr;
+ ls_req_hdr->type = htonl(le->le_lsa->type);
+ ls_req_hdr->ls_id = le->le_lsa->ls_id;
+ ls_req_hdr->adv_rtr = le->le_lsa->adv_rtr;
+ ptr += sizeof(*ls_req_hdr);
+ }
+
+ /* update authentication and calculate checksum */
+ auth_gen(buf, ptr - buf, nbr->iface);
+
+ if ((ret = send_packet(nbr->iface, buf, (ptr - buf), &dst)) == -1)
+ log_warnx("send_ls_req: error sending packet on "
+ "interface %s", nbr->iface->name);
+ free(buf);
+ return (ret);
+}
+
+void
+recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len)
+{
+ log_debug("recv_ls_req: neighbor ID %s", inet_ntoa(nbr->id));
+
+ switch (nbr->state) {
+ case NBR_STA_DOWN:
+ case NBR_STA_ATTEMPT:
+ case NBR_STA_INIT:
+ case NBR_STA_2_WAY:
+ case NBR_STA_XSTRT:
+ case NBR_STA_SNAP:
+ log_debug("recv_ls_req: packet ignored in state %s, "
+ "neighbor ID %s", nbr_state_name(nbr->state),
+ inet_ntoa(nbr->id));
+ nbr_fsm(nbr, NBR_EVT_ADJ_OK);
+ break;
+ case NBR_STA_XCHNG:
+ case NBR_STA_LOAD:
+ case NBR_STA_FULL:
+ imsg_compose(ibuf_rde, IMSG_LS_REQ, nbr->peerid, 0, -1,
+ buf, len);
+ break;
+ default:
+ fatalx("recv_ls_req: unknown neighbor state");
+ }
+}
+
+/* link state request list */
+void
+ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
+{
+ struct lsa_entry *le;
+
+ if (lsa == NULL)
+ fatalx("ls_req_list_add: no LSA header");
+
+ if ((le = calloc(1, sizeof(*le))) == NULL)
+ fatal("ls_req_list_add");
+
+ TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry);
+ le->le_lsa = lsa;
+ nbr->ls_req_cnt++;
+}
+
+struct lsa_entry *
+ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
+{
+ struct lsa_entry *le;
+
+ TAILQ_FOREACH(le, &nbr->ls_req_list, entry) {
+ if ((lsa_hdr->type == le->le_lsa->type) &&
+ (lsa_hdr->ls_id == le->le_lsa->ls_id) &&
+ (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr))
+ return (le);
+ }
+ return (NULL);
+}
+
+void
+ls_req_list_free(struct nbr *nbr, struct lsa_entry *le)
+{
+ if (nbr->ls_req == le) {
+ nbr->ls_req = TAILQ_NEXT(le, entry);
+ }
+
+ TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
+ free(le->le_lsa);
+ free(le);
+ nbr->ls_req_cnt--;
+
+ /* received all requested LSA(s), send a new LS req */
+ if (nbr->ls_req != NULL &&
+ nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) {
+ start_ls_req_tx_timer(nbr);
+ }
+
+ if (ls_req_list_empty(nbr))
+ nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
+}
+
+void
+ls_req_list_clr(struct nbr *nbr)
+{
+ struct lsa_entry *le;
+
+ while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) {
+ TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
+ free(le->le_lsa);
+ free(le);
+ }
+
+ nbr->ls_req_cnt = 0;
+ nbr->ls_req = NULL;
+}
+
+bool
+ls_req_list_empty(struct nbr *nbr)
+{
+ return (TAILQ_EMPTY(&nbr->ls_req_list));
+}
+
+/* timers */
+void
+ls_req_tx_timer(int fd, short event, void *arg)
+{
+ struct nbr *nbr = arg;
+ struct timeval tv;
+
+ log_debug("ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id));
+
+ switch (nbr->state) {
+ case NBR_STA_DOWN:
+ case NBR_STA_ATTEMPT:
+ case NBR_STA_INIT:
+ case NBR_STA_2_WAY:
+ case NBR_STA_SNAP:
+ case NBR_STA_XSTRT:
+ case NBR_STA_XCHNG:
+ return;
+ case NBR_STA_LOAD:
+ send_ls_req(nbr);
+ break;
+ case NBR_STA_FULL:
+ return;
+ default:
+ log_debug("ls_req_tx_timer: unknown neighbor state, "
+ "neighbor ID %s", inet_ntoa(nbr->id));
+ break;
+ }
+
+ /* reschedule lsreq_tx_timer */
+ if (nbr->state == NBR_STA_LOAD) {
+ timerclear(&tv);
+ tv.tv_sec = nbr->iface->rxmt_interval;
+ log_debug("ls_req_tx_timer: reschedule neighbor ID %s",
+ inet_ntoa(nbr->id));
+ evtimer_add(&nbr->lsreq_tx_timer, &tv);
+ }
+}
+
+int
+start_ls_req_tx_timer(struct nbr *nbr)
+{
+ struct timeval tv;
+
+ if (nbr == nbr->iface->self)
+ return (0);
+
+ log_debug("start_ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id));
+ timerclear(&tv);
+
+ return (evtimer_add(&nbr->lsreq_tx_timer, &tv));
+}
+
+int
+stop_ls_req_tx_timer(struct nbr *nbr)
+{
+ if (nbr == nbr->iface->self)
+ return (0);
+
+ log_debug("stop_ls_req_tx_timer: neighbor ID %s", inet_ntoa(nbr->id));
+
+ return (evtimer_del(&nbr->lsreq_tx_timer));
+}