📄 rdisclib.c
字号:
* Is called in rdCtl to verify the input parameter** Returns: pointer to valid interface if successfull, else NULL**/LOCAL struct ifrd* searchInterface(const char* ifName){ struct ifrd* t = pIfDisc; int index; /* find matching RD interface */ if (NULL == ifName){ logMsg("rdCtl: no interface specified\n",1,2,3,4,5,6); return NULL; } for( index=0; index < rdiscNumInterfaces ; index++) { if( strcmp(t[index].ifName, ifName) == 0) break; } if (index == rdiscNumInterfaces) { logMsg("rdCtl: could not find interface %s\n", (int)ifName,2,3,4,5,6); return NULL; } return &t[index]; }/********************************************************************************* returnFromRdCtl - central return from rdCtl function** gives the central semaphore before returning from rdCtl** Returns: STATUS which is passed is parameter**/LOCAL STATUS returnFromRdCtl(STATUS retVal) { semGive (rdiscIfSem); return retVal; }/********************************************************************************* rdCtl - implement the ICMP router discovery control function ** This routine allows a user to get and set router discovery parameters, and* control the mode of operation. ** OPTIONS* The following section discuss the various flags that may be passed* to rdCtl().** .SS "SET_MODE -- Set debug mode or exit router discovery"* This flag does not require an <interface> to be specified* it is best to specify NULL.** This flag is used in conjunction with the following values:** .SS "MODE_DEBUG_ON -- Turn debugging messages on. "* * .CS* rdCtl (NULL, SET_MODE, MODE_DEBUG_ON);* .CE** .SS "MODE_DEBUG_OFF -- Turn debugging messages off."** .CS* rdCtl (NULL, SET_MODE, MODE_DEBUG_OFF);* .CE** .SS "MODE_STOP -- Exit from router discovery."** .CS* rdCtl (NULL, SET_MODE, MODE_STOP);* .CE** .SS "SET_MIN_ADVERT_INT -- set minimum advertisement interval in seconds"* Specify the minimum time between advertisements in seconds. The minimum* value allowed is 4 seconds, the maximum is 1800.** .CS* rdCtl (NULL, SET_MIN_ADVERT_INT, <seconds>);* .CE** .SS "SET_MAX_ADVERT_INT -- set maximum advertisement interval in seconds"* Specify the maximum time between advertisements in seconds. The minimum* value allowed is 4 seconds, the maximum is 1800.** .CS* rdCtl (NULL, SET_MAX_ADVERT_INT, <seconds>);* .CE** .SS "SET_FLAG -- Set whether advertisements are sent on an interface."* If this flag is 1 then advertisements are sent on this interface. * If it is 0 then they are not.** .CS* rdCtl (<interface>, SET_FLAG, <0 or 1>);* .CE** .SS "SET_ADVERT_ADDRESS -- Set the IP address to which advertisements are sent. "* Set the multicast IP address to which advertisements are sent.** .CS* rdCtl (<interface>, SET_ADVERT_ADDRESS, <multicast address>);* .CE** .SS "SET_ADVERT_LIFETIME -- Set the lifetime for advertisements in seconds. "* Set the lifetime in seconds to be contained in each advertisement.** .CS* rdCtl (<interface>, SET_ADVERT_LIFETIME, seconds);* .CE** .SS "SET_ADVERT_PREF -- Set the preference level contained in advertisements."* Set the preference level contained in advertisements.** .CS* rdCtl (<interface>, SET_ADVERT_PREF, value);* .CE** .SS "GET_MIN_ADVERT_INT -- Get the minimum advertisement interval. "* .CS* rdCtl (NULL, GET_MIN_ADVERT_INT, &value);* .CE** .SS "GET_MAX_ADVERT_INT -- Get the maximum advertisement interval. "* .CS* rdCtl (NULL, GET_MAX_ADVERT_INT, &value);* .CE** .SS "GET_FLAG -- Get the flag on an interface.. "* .CS* rdCtl (<interface>, GET_FLAG, &value);* .CE** .SS "GET_ADVERT_ADDRESS -- Get the advertisement address for an interface. "* .CS* rdCtl (<interface>, GET_ADVERT_ADDRESS, &value);* .CE** .SS "GET_ADVERT_LIFETIME -- Get the advertisement lifetime. "* .CS* rdCtl (<interface>, GET_ADVERT_LIFETIME, &value);* .CE** .SS "GET_ADVERT_PREF -- Get the advertisement preference. "* .CS* rdCtl (<interface>, GET_ADVERT_PREF, value);* .CE** Returns: OK on success, ERROR on failure**/STATUS rdCtl ( char *ifName, int cmd, void* value /* my be an int (set-cmds) or an int* (get-cmds) */ ) { /* Check the interface list lock. */ semTake (rdiscIfSem, WAIT_FOREVER); /* execute command */ switch(cmd) { case SET_MODE: if ((int)value == MODE_DEBUG_OFF) { logMsg("rdisc: debug mode off\n",0,0,0,0,0,0); debugFlag = 0; } else { if ((int)value == MODE_DEBUG_ON) { logMsg("rdisc: debug mode on\n",0,0,0,0,0,0); debugFlag = 1; } else { if ((int)value == MODE_STOP) { int i; logMsg("rdisc: received termination message\n",0,0,0,0,0,0); semGive (rdiscIfSem); terminateFlag = 1; for(i=0; i<rdiscNumInterfaces; i++) pIfDisc[i].AdvertLifetime = 0; sendAdvertAll(); /* recvfrom is blocked */ } } } break; case SET_MIN_ADVERT_INT: { int numSeconds = (int)value; if ((numSeconds < 4) || (numSeconds > 1800) || (numSeconds >= MaxAdvertInterval)) { return returnFromRdCtl(ERROR); } MinAdvertInterval = numSeconds; wdCancel(wdId); startWdTimer(); } break; case SET_MAX_ADVERT_INT: { int numSeconds = (int)value; if ((numSeconds < 4) || (numSeconds > 1800) || (numSeconds <= MinAdvertInterval)) { return returnFromRdCtl(ERROR); } MaxAdvertInterval = numSeconds; wdCancel(wdId); startWdTimer(); } break; case SET_FLAG: { struct ifrd* interface = searchInterface(ifName); if (0 == interface) return returnFromRdCtl(ERROR); interface->Advertise = (int)value ? 1:0 ; } break; case SET_ADVERT_ADDRESS: { struct ifrd* interface = searchInterface(ifName); if (0 == interface) return returnFromRdCtl(ERROR); if ((int)value == INADDR_BROADCAST) { if (debugFlag == TRUE) logMsg ("rdisc broadcast not yet supported%d\n", 1, 2, 3, 4, 5, 6); return returnFromRdCtl(ERROR); } interface->AdvertAddress.s_addr = (int)value; } break; case SET_ADVERT_LIFETIME: { int numSeconds = (int)value; struct ifrd* interface = searchInterface(ifName); if (0 == interface) return returnFromRdCtl(ERROR); if ((numSeconds < MaxAdvertInterval) || (numSeconds > 9000)) { return returnFromRdCtl(ERROR); } interface->AdvertLifetime = numSeconds; } break; case SET_ADVERT_PREF: { struct ifrd* interface = searchInterface(ifName); if (0 == interface) return returnFromRdCtl(ERROR); interface->PrefLevel = (int)value; } break; case GET_MIN_ADVERT_INT: { int* intPtr = (int *)value; *intPtr = MinAdvertInterval ; } break; case GET_MAX_ADVERT_INT: { int* intPtr = (int *)value; *intPtr = MaxAdvertInterval; } break; case GET_FLAG: { struct ifrd* interface = searchInterface(ifName); int* intPtr = (int *)value; if (0 == interface) return returnFromRdCtl(ERROR); *intPtr = interface->Advertise; } break; case GET_ADVERT_ADDRESS: { struct ifrd* interface = searchInterface(ifName); int* intPtr = (int *)value; if (0 == interface) return returnFromRdCtl(ERROR); *intPtr = interface->AdvertAddress.s_addr; } break; case GET_ADVERT_LIFETIME: { struct ifrd* interface = searchInterface(ifName); int* intPtr = (int *)value; if (0 == interface) return returnFromRdCtl(ERROR); *intPtr = interface->AdvertLifetime; } break; case GET_ADVERT_PREF: { struct ifrd* interface = searchInterface(ifName); int* intPtr = (int *)value; if (0 == interface) return returnFromRdCtl(ERROR); *intPtr = interface->PrefLevel; } break; default: logMsg("rdCtl: illegal cmd %d\n",cmd,2,3,4,5,6); return returnFromRdCtl(ERROR); } return returnFromRdCtl(OK) ; }/******************************************************************************** rdiscIfReset - check for new or removed interfaces for router discovery** This routine MUST be called any time an interface is added to or removed* from the system so that the router discovery code can deal with this* case. Failure to do so will cause the sending of packets on missing* interfaces to fail as well as no transmission of packets on new interfaces.**/STATUS rdiscIfReset () { struct in_ifaddr *ia = NULL; int i; int status; struct ifnet *ifp=NULL; struct ifaddr *ifa=NULL; char *t=NULL; struct sockaddr_in *tt=0; struct ip_mreq ipMreq; struct ifrd *pTmp=NULL; /* Take the lock. */ semTake (rdiscIfSem, WAIT_FOREVER); /* If we had an old list then free it. */ if (pIfDisc != NULL) { /* First drop the multicast stuff on all interfaces. */ for(i = 0; i < rdiscNumInterfaces; i++) { pTmp = &pIfDisc[i]; /* drop multicast membership for this IF */ ipMreq.imr_multiaddr.s_addr = htonl(0xe0000002); ipMreq.imr_interface.s_addr = pTmp->NetAddress.s_addr; /* * The reason we DON'T check the return status here * is that if we did and the interface has been removed * then we what would we do? This is a best effort * attempt to do remove the multicast address from * all UP interfaces, an interface that is missing * will simply return ERROR which is OK in this case. */ setsockopt(rdiscSock, IPPROTO_IP,IP_DROP_MEMBERSHIP, (char *)&ipMreq, sizeof(ipMreq)); } free (pIfDisc); } /* count interfaces for discovery */ #ifdef VIRTUAL_STACK for(ifp = _ifnet, i=0; ifp != 0; ifp = ifp->if_next)#else for(ifp = ifnet, i=0; ifp != 0; ifp = ifp->if_next)#endif { /* reject unwanted interfaces */ if (!(ifp->if_flags & IFF_MULTICAST)) continue; if (strcmp(ifp->if_name, "lo") == 0) continue; i++; } rdiscNumInterfaces = i; t = malloc(sizeof(struct ifrd) * rdiscNumInterfaces); if (t == NULL) { logMsg("rdiscIfReset: error allocating memory\n",0,0,0,0,0,0); semGive (rdiscIfSem); rdiscNumInterfaces = 0; /* So rdCtl won't walk an empty list. */ rdCtl (NULL, SET_MODE, (void*)MODE_STOP); return ERROR; } bzero(t, sizeof(struct ifrd) * rdiscNumInterfaces); /* set global to head of list */ pIfDisc = (struct ifrd *)t; /* set each interface for discovery */ #ifdef VIRTUAL_STACK for(ifp = _ifnet, i=0; ifp != 0; ifp = ifp->if_next)#else for(ifp = ifnet, i=0; ifp != 0; ifp = ifp->if_next)#endif { /* reject unwanted interfaces */ if (!(ifp->if_flags & IFF_MULTICAST)) continue; if (strcmp(ifp->if_name, "lo") == 0) continue; for (ifa = ifp->if_addrlist; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family == AF_INET) { tt = (struct sockaddr_in *)ifa->ifa_addr; break; } } /* find subnetmask */#ifdef VIRTUAL_STACK for (ia = _in_ifaddr; ia != NULL; ia = ia->ia_next)#else for (ia = in_ifaddr; ia != NULL; ia = ia->ia_next)#endif { if (ia->ia_ifp == ifp) break; } /* fill in router discovery params for this IF */ pTmp = &pIfDisc[i]; sprintf(pTmp->ifName,"%s%d", ifp->if_name, ifp->if_unit); pTmp->NetAddress.s_addr = tt->sin_addr.s_addr; pTmp->AdvertAddress.s_addr = htonl(0xe0000001); pTmp->subnet = ia->ia_subnet; pTmp->mask = ia->ia_subnetmask; pTmp->AdvertLifetime = 1800; pTmp->Advertise = 1; pTmp->PrefLevel = 0; /* add multicast membership for this IF */ ipMreq.imr_multiaddr.s_addr = htonl(0xe0000002); ipMreq.imr_interface.s_addr = pTmp->NetAddress.s_addr; status = setsockopt(rdiscSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&ipMreq, sizeof(ipMreq)); if (status == ERROR) { logMsg("rdisc: could not join multicast group, errno is %d\n", errno,0,0,0,0,0); semGive (rdiscIfSem); rdiscNumInterfaces = 0; /* So rdCtl won't walk a bad list. */ rdCtl (NULL, SET_MODE, (void*)MODE_STOP); return ERROR; } MaxAdvertInterval = 600; /* max interval in seconds */ MinAdvertInterval = 450; /* max interval in seconds */ i++; } /* create random number stream per IF address */ srand((uint_t)pTmp->NetAddress.s_addr); semGive (rdiscIfSem); return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -