#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <machine/spl.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/filedesc.h>
#include <sys/fcntl.h>
#include <sys/mbuf.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <net/if.h>
#include <netat/sysglue.h>
#include <netat/appletalk.h>
#include <netat/at_var.h>
#include <netat/ddp.h>
#include <netat/rtmp.h>
#include <netat/zip.h>
#include <netat/routing_tables.h>
#include <netat/debug.h>
#include <netat/at_pcb.h>
extern void rtmp_router_input();
#define NROUTERS2TRAK 8
#define FIFTYSECS 10
#define NODE(r) ((r)->ifARouter.s_node)
#define NET(r) ((r)->ifARouter.s_net)
#define INUSE(r) (NODE(r))
void ddp_age_router();
static struct routerinfo {
struct at_addr ifARouter;
at_ifaddr_t *ifID;
void *tmo;
} trackedrouters[NROUTERS2TRAK];
void trackrouter_rem_if(ifID)
register at_ifaddr_t *ifID;
{
register i;
register struct routerinfo *router;
for (i = NROUTERS2TRAK; --i >= 0;) {
router = &trackedrouters[i];
if (trackedrouters[i].ifID == ifID) {
untimeout(ddp_age_router, (caddr_t)router);
break;
}
}
}
void routershutdown()
{
register i;
for (i = NROUTERS2TRAK; --i >= 0;) {
register struct routerinfo *router;
router = &trackedrouters[i];
if (INUSE(router)) {
untimeout(ddp_age_router, (caddr_t) router);
bzero((caddr_t) router, sizeof(struct routerinfo));
}
}
}
int router_added = 0;
int router_killed = 0;
void trackrouter(ifID, net, node)
register at_ifaddr_t *ifID;
register unsigned short net;
register unsigned char node;
{
register struct routerinfo *unused = NULL;
register i;
for (i = NROUTERS2TRAK; --i >= 0;) {
register struct routerinfo *router;
router = &trackedrouters[(i + node) & (NROUTERS2TRAK-1)];
if ((NODE(router) == node) && (NET(router) == net)) {
untimeout(ddp_age_router, (caddr_t) router);
timeout(ddp_age_router, (caddr_t) router, 50*SYS_HZ);
unused = NULL;
break;
}
else if (!INUSE(router) && !unused)
unused = router;
}
if (unused) {
router_added++;
unused->ifID = ifID;
NET(unused) = net;
NODE(unused) = node;
timeout(ddp_age_router, (caddr_t) unused, 50*SYS_HZ);
if (NET(ifID) == 0 && NODE(ifID) == 0) {
NET(ifID) = net;
NODE(ifID) = node;
ifID->ifRouterState = ROUTER_AROUND;
}
}
}
void ddp_age_router(deadrouter)
register struct routerinfo *deadrouter;
{
register at_ifaddr_t *ourrouter = deadrouter->ifID;
boolean_t funnel_state;
funnel_state = thread_funnel_set(network_flock, TRUE);
dPrintf(D_M_RTMP, D_L_INFO,
("ddp_age_router called deadrouter=%d:%d\n", NODE(deadrouter), NET(deadrouter)));
router_killed++;
if (NODE(ourrouter) == NODE(deadrouter) &&
NET(ourrouter) == NET(deadrouter)) {
register unsigned long atrandom = random();
register struct routerinfo *newrouter;
register i;
bzero((caddr_t) deadrouter, sizeof(struct routerinfo));
for (i = NROUTERS2TRAK; --i >= 0;) {
newrouter = &trackedrouters[(i + atrandom) & (NROUTERS2TRAK-1)];
if (INUSE(newrouter))
break;
else
newrouter = NULL;
}
if (newrouter) {
NET(ourrouter) = NET(newrouter);
NODE(ourrouter) = NODE(newrouter);
}
else {
ATTRACE(AT_MID_DDP, AT_SID_TIMERS, AT_LV_WARNING, FALSE,
"ddp_age_router entry : ARouter = 0x%x, RouterState = 0x%x",
ATALK_VALUE(ourrouter->ifARouter), ourrouter->ifRouterState, 0);
switch (ourrouter->ifRouterState) {
case ROUTER_AROUND :
ourrouter->ifARouter.s_net = 0;
ourrouter->ifARouter.s_node = 0;
dPrintf(D_M_RTMP,D_L_INFO,
("rtmp.c Gorouterless!!!!!!!!\n"));
ourrouter->ifThisCableStart = DDP_MIN_NETWORK;
ourrouter->ifThisCableEnd = DDP_MAX_NETWORK;
ourrouter->ifRouterState = NO_ROUTER;
zip_control(ourrouter, ZIP_NO_ROUTER);
break;
case ROUTER_WARNING :
ourrouter->ifRouterState = NO_ROUTER;
break;
}
}
} else
bzero((caddr_t) deadrouter, sizeof(struct routerinfo));
(void) thread_funnel_set(network_flock, FALSE);
}
void rtmp_input (mp, ifID)
register gbuf_t *mp;
register at_ifaddr_t *ifID;
{
register at_net_al this_net;
register at_net_al range_start, range_end;
register at_ddp_t *ddp = (at_ddp_t *)gbuf_rptr(mp);
register at_rtmp *rtmp = (at_rtmp *)ddp->data;
if (gbuf_type(mp) != MSG_DATA) {
gbuf_freem(mp);
return;
}
if (!ifID) {
gbuf_freem(mp);
return;
}
if (gbuf_len(mp) < (DDP_X_HDR_SIZE + sizeof(at_rtmp))) {
gbuf_freem(mp);
return;
}
this_net = ifID->ifThisNode.s_net;
if (rtmp->at_rtmp_id_length != 8) {
gbuf_freem(mp);
return;
}
{
at_rtmp_tuple *tp;
tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[1]);
range_start = NET_VALUE(tp->at_rtmp_net);
tp = ((at_rtmp_tuple *)&rtmp->at_rtmp_id[4]);
range_end = NET_VALUE(tp->at_rtmp_net);
if (ifID->ifRouterState == ROUTER_AROUND) {
if ((ifID->ifThisCableStart == range_start) &&
(ifID->ifThisCableEnd == range_end)) {
trackrouter(ifID,
NET_VALUE(rtmp->at_rtmp_this_net),
rtmp->at_rtmp_id[0]
);
}
} else {
if ((this_net >= DDP_STARTUP_LOW) &&
(this_net <= DDP_STARTUP_HIGH)) {
if (ifID->ifRouterState == NO_ROUTER) {
dPrintf(D_M_RTMP, D_L_STARTUP,
("Warning: new router came up: invalid startup net/node\n"));
trackrouter(ifID,
NET_VALUE(rtmp->at_rtmp_this_net),
rtmp->at_rtmp_id[0]
);
ifID->ifRouterState = ROUTER_WARNING;
}
} else {
if ((this_net >= range_start) &&
(this_net <= range_end)) {
ifID->ifThisCableStart = range_start;
ifID->ifThisCableEnd = range_end;
trackrouter(ifID,
NET_VALUE(rtmp->at_rtmp_this_net),
rtmp->at_rtmp_id[0]
);
zip_control(ifID, ZIP_LATE_ROUTER);
} else {
if (ifID->ifRouterState == NO_ROUTER) {
dPrintf(D_M_RTMP,D_L_ERROR,
("Warning: new router came up: invalid net/node\n"));
trackrouter(ifID,
NET_VALUE(rtmp->at_rtmp_this_net),
rtmp->at_rtmp_id[0]
);
ifID->ifRouterState = ROUTER_WARNING;
}
}
}
}
}
gbuf_freem(mp);
return;
}
void rtmp_init()
{
bzero((caddr_t)trackedrouters, sizeof(struct routerinfo)*NROUTERS2TRAK);
}