rdiscLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:26k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* rdiscLib.c - ICMP router discovery server library */
  2. /* Copyright 1984 - 2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h" 
  4. /*
  5. modification history
  6. --------------------
  7. 01a,29mar01,spm  file creation: copied from version 01g of tor2_0.open_stack
  8.                  branch (wpwr VOB) for unified code base
  9. */
  10. /*
  11. DESCRIPTION
  12. rdiscLib contains code to implement ICMP Router Discovery. This feature
  13. allows routers to advertise an address to the hosts on each of the routers
  14. interfaces.  This address is placed by the host into its route table as
  15. a default router.  A host may also solicit the address by multicasting
  16. the request to the ALL_ROUTERS address (224.0.0.2), to which a router
  17. would respond with a unicast version of the advertisement.
  18. There are three routines in this implementation of router discovery:
  19. rdiscInit(), rdisc() and rdCtl().  rdiscInit() is the initialization
  20. routine, rdisc() handles the periodic transmission of advertisements
  21. and processing of solicitations, and rdCtl() sets/gets user parameters.
  22. */
  23.  
  24. /* includes */
  25. #include "vxWorks.h"
  26. #include "rdiscLib.h"
  27. #include "stdioLib.h"
  28. #include "netLib.h"
  29. #include "inetLib.h"
  30. #include "sockLib.h"
  31. #include "taskLib.h"
  32. #include "routeLib.h"
  33. #include "wdLib.h"
  34. #include "vxLib.h"   
  35. #include "inetLib.h"
  36. #include "string.h"
  37. #include "logLib.h"
  38. #include "sysLib.h"
  39. #include "ioLib.h"
  40. #include "math.h"
  41. #include "netinet/ip.h"
  42. #include "netinet/in.h"
  43. #include "netinet/in_systm.h"
  44. #include "netinet/ip_icmp.h"
  45. #include "netinet/in_var.h"
  46. #ifdef VIRTUAL_STACK
  47. #include "netinet/vsLib.h"
  48. #include "netinet/vsRdisc.h"
  49. #endif /* VIRTUAL_STACK */
  50. /* defines */
  51. #define INITIAL_DELAY 600
  52. #define RDISC_PACKET_SIZE 16
  53. /* Defaults for task information */
  54. #define RDISC_TASK_PRIORITY 127
  55. #define RDISC_TASK_OPTIONS 0
  56. #define RDISC_STACK_SIZE 20000
  57. /* RFC 1256 values for each interface */
  58. struct ifrd
  59.     {
  60.     char ifName[8];
  61.     struct in_addr NetAddress;
  62.     struct in_addr AdvertAddress;
  63.     int subnet;
  64.     int mask;
  65.     int AdvertLifetime;
  66.     int Advertise;
  67.     int PrefLevel;
  68.     };
  69.     
  70. struct rdiscPacket
  71.     {
  72.     char type;
  73.     char code;
  74.     short checkSum;
  75.     char numAddrs;
  76.     char entrySize;
  77.     short lifeTime;
  78.     unsigned int rAddr;
  79.     unsigned int pref;
  80.     };
  81. /* globals */
  82. #ifndef VIRTUAL_STACK
  83. IMPORT struct ifnet     *ifnet;         /* list of all network interfaces */
  84. IMPORT struct in_ifaddr    *in_ifaddr;
  85. SEM_ID rdiscIfSem;
  86. #endif  /* VIRTUAL_STACK */
  87. /* locals */
  88. #ifndef VIRTUAL_STACK
  89. LOCAL WDOG_ID wdId;
  90. LOCAL int rdiscSock;
  91. LOCAL int terminateFlag = 0;
  92. LOCAL BOOL debugFlag = 0;
  93. LOCAL int rdiscNumInterfaces=0;
  94. LOCAL struct ifrd *pIfDisc=0;
  95. LOCAL int MaxAdvertInterval;
  96. LOCAL int MinAdvertInterval;
  97. #endif /* VIRTUAL_STACK */
  98. /* forward declarations */
  99. #ifdef VIRTUAL_STACK
  100. void rdiscTimerEvent (int);
  101. #endif /* VIRTUAL_STACK */
  102. LOCAL void startWdTimer();
  103. /******************************************************************************
  104. *
  105. * rdiscLibInit - Initialize router discovery
  106. *
  107. * This routine links the ICMP Router Discovery facility into the VxWorks system.
  108. * The arguments are the task's priority, options and stackSize.
  109. *
  110. * Returns: N/A
  111. *
  112. */
  113. void rdiscLibInit
  114.     (
  115.     int priority, /* Priority of router discovery task. */
  116.     int options, /* Options to taskSpawn(1) for router discovery task. */
  117.     int stackSize /* Stack size for router discovery task. */
  118.     )
  119.     {
  120.     taskSpawn ("tRdisc", priority, options, stackSize,
  121.                (FUNCPTR) rdisc, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
  122.     }
  123. /*******************************************************************************
  124. *
  125. * rdiscInit - initialize the ICMP router discovery function
  126. *
  127. * This routine allocates resources for the router discovery function. Since it
  128. * called in the rdisc() routine, it should not be called subsequently 
  129. *
  130. * Returns: OK on successful initialization, ERROR otherwise
  131. *
  132. */
  133. STATUS rdiscInit()
  134.     {
  135. #ifdef VIRTUAL_STACK
  136.     terminateFlag = 0;
  137.     debugFlag = 0;
  138.     rdiscNumInterfaces=0;
  139.     pIfDisc=0;
  140. #endif
  141.     /* Create Locking semaphore so we can lock our own interface list. */
  142.     if ((rdiscIfSem = semBCreate (SEM_Q_PRIORITY, SEM_FULL)) == NULL)
  143.         {
  144.         logMsg ("rdisc could not create if locking semaphoren",
  145.                 0, 0, 0, 0, 0, 0);
  146.         return (ERROR);
  147.         }
  148.           
  149.     /* create RAW socket */
  150.     rdiscSock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  151.     if (rdiscSock < 0)
  152.         {
  153.         logMsg("could not get raw socketn",0,0,0,0,0,0);
  154.         semDelete (rdiscIfSem);
  155.         return ERROR;
  156.         }
  157.     pIfDisc = NULL;
  158.     if (rdiscIfReset() != OK)
  159.         {
  160.         close (rdiscSock);
  161.         semDelete (rdiscIfSem);
  162.         return (ERROR);
  163.         }
  164.     terminateFlag = 0;
  165.     return OK;
  166.     }
  167. /*******************************************************************************
  168. *
  169. * sendAdvert - send an advertisement to one location
  170. *
  171. * This routine sends a router advertisement using the data stored for its'
  172. * corresponding interface.  Only the primary network address of the interface
  173. * is used as the advertised router address.
  174. *
  175. * Returns: NA
  176. *
  177. */
  178. void sendAdvert
  179.     (
  180.     int index,
  181.     struct in_addr dstAddr
  182.     )
  183.     {
  184.     struct rdiscPacket *pRdis = NULL;
  185.     struct sockaddr_in to;
  186.     int status;
  187.     char sndbuf[RDISC_PACKET_SIZE];
  188.     if (debugFlag == TRUE)
  189.         logMsg("advertising %s to %sn", 
  190.               (int)inet_ntoa((pIfDisc[index].AdvertAddress)), 
  191. (int)inet_ntoa(dstAddr),0,0,0,0);
  192.     /* check Advertise enabled flag */
  193.     if (pIfDisc[index].Advertise == 0)
  194. return;
  195.     bzero (sndbuf, sizeof (sndbuf));
  196.     /* form an advertisement packet */
  197.     pRdis = (struct rdiscPacket*)sndbuf;
  198.     pRdis->type = ICMP_ROUTERADVERT;
  199.     pRdis->code = 0;
  200.     pRdis->numAddrs = 1;
  201.     pRdis->entrySize = 2;
  202.     pRdis->lifeTime = htons(pIfDisc[index].AdvertLifetime);
  203.     pRdis->rAddr = (pIfDisc[index].NetAddress.s_addr); 
  204.     pRdis->pref = htonl(pIfDisc[index].PrefLevel); 
  205.     pRdis->checkSum = 0;
  206.     pRdis->checkSum = checksum((u_short *) pRdis, RDISC_PACKET_SIZE);
  207.     bzero ((char *)&to, sizeof (to));
  208.     to.sin_family = AF_INET;
  209.     to.sin_len = sizeof(struct sockaddr_in);
  210.     to.sin_addr.s_addr = (dstAddr.s_addr);  /* advertisement destination */ 
  211.     status = sendto(rdiscSock, sndbuf, sizeof(struct rdiscPacket),
  212.                     0, (struct sockaddr *)&to, sizeof(to));
  213.     if (status != sizeof(struct rdiscPacket))
  214.         {
  215.         logMsg("rdisc: corrupt packet, errno = %dn", 
  216. errno,0,0,0,0,0);
  217.         }
  218.     } 
  219. /*******************************************************************************
  220. *
  221. * sendAdvertAll - send an advertisement to all active locations
  222. *
  223. * This routine sends a router advertisement using the data stored for each
  224. * corresponding interface.  Only the primary network address of the interface
  225. * is used as the advertised router address.
  226. *
  227. * Returns: NA
  228. *
  229. */
  230. void sendAdvertAll()
  231.     {
  232.     int i=0;
  233.     struct in_addr ia;
  234.     /* Make sure the interface list is not being updated. */
  235.     semTake (rdiscIfSem, WAIT_FOREVER);
  236.     for(i=0; i<rdiscNumInterfaces; i++)
  237. {
  238.         if (pIfDisc[i].Advertise == 0)
  239.     continue; 
  240.         ia.s_addr = pIfDisc[i].NetAddress.s_addr;   
  241. setsockopt(rdiscSock, IPPROTO_IP, IP_MULTICAST_IF, 
  242.    (char *)&ia, sizeof(struct in_addr));
  243. /* multicast to the selected network */ 
  244.         sendAdvert(i, pIfDisc[i].AdvertAddress);
  245.         }
  246.     semGive (rdiscIfSem);
  247.     }
  248. /*******************************************************************************
  249. *
  250. * rdiscTimerEvent - called after watchdog timeout
  251. *
  252. * This routine is called when a new advertisement is to be sent. 
  253. *
  254. * Returns: NA
  255. *
  256. */
  257. #ifdef VIRTUAL_STACK
  258. void rdiscTimerEventRestart
  259.     (
  260.     int stackNum
  261.     )
  262.     {
  263.     netJobAdd ((FUNCPTR)rdiscTimerEvent, stackNum, 0, 0, 0, 0);
  264.     }
  265. void rdiscTimerEvent
  266.     (
  267.     int stackNum
  268.     )
  269.     {
  270.     virtualStackNumTaskIdSet(stackNum);
  271. #else
  272. void rdiscTimerEvent()
  273.     {
  274. #endif /* VIRTUAL_STACK */
  275.     sendAdvertAll();
  276.    
  277.     if (terminateFlag != 0)
  278. return;
  279.     startWdTimer();
  280.     }
  281. /*******************************************************************************
  282. *
  283. * rdisc - implement the ICMP router discovery function
  284. *
  285. * This routine is the entry point for the router discovery function.  It
  286. * allocates and initializes resources, listens for solicitation messages 
  287. * on the ALL_ROUTERS (224.0.0.1) multicast address and processes the
  288. * messages.
  289. *
  290. * This routine usually runs until explicitly killed by a system operator, but
  291. * can also be terminated cleanly (see rdCtl() routine).
  292. *
  293. * Returns: NA
  294. *
  295. */
  296. void rdisc ()
  297.     {
  298.     int  i;
  299.     int status;
  300.     char recvBuff[128];
  301.     struct sockaddr from;
  302.     int FromLen;
  303.     struct ip *pIp;
  304.     struct rdiscPacket *rdp;
  305.     short checkSum;
  306.     status = rdiscInit();
  307.     if (status == ERROR)
  308.         {
  309.         logMsg("rdisc: could not initialize router discoveryn", 0,0,0,0,0,0);
  310. return;
  311.         }
  312.     /* receive buffer IP packet */
  313.     pIp = (struct ip * )recvBuff;
  314.     /* receive buffer ICMP route discovery packet */
  315.     rdp = (struct rdiscPacket *)&recvBuff[20];
  316.     /* create WatchDog timer */
  317.     wdId = wdCreate();
  318.     sendAdvertAll();
  319. #ifdef VIRTUAL_STACK
  320.     status = wdStart(wdId, INITIAL_DELAY, (FUNCPTR) rdiscTimerEventRestart,
  321.                      (int) myStackNum);
  322. #else
  323.     status = wdStart(wdId, INITIAL_DELAY, netJobAdd, (int)rdiscTimerEvent );
  324. #endif /* VIRTUAL_STACK */
  325.     if (status == ERROR) 
  326. {
  327. logMsg("rdisc: error starting watchdog timer: %dn", errno,0,0,0,0,0);
  328.         }
  329.     while (terminateFlag == 0)
  330. {
  331.         if (debugFlag == TRUE)
  332.     logMsg("rdisc: Waiting for solicitation...n",0,0,0,0,0,0);
  333.         status = recvfrom(rdiscSock, recvBuff, 100, 0,
  334.  (struct sockaddr *)&from, &FromLen);
  335.         if (status < 0)
  336.     {
  337.             logMsg("error in recvfrom returns %d, errno is %d exitingn", 
  338. status, errno, 0,0,0,0);
  339.             rdCtl (NULL, SET_MODE, (void*)MODE_STOP);
  340.             return;
  341.             }
  342. if (pIp->ip_len < 8)   /* verify IP packet length */
  343.     {
  344.             logMsg("rdisc: packet too short, %d bytesn", 
  345.                    pIp->ip_len * 4, 0,0,0,0,0);
  346.     continue;
  347.     }
  348. if (rdp->code != 0) /* ICMP code */
  349.     {
  350.             logMsg("rdisc: wrong code: %dn", rdp->code, 0,0,0,0,0);
  351.     continue;
  352.     }
  353.         if (rdp->type == 10) /* solicitation message */
  354.     {
  355.     /* NEED to check source address here per RFC */
  356.             if (debugFlag == TRUE)
  357. logMsg("rdisc: received solicitation from src addr is %sn", 
  358.         (int)inet_ntoa(pIp->ip_src), 0,0,0,0,0);
  359.     
  360.     /* verify checksum */
  361.             checkSum = rdp->checkSum;
  362.             rdp->checkSum = 0;
  363.          if ((u_short)checkSum != (u_short)checksum((u_short *) rdp, 8))
  364. {
  365.         logMsg ("checksum error: %d != %dn" , (u_short)checkSum , 
  366. (u_short)checksum((u_short *) rdp,8), 0,0,0,0);
  367.         continue;
  368.         }
  369.             /* Check the interface list lock. */
  370.             semTake (rdiscIfSem, WAIT_FOREVER);
  371.     /* find the matching interface */
  372.     for(i = 0; i < rdiscNumInterfaces; i++)
  373.                 {
  374. if (pIfDisc[i].subnet == (htonl(pIp->ip_src.s_addr) & 
  375. pIfDisc[i].mask))
  376.    break;
  377. }
  378.             /* Check for a match. */
  379.             if (i < rdiscNumInterfaces)
  380.                 sendAdvert(i, pIp->ip_src);
  381.             semGive (rdiscIfSem);
  382.             }
  383.         else
  384.             {
  385.             if (rdp->type == 9)
  386.                 {
  387.                 if (debugFlag == TRUE)
  388.                     logMsg("received router advertisement from %sn", 
  389.                            (int)inet_ntoa(pIp->ip_src),0,0,0,0,0); 
  390.                 }
  391.             }
  392.         }
  393.     
  394.     if (pIfDisc != NULL)
  395.         free((char *)pIfDisc);
  396.     wdCancel(wdId);
  397.     close(rdiscSock);
  398.     }
  399. /*******************************************************************************
  400. *
  401. * restartWdTimer - called at various place when the rdisc timer has to be
  402. *    (re-) started
  403. *
  404. * This routine calculates the new interval and starts the rdisc timer.
  405. *
  406. * Returns: NA
  407. *
  408. */
  409. LOCAL void startWdTimer()
  410.     {
  411.     int interval = MinAdvertInterval+
  412.                 (rand()%(MaxAdvertInterval-MinAdvertInterval));
  413.     interval *= sysClkRateGet();
  414. #ifdef VIRTUAL_STACK
  415.     wdStart(wdId, interval, (FUNCPTR)rdiscTimerEventRestart, (int) myStackNum);
  416. #else
  417.     wdStart(wdId, interval, netJobAdd, (int)rdiscTimerEvent);
  418. #endif /* VIRTUAL_STACK */
  419.     }
  420. /*******************************************************************************
  421. *
  422. * searchInterface - search interface in local database
  423. *
  424. * Is called in rdCtl to verify the input parameter
  425. *
  426. * Returns: pointer to valid interface if successfull, else NULL
  427. *
  428. */
  429. LOCAL struct ifrd* searchInterface(const char* ifName){
  430.     struct ifrd* t = pIfDisc;
  431.     int index;
  432.     
  433.     /* find matching RD interface */ 
  434.     if (NULL == ifName){
  435.      logMsg("rdCtl: no interface specifiedn",1,2,3,4,5,6);
  436. return NULL;
  437.     }
  438.     for( index=0; index < rdiscNumInterfaces ; index++)
  439.         {
  440.         if( strcmp(t[index].ifName, ifName) == 0)
  441.                 break;
  442.         }
  443.     if (index == rdiscNumInterfaces)
  444.         {
  445. logMsg("rdCtl: could not find interface %sn", (int)ifName,2,3,4,5,6);
  446.         return NULL;
  447.         }
  448.     return &t[index];    
  449.     }
  450. /*******************************************************************************
  451. *
  452. * returnFromRdCtl - central return from rdCtl function
  453. *
  454. * gives the central semaphore before returning from rdCtl
  455. *
  456. * Returns: STATUS which is passed is parameter
  457. *
  458. */
  459. LOCAL STATUS returnFromRdCtl(STATUS retVal)
  460.     {
  461.     semGive (rdiscIfSem);
  462.     return retVal;
  463.     }
  464. /*******************************************************************************
  465. *
  466. * rdCtl - implement the ICMP router discovery control function 
  467. *
  468. * This routine allows a user to get and set router discovery parameters, and
  469. * control the mode of operation.  
  470. *
  471. * OPTIONS
  472. * The following section discuss the various flags that may be passed
  473. * to rdCtl().
  474. *
  475. * .SS "SET_MODE -- Set debug mode or exit router discovery"
  476. * This flag does not require an <interface> to be specified
  477. * it is best to specify NULL.
  478. *
  479. * This flag is used in conjunction with the following values:
  480. *
  481. * .SS "MODE_DEBUG_ON -- Turn debugging messages on. "
  482. * .CS
  483. *     rdCtl (NULL, SET_MODE, MODE_DEBUG_ON);
  484. * .CE
  485. *
  486. * .SS "MODE_DEBUG_OFF -- Turn debugging messages off."
  487. *
  488. * .CS
  489. *     rdCtl (NULL, SET_MODE, MODE_DEBUG_OFF);
  490. * .CE
  491. *
  492. * .SS "MODE_STOP -- Exit from router discovery."
  493. *
  494. * .CS
  495. *     rdCtl (NULL, SET_MODE, MODE_STOP);
  496. * .CE
  497. *
  498. * .SS "SET_MIN_ADVERT_INT -- set minimum advertisement interval in seconds"
  499. * Specify the minimum time between advertisements in seconds.  The minimum
  500. * value allowed is 4 seconds, the maximum is 1800.
  501. *
  502. * .CS
  503. *     rdCtl (NULL, SET_MIN_ADVERT_INT, <seconds>);
  504. * .CE
  505. *
  506. * .SS "SET_MAX_ADVERT_INT -- set maximum advertisement interval in seconds"
  507. * Specify the maximum time between advertisements in seconds.  The minimum
  508. * value allowed is 4 seconds, the maximum is 1800.
  509. *
  510. * .CS
  511. *     rdCtl (NULL, SET_MAX_ADVERT_INT, <seconds>);
  512. * .CE
  513. *
  514. * .SS "SET_FLAG -- Set whether advertisements are sent on an interface."
  515. * If this flag is 1 then advertisements are sent on this interface.  
  516. * If it is 0 then they are not.
  517. *
  518. * .CS
  519. *    rdCtl (<interface>, SET_FLAG, <0 or 1>);
  520. * .CE
  521. *
  522. * .SS "SET_ADVERT_ADDRESS -- Set the IP address to which advertisements are sent. "
  523. *  Set the multicast IP address to which advertisements are sent.
  524. *
  525. * .CS
  526. *    rdCtl (<interface>, SET_ADVERT_ADDRESS, <multicast address>);
  527. * .CE
  528. *
  529. * .SS "SET_ADVERT_LIFETIME -- Set the lifetime for advertisements in seconds. "
  530. * Set the lifetime in seconds to be contained in each advertisement.
  531. *
  532. * .CS
  533. *    rdCtl (<interface>, SET_ADVERT_LIFETIME, seconds);
  534. * .CE
  535. *
  536. * .SS "SET_ADVERT_PREF -- Set the preference level contained in advertisements."
  537. * Set the preference level contained in advertisements.
  538. *
  539. * .CS
  540. *    rdCtl (<interface>, SET_ADVERT_PREF, value);
  541. * .CE
  542. *
  543. * .SS "GET_MIN_ADVERT_INT -- Get the minimum advertisement interval. "
  544. * .CS
  545. *    rdCtl (NULL, GET_MIN_ADVERT_INT, &value);
  546. * .CE
  547. *
  548. * .SS "GET_MAX_ADVERT_INT -- Get the maximum advertisement interval. "
  549. * .CS
  550. *    rdCtl (NULL, GET_MAX_ADVERT_INT, &value);
  551. * .CE
  552. *
  553. * .SS "GET_FLAG -- Get the flag on an interface.. "
  554. * .CS
  555. *    rdCtl (<interface>, GET_FLAG, &value);
  556. * .CE
  557. *
  558. * .SS "GET_ADVERT_ADDRESS -- Get the advertisement address for an interface. "
  559. * .CS
  560. *    rdCtl (<interface>, GET_ADVERT_ADDRESS, &value);
  561. * .CE
  562. *
  563. * .SS "GET_ADVERT_LIFETIME -- Get the advertisement lifetime. "
  564. * .CS
  565. *    rdCtl (<interface>, GET_ADVERT_LIFETIME, &value);
  566. * .CE
  567. *
  568. * .SS "GET_ADVERT_PREF -- Get the advertisement preference. "
  569. * .CS
  570. *    rdCtl (<interface>, GET_ADVERT_PREF, value);
  571. * .CE
  572. *
  573. * Returns: OK on success, ERROR on failure
  574. *
  575. */
  576. STATUS rdCtl
  577.     (
  578.     char *ifName, 
  579.     int cmd, 
  580.     void* value /* my be an int (set-cmds) or an int* (get-cmds) */
  581.     )
  582.     {
  583.     
  584.     /* Check the interface list lock. */
  585.     semTake (rdiscIfSem, WAIT_FOREVER);
  586.     /* execute command */
  587.     
  588.     switch(cmd)
  589. {
  590.         
  591. case SET_MODE:
  592.             if ((int)value == MODE_DEBUG_OFF)
  593.                 {
  594.                 logMsg("rdisc: debug mode offn",0,0,0,0,0,0);
  595.                 debugFlag = 0;
  596.                 }
  597.             else
  598.                 {
  599. if ((int)value == MODE_DEBUG_ON)
  600.     {
  601.     logMsg("rdisc: debug mode onn",0,0,0,0,0,0);
  602.     debugFlag = 1;
  603.     }
  604. else 
  605.                     {
  606.                     if ((int)value == MODE_STOP)
  607.                         {
  608. int i;
  609.                         logMsg("rdisc: received termination messagen",0,0,0,0,0,0);
  610.                         semGive (rdiscIfSem);
  611.                         terminateFlag = 1;
  612.                         for(i=0; i<rdiscNumInterfaces; i++)
  613.                             pIfDisc[i].AdvertLifetime = 0;
  614.                         sendAdvertAll(); /* recvfrom is blocked */
  615.                         }
  616.                     }
  617.                 }
  618.             break;
  619.             
  620. case SET_MIN_ADVERT_INT:
  621.     {
  622.     int numSeconds = (int)value;
  623.             if ((numSeconds < 4) || 
  624.                 (numSeconds > 1800) || 
  625.                 (numSeconds >= MaxAdvertInterval))
  626.                 {
  627.                 return returnFromRdCtl(ERROR);
  628.                 }
  629.             MinAdvertInterval = numSeconds;
  630.             
  631.             wdCancel(wdId);
  632.             startWdTimer();
  633.     }
  634.             break;
  635.             
  636. case SET_MAX_ADVERT_INT:
  637.     {
  638.     int numSeconds = (int)value;
  639.             if ((numSeconds < 4) || 
  640.                 (numSeconds > 1800) || 
  641.                 (numSeconds <= MinAdvertInterval))
  642.                 {
  643.                 return returnFromRdCtl(ERROR);
  644.                 }
  645.             MaxAdvertInterval = numSeconds;
  646.             
  647.             wdCancel(wdId);
  648.             startWdTimer();
  649.     }
  650.             break;
  651.             
  652. case SET_FLAG:
  653.     {
  654.     struct ifrd* interface = searchInterface(ifName);
  655.     if (0 == interface)
  656.      return returnFromRdCtl(ERROR);
  657.             interface->Advertise = (int)value ? 1:0 ;
  658.     }
  659.             break;
  660.             
  661. case SET_ADVERT_ADDRESS:
  662.     {
  663.     struct ifrd* interface = searchInterface(ifName);
  664.     if (0 == interface)
  665.      return returnFromRdCtl(ERROR);
  666.             if ((int)value == INADDR_BROADCAST)
  667.                 {
  668.                 if (debugFlag == TRUE)
  669.                     logMsg ("rdisc broadcast not yet supported%dn",
  670.                             1, 2, 3, 4, 5, 6);
  671.                 return returnFromRdCtl(ERROR);
  672.                 }
  673.             interface->AdvertAddress.s_addr = (int)value;
  674.     }
  675.             break;
  676.             
  677. case SET_ADVERT_LIFETIME:
  678.     {
  679.     int numSeconds = (int)value;
  680.     struct ifrd* interface = searchInterface(ifName);
  681.     if (0 == interface)
  682.      return returnFromRdCtl(ERROR);
  683.             if ((numSeconds < MaxAdvertInterval) ||
  684.                 (numSeconds > 9000))
  685.                 {
  686.                 return returnFromRdCtl(ERROR);
  687.                 }
  688.             interface->AdvertLifetime = numSeconds;
  689.     }
  690.             break;
  691.             
  692. case SET_ADVERT_PREF:
  693.     {
  694.     struct ifrd* interface = searchInterface(ifName);
  695.     if (0 == interface)
  696.      return returnFromRdCtl(ERROR);
  697.             interface->PrefLevel = (int)value;
  698.     }
  699.             break;
  700.             
  701.         case GET_MIN_ADVERT_INT:
  702.     {
  703.     int* intPtr = (int *)value;
  704.             *intPtr = MinAdvertInterval ;
  705.     }
  706.             break;
  707.             
  708.         case GET_MAX_ADVERT_INT:
  709.     {
  710.     int* intPtr = (int *)value;
  711.             *intPtr = MaxAdvertInterval;
  712.     }
  713.             break;
  714.             
  715.         case GET_FLAG:
  716.     {
  717.     struct ifrd* interface = searchInterface(ifName);
  718.     int* intPtr = (int *)value;
  719.     if (0 == interface)
  720.      return returnFromRdCtl(ERROR);
  721.             *intPtr = interface->Advertise;
  722.     }
  723.             break;
  724.             
  725.         case GET_ADVERT_ADDRESS:
  726.     {
  727.     struct ifrd* interface = searchInterface(ifName);
  728.     int* intPtr = (int *)value;
  729.     if (0 == interface)
  730.      return returnFromRdCtl(ERROR);
  731.             *intPtr = interface->AdvertAddress.s_addr;
  732.     }
  733.             break;
  734.             
  735.         case GET_ADVERT_LIFETIME:
  736.     {
  737.     struct ifrd* interface = searchInterface(ifName);
  738.     int* intPtr = (int *)value;
  739.     if (0 == interface)
  740.      return returnFromRdCtl(ERROR);
  741.             *intPtr = interface->AdvertLifetime;
  742.     }
  743.             break;
  744.             
  745.         case GET_ADVERT_PREF:
  746.     {
  747.     struct ifrd* interface = searchInterface(ifName);
  748.     int* intPtr = (int *)value;
  749.     if (0 == interface)
  750.      return returnFromRdCtl(ERROR);
  751.             *intPtr = interface->PrefLevel;
  752.     }
  753.             break;
  754.             
  755. default:
  756.     logMsg("rdCtl: illegal cmd %dn",cmd,2,3,4,5,6);
  757.             return returnFromRdCtl(ERROR);
  758.         }
  759.     
  760.     return returnFromRdCtl(OK) ;
  761.     
  762.     }
  763. /******************************************************************************
  764. *
  765. * rdiscIfReset - check for new or removed interfaces for router discovery
  766. *
  767. * This routine MUST be called any time an interface is added to or removed
  768. * from the system so that the router discovery code can deal with this
  769. * case.  Failure to do so will cause the sending of packets on missing
  770. * interfaces to fail as well as no transmission of packets on new interfaces.
  771. *
  772. */
  773. STATUS rdiscIfReset ()
  774.     {
  775.     
  776.     struct in_ifaddr *ia = NULL;
  777.     int i;
  778.     int status;
  779.     struct ifnet *ifp=NULL;
  780.     struct ifaddr *ifa=NULL;
  781.     char *t=NULL;
  782.     struct sockaddr_in *tt=0;
  783.     struct ip_mreq ipMreq;
  784.     struct ifrd *pTmp=NULL;
  785.     /* Take the lock. */
  786.     semTake (rdiscIfSem, WAIT_FOREVER);
  787.     
  788.     /* If we had an old list then free it. */
  789.     if (pIfDisc != NULL)
  790.         {
  791.         /* First drop the multicast stuff on all interfaces. */
  792.         for(i = 0; i < rdiscNumInterfaces; i++)
  793.             {
  794.             pTmp = &pIfDisc[i];
  795.             /* drop multicast membership for this IF */
  796.             ipMreq.imr_multiaddr.s_addr = htonl(0xe0000002); 
  797.             ipMreq.imr_interface.s_addr = pTmp->NetAddress.s_addr; 
  798.             /*
  799.              * The reason we DON'T check the return status here
  800.              * is that if we did and the interface has been removed
  801.              * then we what would we do?  This is a best effort
  802.              * attempt to do remove the multicast address from
  803.              * all UP interfaces, an interface that is missing
  804.              * will simply return ERROR which is OK in this case.
  805.              */
  806.             setsockopt(rdiscSock, IPPROTO_IP,IP_DROP_MEMBERSHIP, 
  807.                        (char *)&ipMreq, sizeof(ipMreq));
  808.             }
  809.         free (pIfDisc);
  810.         }
  811.     /* count interfaces for discovery */ 
  812. #ifdef VIRTUAL_STACK
  813.     for(ifp = _ifnet, i=0; ifp != 0; ifp = ifp->if_next)
  814. #else
  815.     for(ifp = ifnet, i=0; ifp != 0; ifp = ifp->if_next)
  816. #endif
  817.         {
  818. /* reject unwanted interfaces */
  819.         if (!(ifp->if_flags & IFF_MULTICAST)) 
  820.             continue;
  821. if (strcmp(ifp->if_name, "lo") == 0) 
  822.    continue;
  823. i++;
  824.         }
  825.     rdiscNumInterfaces = i;
  826.     t = malloc(sizeof(struct ifrd) * rdiscNumInterfaces);
  827.     if (t == NULL)
  828.         {
  829.         logMsg("rdiscIfReset: error allocating memoryn",0,0,0,0,0,0);
  830.         semGive (rdiscIfSem);
  831.         rdiscNumInterfaces = 0; /* So rdCtl won't walk an empty list. */
  832.         rdCtl (NULL, SET_MODE, (void*)MODE_STOP);
  833. return ERROR;
  834. }
  835.     bzero(t, sizeof(struct ifrd) * rdiscNumInterfaces);
  836.     /* set global to head of list */
  837.     pIfDisc = (struct ifrd *)t;
  838.     /* set each interface for discovery */ 
  839. #ifdef VIRTUAL_STACK
  840.     for(ifp = _ifnet, i=0; ifp != 0; ifp = ifp->if_next)
  841. #else
  842.     for(ifp = ifnet, i=0; ifp != 0; ifp = ifp->if_next)
  843. #endif
  844. {
  845. /* reject unwanted interfaces */
  846.         if (!(ifp->if_flags & IFF_MULTICAST)) 
  847.             continue;
  848. if (strcmp(ifp->if_name, "lo") == 0) 
  849.    continue;
  850.         for (ifa = ifp->if_addrlist;  ifa != NULL;  ifa = ifa->ifa_next)
  851.             {
  852.             if (ifa->ifa_addr->sa_family == AF_INET)
  853.                 {
  854. tt = (struct sockaddr_in *)ifa->ifa_addr;
  855. break;
  856.                 }
  857.             }
  858. /* find subnetmask */
  859. #ifdef VIRTUAL_STACK
  860. for (ia = _in_ifaddr;  ia != NULL;  ia = ia->ia_next)
  861. #else
  862. for (ia = in_ifaddr;  ia != NULL;  ia = ia->ia_next)
  863. #endif
  864.    {
  865.       if (ia->ia_ifp == ifp)
  866.    break;
  867.    }
  868. /* fill in router discovery params for this IF */
  869.         pTmp = &pIfDisc[i];
  870. sprintf(pTmp->ifName,"%s%d", ifp->if_name, ifp->if_unit);
  871.         pTmp->NetAddress.s_addr = tt->sin_addr.s_addr;
  872.         pTmp->AdvertAddress.s_addr = htonl(0xe0000001); 
  873.         pTmp->subnet = ia->ia_subnet;
  874.         pTmp->mask = ia->ia_subnetmask;
  875.         pTmp->AdvertLifetime = 1800;
  876.         pTmp->Advertise = 1;
  877.         pTmp->PrefLevel = 0; 
  878. /* add multicast membership for this IF */
  879.         ipMreq.imr_multiaddr.s_addr = htonl(0xe0000002); 
  880.         ipMreq.imr_interface.s_addr = pTmp->NetAddress.s_addr; 
  881.         status = setsockopt(rdiscSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
  882.             (char *)&ipMreq, sizeof(ipMreq));
  883.         if (status == ERROR)
  884.     {
  885.                 logMsg("rdisc: could not join multicast group, errno is %dn", 
  886. errno,0,0,0,0,0);
  887.                 semGive (rdiscIfSem);
  888.                 rdiscNumInterfaces = 0; /* So rdCtl won't walk a bad list. */
  889.                 rdCtl (NULL, SET_MODE, (void*)MODE_STOP);
  890. return ERROR;
  891.             } 
  892. MaxAdvertInterval = 600; /* max interval in seconds */
  893. MinAdvertInterval = 450; /* max interval in seconds */
  894. i++;
  895.         }
  896.     /* create random number stream per IF address */
  897.     srand((uint_t)pTmp->NetAddress.s_addr);
  898.     semGive (rdiscIfSem);
  899.     
  900.     return (OK);
  901.     }