#include "global.h" #include "mbuf.h" #include "timer.h" #include "iface.h" #include "cmdparse.h" #include "netuser.h" #include "socket.h" #include "rspf.h" int Rspfownmode = -1; static int dointerface __ARGS((int argc,char *argv[],void *p)); static int domessage __ARGS((int argc,char *argv[],void *p)); static int domaxping __ARGS((int argc,char *argv[],void *p)); static int domode __ARGS((int argc,char *argv[],void *p)); static int dorrhtimer __ARGS((int argc,char *argv[],void *p)); static int dotimer __ARGS((int argc,char *argv[],void *p)); static int doroutes __ARGS((int argc,char *argv[],void *p)); static int dostatus __ARGS((int argc,char *argv[],void *p)); static int dosuspect __ARGS((int argc,char *argv[],void *p)); static struct timer rrhtimer, rspftimer; static struct cmds Rspfcmds[] = { "interface", dointerface, 0, 0, NULLCHAR, "message", domessage, 0, 0, NULLCHAR, "maxping", domaxping, 0, 0, NULLCHAR, "mode", domode, 0, 0, NULLCHAR, "rrhtimer", dorrhtimer, 0, 0, NULLCHAR, "routes", doroutes, 0, 0, NULLCHAR, "status", dostatus, 0, 0, NULLCHAR, "suspecttimer", dosuspect, 0, 0, NULLCHAR, "timer", dotimer, 0, 0, NULLCHAR, NULLCHAR }; int dorspf(argc,argv,p) int argc; char *argv[]; void *p; { return subcmd(Rspfcmds,argc,argv,p); } /* The suspect timer controls how often old links expire. When a link has * expired, we try to renew its entry by various methods. */ static int dosuspect(argc,argv,p) int argc; char *argv[]; void *p; { if(Rspfifaces == NULLRIFACE){ tprintf("RSPF is not active - define interface first.\n"); return 0; } if(argc < 2){ tprintf("Suspect timer: %lu/%lu seconds\n", read_timer(&Susptimer)/1000, dur_timer(&Susptimer)/1000); return 0; } Susptimer.func = rspfsuspect; /* what to call on timeout */ Susptimer.arg = NULL; /* dummy value */ set_timer(&Susptimer,atol(argv[1])*1000L); /* set timer duration */ start_timer(&Susptimer); /* and fire it up */ return 0; } /* The RRH timer controls the interval between Router-To-Router Hello * messages. These messages announce that your station is live and well * and that you are willing to exchange RSPF routing updates. */ static int dorrhtimer(argc,argv,p) int argc; char *argv[]; void *p; { if(Rspfifaces == NULLRIFACE){ tprintf("RSPF is not active - define interface first.\n"); return 0; } if(argc < 2){ tprintf("RRH timer: %lu/%lu seconds\n", read_timer(&rrhtimer)/1000, dur_timer(&rrhtimer)/1000); return 0; } rrhtimer.func = rspfevent; /* what to call on timeout */ rrhtimer.arg = (void *) &rrhtimer; set_timer(&rrhtimer,atol(argv[1])*1000L); /* set timer duration */ start_timer(&rrhtimer); /* and fire it up */ return 0; } /* This timer controls the interval between the RSPF routing updates. */ static int dotimer(argc,argv,p) int argc; char *argv[]; void *p; { if(Rspfifaces == NULLRIFACE){ tprintf("RSPF is not active - define interface first.\n"); return 0; } if(argc < 2){ tprintf("RSPF update timer: %lu/%lu seconds\n", read_timer(&rspftimer)/1000, dur_timer(&rspftimer)/1000); return 0; } rspftimer.func = rspfevent; /* what to call on timeout */ rspftimer.arg = (void *) &rspftimer; set_timer(&rspftimer,atol(argv[1])*1000L); /* set timer duration */ start_timer(&rspftimer); /* and fire it up */ return 0; } /* Called when either the RRH timer, the Update timer or the Suspect timer * expires. */ void rspfevent(t) void *t; { int cmd; struct mbuf *bp; struct rspfadj *adj = NULLADJ; struct timer *tp; tp = (struct timer *) t; if(tp == &rrhtimer) { cmd = RSPFE_RRH; start_timer(tp); } else if(tp == &rspftimer) { cmd = RSPFE_UPDATE; start_timer(tp); } else { for(adj = Adjs; adj != NULLADJ; adj = adj->next) if(&adj->timer == tp) break; if(adj == NULLADJ) return; cmd = RSPFE_CHECK; } bp = ambufw(1+sizeof(int32)); *bp->data = cmd; memcpy(bp->data + 1,&adj,sizeof(adj)); bp->cnt = bp->size; enqueue(&Rspfinq,bp); } static int domessage(argc,argv,p) int argc; char *argv[]; void *p; { if(argc > 2) { tputs("Usage: rspf message \"\"\n"); return 0; } if(argc < 2) { if(Rrh_message != NULLCHAR) tputs(Rrh_message); } else { if(Rrh_message != NULLCHAR){ free(Rrh_message); Rrh_message = NULLCHAR; /* reset the pointer */ } if(!strlen(argv[1])) return 0; /* clearing the buffer */ Rrh_message = mallocw(strlen(argv[1])+5);/* allow for EOL */ strcpy(Rrh_message, argv[1]); strcat(Rrh_message, INET_EOL); /* add the EOL char */ } return 0; } static int domaxping(argc,argv,p) int argc; char *argv[]; void *p; { return setshort(&Rspfpingmax,"Max failed pings before deleting adjacency", argc,argv); } static int domode(argc,argv,p) int argc; char *argv[]; void *p; { if(argc < 2) { tputs("RSPF preferred mode is "); if(Rspfownmode == -1) tputs("not set.\n"); else tprintf("%s.\n",(Rspfownmode & CONNECT_MODE) ? "VC mode" : "Datagram mode"); return 0; } switch(*argv[1]){ case 'v': case 'c': case 'V': case 'C': Rspfownmode = CONNECT_MODE; break; case 'd': case 'D': Rspfownmode = DATAGRAM_MODE; break; case 'n': case 'N': Rspfownmode = -1; break; default: tputs("Usage: rspf mode [vc | datagram | none]\n"); return 1; } return 0; } static int dointerface(argc,argv,p) int argc; char *argv[]; void *p; { struct rspfiface *riface; struct iface *iface; struct mbuf *bp; int h,q; if(argc < 2){ tputs("Iface Quality Horizon\n"); for(riface = Rspfifaces; riface != NULLRIFACE; riface = riface->next) tprintf("%-9s%-11d%-11d\n",riface->iface->name,riface->quality, riface->horizon); return 0; } if(argc != 4){ tputs("Usage: rspf interface \n"); return 1; } if((iface = if_lookup(argv[1])) == NULLIF){ tputs("No such interface.\n"); return 1; } if(iface->broadcast == 0){ tprintf("Broadcast address for interface %s not set\n",argv[1]); return 1; } q = atoi(argv[2]); if(q < 1 || q > 127){ tputs("Quality must be between 1 and 127\n"); return 1; } h = atoi(argv[3]); if(h < 1 || h > 255){ tputs("Horizon must be between 1 and 255\n"); return 1; } riface = (struct rspfiface *)callocw(1,sizeof(struct rspfiface)); riface->iface = iface; riface->quality = q; riface->horizon = h; riface->next = Rspfifaces; if(Rspfifaces == NULLRIFACE) newproc("RSPF",2048,rspfmain,0,NULL,NULL,0); Rspfifaces = riface; bp = ambufw(1+sizeof(int32)); *bp->data = RSPFE_RRH; /* Send an RRH immediately */ memcpy(bp->data + 1,&riface,sizeof(riface)); bp->cnt = bp->size; enqueue(&Rspfinq,bp); return 0; } /* Display accumulated routing updates */ static int doroutes(argc,argv,p) int argc; char *argv[]; void *p; { struct mbuf *bp; struct rspfrouter *rr; if(Rspfifaces == NULLRIFACE){ tprintf("RSPF is not active - define interface first.\n"); return 0; } bp = makeownupdate(INADDR_ANY,0); if(bp == NULLBUF && Rspfrouters == NULLRROUTER) { tputs("No routing information is available.\n"); return 0; } if(bp != NULLBUF) { tputs(" Local routing update:\n"); rspfnodedump(NULLFILE,&bp,0); tputc('\n'); } for(rr = Rspfrouters; rr != NULLRROUTER; rr = rr->next) { tprintf(" Time since receipt: %s",tformat(secclock() - rr->time)); if(rr->subseq != 0) tprintf(" Last subseq: %u",uchar(rr->subseq)); if(rr->sent) tputs(" Propagated"); tputc('\n'); if(rr->data != NULLBUF) { dup_p(&bp,rr->data,0,len_p(rr->data)); rspfnodedump(NULLFILE,&bp,0); tputc('\n'); } } return 0; } static int dostatus(argc,argv,p) int argc; char *argv[]; void *p; { struct rspfreasm *re; struct rspfadj *adj; struct mbuf *bp; union rspf rspf; if(Rspfifaces == NULLRIFACE){ tprintf("RSPF is not active - define interface first.\n"); return 0; } tprintf("Bad checksum %u Bad version %u Not RSPF interface %u\n", Rspf_stat.badcsum,Rspf_stat.badvers,Rspf_stat.norspfiface); tprintf("RRH in %u RRH out %u Update in %u Update out %u\n", Rspf_stat.rrhin,Rspf_stat.rrhout,Rspf_stat.updatein, Rspf_stat.updateout); tprintf("Non-adjacency update %u Old node report %u Polls sent %u\n", Rspf_stat.noadjupdate,Rspf_stat.oldreport,Rspf_stat.outpolls); if(Adjs == NULLADJ) return 0; tputs("Addr Cost Seq Heard Timer TOS State\n"); for(adj = Adjs; adj != NULLADJ; adj = adj->next) { tprintf("%-15s %4u %5u %6lu ", inet_ntoa(adj->addr), uchar(adj->cost),adj->seq,adj->heard); if(run_timer(&adj->timer)) tprintf("%5lu/%-5lu", read_timer(&adj->timer)/1000L ,dur_timer(&adj->timer)/1000L); else tprintf("%11s",""); tprintf(" %3u ", uchar(adj->tos)); switch(adj->state) { case RSPF_TENTATIVE: tputs("Tentative"); break; case RSPF_OK: tputs("OK"); break; case RSPF_SUSPECT: tputs("Suspect"); break; case RSPF_BAD: tputs("Bad"); break; default: tputs("Unknown"); break; } tputc('\n'); } if(run_timer(&Rspfreasmt)) { tprintf("Reassembly timer running: %lu/%lu seconds\n", read_timer(&Rspfreasmt)/1000L, dur_timer(&Rspfreasmt)/1000L); } if(Rspfreasmq != NULLRREASM) tputs("Reassembly fragments:\n"); for(re = Rspfreasmq; re != NULLRREASM; re = re->next) { tprintf("src %s time since last frag %s",inet_ntoa(re->addr), tformat((secclock() - re->time))); if(dup_p(&bp,re->data,0,RSPFPKTLEN) == RSPFPKTLEN && ntohrspf(&rspf,&bp) != -1) tprintf(" frag count %u/%u\n",len_q(re->data), rspf.pkthdr.fragtot); else { tputc('\n'); free_p(bp); continue; } } return 0; }