📄 rdisclib.c
字号:
/* rdiscLib.c - ICMP router discovery server library *//* Copyright 1984 - 2001 Wind River Systems, Inc. */#include "copyright_wrs.h" /*modification history--------------------01a,29mar01,spm file creation: copied from version 01g of tor2_0.open_stack branch (wpwr VOB) for unified code base*//*DESCRIPTIONrdiscLib contains code to implement ICMP Router Discovery. This featureallows routers to advertise an address to the hosts on each of the routersinterfaces. This address is placed by the host into its route table asa default router. A host may also solicit the address by multicastingthe request to the ALL_ROUTERS address (224.0.0.2), to which a routerwould respond with a unicast version of the advertisement.There are three routines in this implementation of router discovery:rdiscInit(), rdisc() and rdCtl(). rdiscInit() is the initializationroutine, rdisc() handles the periodic transmission of advertisementsand processing of solicitations, and rdCtl() sets/gets user parameters.*/ /* includes */#include "vxWorks.h"#include "rdiscLib.h"#include "stdioLib.h"#include "netLib.h"#include "inetLib.h"#include "sockLib.h"#include "taskLib.h"#include "routeLib.h"#include "wdLib.h"#include "vxLib.h" #include "inetLib.h"#include "string.h"#include "logLib.h"#include "sysLib.h"#include "ioLib.h"#include "math.h"#include "netinet/ip.h"#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/ip_icmp.h"#include "netinet/in_var.h"#ifdef VIRTUAL_STACK#include "netinet/vsLib.h"#include "netinet/vsRdisc.h"#endif /* VIRTUAL_STACK *//* defines */#define INITIAL_DELAY 600#define RDISC_PACKET_SIZE 16/* Defaults for task information */#define RDISC_TASK_PRIORITY 127#define RDISC_TASK_OPTIONS 0#define RDISC_STACK_SIZE 20000/* RFC 1256 values for each interface */struct ifrd { char ifName[8]; struct in_addr NetAddress; struct in_addr AdvertAddress; int subnet; int mask; int AdvertLifetime; int Advertise; int PrefLevel; }; struct rdiscPacket { char type; char code; short checkSum; char numAddrs; char entrySize; short lifeTime; unsigned int rAddr; unsigned int pref; };/* globals */#ifndef VIRTUAL_STACKIMPORT struct ifnet *ifnet; /* list of all network interfaces */IMPORT struct in_ifaddr *in_ifaddr;SEM_ID rdiscIfSem;#endif /* VIRTUAL_STACK *//* locals */#ifndef VIRTUAL_STACKLOCAL WDOG_ID wdId;LOCAL int rdiscSock;LOCAL int terminateFlag = 0;LOCAL BOOL debugFlag = 0;LOCAL int rdiscNumInterfaces=0;LOCAL struct ifrd *pIfDisc=0;LOCAL int MaxAdvertInterval;LOCAL int MinAdvertInterval;#endif /* VIRTUAL_STACK *//* forward declarations */#ifdef VIRTUAL_STACKvoid rdiscTimerEvent (int);#endif /* VIRTUAL_STACK */LOCAL void startWdTimer();/******************************************************************************** rdiscLibInit - Initialize router discovery** This routine links the ICMP Router Discovery facility into the VxWorks system.* The arguments are the task's priority, options and stackSize.** Returns: N/A**/void rdiscLibInit ( int priority, /* Priority of router discovery task. */ int options, /* Options to taskSpawn(1) for router discovery task. */ int stackSize /* Stack size for router discovery task. */ ) { taskSpawn ("tRdisc", priority, options, stackSize, (FUNCPTR) rdisc, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); }/********************************************************************************* rdiscInit - initialize the ICMP router discovery function** This routine allocates resources for the router discovery function. Since it* called in the rdisc() routine, it should not be called subsequently ** Returns: OK on successful initialization, ERROR otherwise**/STATUS rdiscInit() {#ifdef VIRTUAL_STACK terminateFlag = 0; debugFlag = 0; rdiscNumInterfaces=0; pIfDisc=0;#endif /* Create Locking semaphore so we can lock our own interface list. */ if ((rdiscIfSem = semBCreate (SEM_Q_PRIORITY, SEM_FULL)) == NULL) { logMsg ("rdisc could not create if locking semaphore\n", 0, 0, 0, 0, 0, 0); return (ERROR); } /* create RAW socket */ rdiscSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (rdiscSock < 0) { logMsg("could not get raw socket\n",0,0,0,0,0,0); semDelete (rdiscIfSem); return ERROR; } pIfDisc = NULL; if (rdiscIfReset() != OK) { close (rdiscSock); semDelete (rdiscIfSem); return (ERROR); } terminateFlag = 0; return OK; }/********************************************************************************* sendAdvert - send an advertisement to one location** This routine sends a router advertisement using the data stored for its'* corresponding interface. Only the primary network address of the interface* is used as the advertised router address.** Returns: NA**/void sendAdvert ( int index, struct in_addr dstAddr ) { struct rdiscPacket *pRdis = NULL; struct sockaddr_in to; int status; char sndbuf[RDISC_PACKET_SIZE]; if (debugFlag == TRUE) logMsg("advertising %s to %s\n", (int)inet_ntoa((pIfDisc[index].AdvertAddress)), (int)inet_ntoa(dstAddr),0,0,0,0); /* check Advertise enabled flag */ if (pIfDisc[index].Advertise == 0) return; bzero (sndbuf, sizeof (sndbuf)); /* form an advertisement packet */ pRdis = (struct rdiscPacket*)sndbuf; pRdis->type = ICMP_ROUTERADVERT; pRdis->code = 0; pRdis->numAddrs = 1; pRdis->entrySize = 2; pRdis->lifeTime = htons(pIfDisc[index].AdvertLifetime); pRdis->rAddr = (pIfDisc[index].NetAddress.s_addr); pRdis->pref = htonl(pIfDisc[index].PrefLevel); pRdis->checkSum = 0; pRdis->checkSum = checksum((u_short *) pRdis, RDISC_PACKET_SIZE); bzero ((char *)&to, sizeof (to)); to.sin_family = AF_INET; to.sin_len = sizeof(struct sockaddr_in); to.sin_addr.s_addr = (dstAddr.s_addr); /* advertisement destination */ status = sendto(rdiscSock, sndbuf, sizeof(struct rdiscPacket), 0, (struct sockaddr *)&to, sizeof(to)); if (status != sizeof(struct rdiscPacket)) { logMsg("rdisc: corrupt packet, errno = %d\n", errno,0,0,0,0,0); } } /********************************************************************************* sendAdvertAll - send an advertisement to all active locations** This routine sends a router advertisement using the data stored for each* corresponding interface. Only the primary network address of the interface* is used as the advertised router address.** Returns: NA**/void sendAdvertAll() { int i=0; struct in_addr ia; /* Make sure the interface list is not being updated. */ semTake (rdiscIfSem, WAIT_FOREVER); for(i=0; i<rdiscNumInterfaces; i++) { if (pIfDisc[i].Advertise == 0) continue; ia.s_addr = pIfDisc[i].NetAddress.s_addr; setsockopt(rdiscSock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ia, sizeof(struct in_addr)); /* multicast to the selected network */ sendAdvert(i, pIfDisc[i].AdvertAddress); } semGive (rdiscIfSem); }/********************************************************************************* rdiscTimerEvent - called after watchdog timeout** This routine is called when a new advertisement is to be sent. ** Returns: NA**/#ifdef VIRTUAL_STACKvoid rdiscTimerEventRestart ( int stackNum ) { netJobAdd ((FUNCPTR)rdiscTimerEvent, stackNum, 0, 0, 0, 0); }void rdiscTimerEvent ( int stackNum ) { virtualStackNumTaskIdSet(stackNum);#elsevoid rdiscTimerEvent() {#endif /* VIRTUAL_STACK */ sendAdvertAll(); if (terminateFlag != 0) return; startWdTimer(); }/********************************************************************************* rdisc - implement the ICMP router discovery function** This routine is the entry point for the router discovery function. It* allocates and initializes resources, listens for solicitation messages * on the ALL_ROUTERS (224.0.0.1) multicast address and processes the* messages.** This routine usually runs until explicitly killed by a system operator, but* can also be terminated cleanly (see rdCtl() routine).** Returns: NA**/void rdisc () { int i; int status; char recvBuff[128]; struct sockaddr from; int FromLen; struct ip *pIp; struct rdiscPacket *rdp; short checkSum; status = rdiscInit(); if (status == ERROR) { logMsg("rdisc: could not initialize router discovery\n", 0,0,0,0,0,0); return; } /* receive buffer IP packet */ pIp = (struct ip * )recvBuff; /* receive buffer ICMP route discovery packet */ rdp = (struct rdiscPacket *)&recvBuff[20]; /* create WatchDog timer */ wdId = wdCreate(); sendAdvertAll();#ifdef VIRTUAL_STACK status = wdStart(wdId, INITIAL_DELAY, (FUNCPTR) rdiscTimerEventRestart, (int) myStackNum);#else status = wdStart(wdId, INITIAL_DELAY, netJobAdd, (int)rdiscTimerEvent );#endif /* VIRTUAL_STACK */ if (status == ERROR) { logMsg("rdisc: error starting watchdog timer: %d\n", errno,0,0,0,0,0); } while (terminateFlag == 0) { if (debugFlag == TRUE) logMsg("rdisc: Waiting for solicitation...\n",0,0,0,0,0,0); status = recvfrom(rdiscSock, recvBuff, 100, 0, (struct sockaddr *)&from, &FromLen); if (status < 0) { logMsg("error in recvfrom returns %d, errno is %d exiting\n", status, errno, 0,0,0,0); rdCtl (NULL, SET_MODE, (void*)MODE_STOP); return; } if (pIp->ip_len < 8) /* verify IP packet length */ { logMsg("rdisc: packet too short, %d bytes\n", pIp->ip_len * 4, 0,0,0,0,0); continue; } if (rdp->code != 0) /* ICMP code */ { logMsg("rdisc: wrong code: %d\n", rdp->code, 0,0,0,0,0); continue; } if (rdp->type == 10) /* solicitation message */ { /* NEED to check source address here per RFC */ if (debugFlag == TRUE) logMsg("rdisc: received solicitation from src addr is %s\n", (int)inet_ntoa(pIp->ip_src), 0,0,0,0,0); /* verify checksum */ checkSum = rdp->checkSum; rdp->checkSum = 0; if ((u_short)checkSum != (u_short)checksum((u_short *) rdp, 8)) { logMsg ("checksum error: %d != %d\n" , (u_short)checkSum , (u_short)checksum((u_short *) rdp,8), 0,0,0,0); continue; } /* Check the interface list lock. */ semTake (rdiscIfSem, WAIT_FOREVER); /* find the matching interface */ for(i = 0; i < rdiscNumInterfaces; i++) { if (pIfDisc[i].subnet == (htonl(pIp->ip_src.s_addr) & pIfDisc[i].mask)) break; } /* Check for a match. */ if (i < rdiscNumInterfaces) sendAdvert(i, pIp->ip_src); semGive (rdiscIfSem); } else { if (rdp->type == 9) { if (debugFlag == TRUE) logMsg("received router advertisement from %s\n", (int)inet_ntoa(pIp->ip_src),0,0,0,0,0); } } } if (pIfDisc != NULL) free((char *)pIfDisc); wdCancel(wdId); close(rdiscSock); }/********************************************************************************* restartWdTimer - called at various place when the rdisc timer has to be* (re-) started** This routine calculates the new interval and starts the rdisc timer.** Returns: NA**/LOCAL void startWdTimer() { int interval = MinAdvertInterval+ (rand()%(MaxAdvertInterval-MinAdvertInterval)); interval *= sysClkRateGet();#ifdef VIRTUAL_STACK wdStart(wdId, interval, (FUNCPTR)rdiscTimerEventRestart, (int) myStackNum);#else wdStart(wdId, interval, netJobAdd, (int)rdiscTimerEvent);#endif /* VIRTUAL_STACK */ }/********************************************************************************* searchInterface - search interface in local database*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -