summaryrefslogtreecommitdiff
path: root/proto/ospf/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/ospf/iface.c')
-rw-r--r--proto/ospf/iface.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
new file mode 100644
index 00000000..57c6983d
--- /dev/null
+++ b/proto/ospf/iface.c
@@ -0,0 +1,330 @@
+/*
+ * BIRD -- OSPF
+ *
+ * (c) 1999 Ondrej Filip <feela@network.cz>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "ospf.h"
+
+void
+iface_chstate(struct ospf_iface *ifa, u8 state)
+{
+ struct proto *p;
+
+ p=(struct proto *)(ifa->proto);
+ debug("%s: Changing state of iface: %s from %u into %u.\n",
+ p->name, ifa->iface->name, ifa->state, state);
+ ifa->state=state;
+}
+
+void
+downint(struct ospf_iface *ifa)
+{
+ /* FIXME: Delete all neighbors! */
+}
+
+void
+ospf_int_sm(struct ospf_iface *ifa, int event)
+{
+ struct proto *p;
+
+ p=(struct proto *)(ifa->proto);
+
+ DBG("%s: SM on iface %s. Event is %d.\n",
+ p->name, ifa->iface->name, event);
+
+ switch(event)
+ {
+ case ISM_UP:
+ if(ifa->state==OSPF_IS_DOWN)
+ {
+ restart_hellotim(ifa);
+ if((ifa->type==OSPF_IT_PTP) || (ifa->type==OSPF_IT_VLINK))
+ {
+ iface_chstate(ifa, OSPF_IS_PTP);
+ }
+ else
+ {
+ if(ifa->priority==0)
+ {
+ iface_chstate(ifa, OSPF_IS_DROTHER);
+ }
+ else
+ {
+ iface_chstate(ifa, OSPF_IS_WAITING);
+ restart_waittim(ifa);
+ }
+ }
+ }
+ break;
+ case ISM_BACKS:
+ case ISM_WAITF:
+ if(ifa->state==OSPF_IS_WAITING)
+ {
+ bdr_election(ifa ,p);
+ }
+ break;
+ case ISM_NEICH:
+ if((ifa->state==OSPF_IS_DROTHER) || (ifa->state==OSPF_IS_DR) ||
+ (ifa->state==OSPF_IS_BACKUP))
+ {
+ bdr_election(ifa ,p);
+ }
+ case ISM_DOWN:
+ iface_chstate(ifa, OSPF_IS_DOWN);
+ downint(ifa);
+ break;
+ case ISM_LOOP: /* Useless? */
+ iface_chstate(ifa, OSPF_IS_LOOP);
+ downint(ifa);
+ break;
+ case ISM_UNLOOP:
+ iface_chstate(ifa, OSPF_IS_DOWN);
+ break;
+ default:
+ die("%s: ISM - Unknown event?",p->name);
+ break;
+ }
+
+}
+
+sock *
+ospf_open_mc_socket(struct ospf_iface *ifa)
+{
+ sock *mcsk;
+ struct proto *p;
+
+ p=(struct proto *)(ifa->proto);
+
+
+ /* FIXME: No NBMA networks now */
+
+ if(ifa->iface->flags & IF_MULTICAST)
+ {
+ mcsk=sk_new(p->pool);
+ mcsk->type=SK_IP_MC;
+ mcsk->dport=OSPF_PROTO;
+ mcsk->saddr=AllSPFRouters;
+ mcsk->daddr=AllSPFRouters;
+ mcsk->tos=IP_PREC_INTERNET_CONTROL;
+ mcsk->ttl=1;
+ mcsk->rx_hook=ospf_rx_hook;
+ mcsk->tx_hook=ospf_tx_hook;
+ mcsk->err_hook=ospf_err_hook;
+ mcsk->iface=ifa->iface;
+ mcsk->rbsize=ifa->iface->mtu;
+ mcsk->tbsize=ifa->iface->mtu;
+ mcsk->data=(void *)ifa;
+ if(sk_open(mcsk)!=0)
+ {
+ DBG("%s: SK_OPEN: mc open failed.\n",p->name);
+ return(NULL);
+ }
+ DBG("%s: SK_OPEN: mc opened.\n",p->name);
+ return(mcsk);
+ }
+ else return(NULL);
+}
+
+sock *
+ospf_open_ip_socket(struct ospf_iface *ifa)
+{
+ sock *ipsk;
+ struct proto *p;
+
+ p=(struct proto *)(ifa->proto);
+
+ ipsk=sk_new(p->pool);
+ ipsk->type=SK_IP;
+ ipsk->dport=OSPF_PROTO;
+ ipsk->saddr=ifa->iface->addr->ip;
+ ipsk->tos=IP_PREC_INTERNET_CONTROL;
+ ipsk->ttl=1;
+ ipsk->rx_hook=ospf_rx_hook;
+ ipsk->tx_hook=ospf_tx_hook;
+ ipsk->err_hook=ospf_err_hook;
+ ipsk->iface=ifa->iface;
+ ipsk->rbsize=ifa->iface->mtu;
+ ipsk->tbsize=ifa->iface->mtu;
+ ipsk->data=(void *)ifa;
+ if(sk_open(ipsk)!=0)
+ {
+ DBG("%s: SK_OPEN: ip open failed.\n",p->name);
+ return(NULL);
+ }
+ DBG("%s: SK_OPEN: ip opened.\n",p->name);
+ return(ipsk);
+}
+
+/*
+ * This will later decide, wheter use iface for OSPF or not
+ * depending on config
+ */
+u8
+is_good_iface(struct proto *p, struct iface *iface)
+{
+ if(iface->flags & IF_UP)
+ {
+ if(!(iface->flags & IF_IGNORE)) return 1;
+ }
+ return 0;
+}
+
+/* Of course, it's NOT true now */
+u8
+ospf_iface_clasify(struct iface *ifa)
+{
+ /* FIXME: Latter I'll use config - this is incorrect */
+ if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
+ (IF_MULTIACCESS|IF_MULTICAST))
+ {
+ DBG(" OSPF: Clasifying BCAST.\n");
+ return OSPF_IT_BCAST;
+ }
+ if((ifa->flags & (IF_MULTIACCESS|IF_MULTICAST))==
+ IF_MULTIACCESS)
+ {
+ DBG(" OSPF: Clasifying NBMA.\n");
+ return OSPF_IT_NBMA;
+ }
+ DBG(" OSPF: Clasifying P-T-P.\n");
+ return OSPF_IT_PTP;
+}
+
+void
+ospf_add_timers(struct ospf_iface *ifa, pool *pool)
+{
+ struct proto *p;
+
+ p=(struct proto *)(ifa->proto);
+ /* Add hello timer */
+ ifa->hello_timer=tm_new(pool);
+ ifa->hello_timer->data=ifa;
+ ifa->hello_timer->randomize=0;
+ if(ifa->helloint==0) ifa->helloint=HELLOINT_D;
+ ifa->hello_timer->hook=hello_timer_hook;
+ ifa->hello_timer->recurrent=ifa->helloint;
+ DBG("%s: Installing hello timer. (%u)\n", p->name, ifa->helloint);
+
+ ifa->rxmt_timer=tm_new(pool);
+ ifa->rxmt_timer->data=ifa;
+ ifa->rxmt_timer->randomize=0;
+ if(ifa->rxmtint==0) ifa->rxmtint=RXMTINT_D;
+ ifa->rxmt_timer->hook=rxmt_timer_hook;
+ ifa->rxmt_timer->recurrent=ifa->rxmtint;
+ DBG("%s: Installing rxmt timer. (%u)\n", p->name, ifa->rxmtint);
+
+ ifa->wait_timer=tm_new(pool);
+ ifa->wait_timer->data=ifa;
+ ifa->wait_timer->randomize=0;
+ ifa->wait_timer->hook=wait_timer_hook;
+ ifa->wait_timer->recurrent=0;
+ if(ifa->waitint==0) ifa->waitint= WAIT_DMH*ifa->helloint;
+ DBG("%s: Installing wait timer. (%u)\n", p->name, ifa->waitint);
+}
+
+void
+ospf_iface_default(struct ospf_iface *ifa)
+{
+ u8 i;
+
+ ifa->area=0; /* FIXME: Read from config */
+ ifa->cost=COST_D;
+ ifa->rxmtint=RXMTINT_D;
+ ifa->iftransdelay=IFTRANSDELAY_D;
+ ifa->priority=PRIORITY_D;
+ ifa->helloint=HELLOINT_D;
+ ifa->deadc=DEADC_D;
+ ifa->autype=0;
+ for(i=0;i<8;i++) ifa->aukey[i]=0;
+ ifa->options=2;
+ ifa->drip=ipa_from_u32(0x00000000);
+ ifa->drid=0;
+ ifa->bdrip=ipa_from_u32(0x00000000);
+ ifa->bdrid=0;
+ ifa->type=ospf_iface_clasify(ifa->iface);
+}
+
+struct ospf_iface*
+find_iface(struct proto_ospf *p, struct iface *what)
+{
+ struct ospf_iface *i;
+
+ WALK_LIST (i, p->iface_list)
+ if ((i)->iface == what)
+ return i;
+ return NULL;
+}
+
+void
+ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
+{
+ struct ospf_iface *ifa;
+ sock *mcsk;
+
+ struct ospf_config *c;
+ c=(struct ospf_config *)(p->cf);
+
+ DBG(" OSPF: If notify called\n");
+ if (iface->flags & IF_IGNORE)
+ return;
+
+ if((flags & IF_CHANGE_UP) && is_good_iface(p, iface))
+ {
+ debug(" OSPF: using interface %s.\n", iface->name);
+ /* FIXME: Latter I'll use config - this is incorrect */
+ ifa=mb_alloc(p->pool, sizeof(struct ospf_iface));
+ ifa->proto=(struct proto_ospf *)p;
+ ifa->iface=iface;
+ ospf_iface_default(ifa);
+ if(ifa->type!=OSPF_IT_NBMA)
+ {
+ if((ifa->hello_sk=ospf_open_mc_socket(ifa))==NULL)
+ {
+ log("%s: Huh? could not open mc socket on interface %s?", p->name,
+ iface->name);
+ mb_free(ifa);
+ log("%s: Ignoring this interface\n", p->name);
+ return;
+ }
+
+ if((ifa->ip_sk=ospf_open_ip_socket(ifa))==NULL)
+ {
+ log("%s: Huh? could not open ip socket on interface %s?", p->name,
+ iface->name);
+ mb_free(ifa);
+ log("%s: Ignoring this interface\n", p->name);
+ return;
+ }
+
+ init_list(&(ifa->neigh_list));
+ }
+ /* FIXME: This should read config */
+ ifa->helloint=0;
+ ifa->waitint=0;
+ ospf_add_timers(ifa,p->pool);
+ add_tail(&((struct proto_ospf *)p)->iface_list, NODE ifa);
+ ospf_int_sm(ifa, ISM_UP);
+ }
+
+ if(flags & IF_CHANGE_DOWN)
+ {
+ if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
+ {
+ debug(" OSPF: killing interface %s.\n", iface->name);
+ ospf_int_sm(ifa, ISM_DOWN);
+ }
+ }
+
+ if(flags & IF_CHANGE_MTU)
+ {
+ if((ifa=find_iface((struct proto_ospf *)p, iface))!=NULL)
+ {
+ debug(" OSPF: changing MTU on interface %s.\n", iface->name);
+ /* FIXME: change MTU */
+ }
+ }
+}
+