//*************************************************************************** // // EXTCFG.CPP // // Module: WMI Framework Instance provider // // Purpose: Low-level utilities to configure NICs -- bind/unbind, // get/set IP address lists, and get/set NLB cluster params. // // Copyright (c)2001 Microsoft Corporation, All Rights Reserved // // History: // // 04/05/01 JosephJ Created (original version, from updatecfg.cpp under // nlbmgr\provider). // 07/23/01 JosephJ Moved functionality to lib. // //*************************************************************************** #include "private.h" #include "extcfg.tmh" // // NLBUPD_MAX_NETWORK_ADDRESS_LENGTH is the max number of chars (excluding // the terminating 0) of a string of the form "ip-addr/subnet", eg: // "10.0.0.1/255.255.255.0" // #define NLBUPD_MAX_NETWORK_ADDRESS_LENGTH \ (WLBS_MAX_CL_IP_ADDR + 1 + WLBS_MAX_CL_NET_MASK) LPWSTR * allocate_string_array( UINT NumStrings, UINT StringLen // excluding ending NULL ); WBEMSTATUS address_string_to_ip_and_subnet( IN LPCWSTR szAddress, OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK ); WBEMSTATUS ip_and_subnet_to_address_string( IN LPCWSTR szIp, IN LPCWSTR szSubnet, IN UINT cchAddress, // length in chars, including NULL. OUT LPWSTR szAddress // max NLBUPD_MAX_NETWORK_ADDRESS_LENGTH // + 1 (for NULL) ); VOID uint_to_szipaddr( UINT uIpAddress, // Ip address or subnet -- no validation, network order UINT cchLen, WCHAR *rgAddress // Expected to be at least 17 chars long ); const NLB_IP_ADDRESS_INFO * find_ip_in_ipinfo( LPCWSTR szIpToFind, const NLB_IP_ADDRESS_INFO *pIpInfo, UINT NumIpInfos ); NLBERROR NLB_EXTENDED_CLUSTER_CONFIGURATION::AnalyzeUpdate( IN OUT NLB_EXTENDED_CLUSTER_CONFIGURATION *pNewCfg, OUT BOOL *pfConnectivityChange ) // // NLBERR_NO_CHANGE -- update is a no-op. // // Will MUNGE pNewCfg -- munge NlbParams and also // fill out pIpAddressInfo if it's NULL. // { NLBERROR nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION; BOOL fConnectivityChange = FALSE; BOOL fSettingsChanged = FALSE; UINT NumIpAddresses = 0; NLB_IP_ADDRESS_INFO *pNewIpInfo = NULL; const NLB_EXTENDED_CLUSTER_CONFIGURATION *pOldCfg = this; UINT u; LPCWSTR szFriendlyName = m_szFriendlyName; if (szFriendlyName == NULL) { szFriendlyName = L""; } if (pOldCfg->fBound && !pOldCfg->fValidNlbCfg) { // // We're starting with a bound but invalid cluster state -- all bets are // off. // fConnectivityChange = TRUE; TRACE_CRIT("Analyze: Choosing Async because old state is invalid %ws", szFriendlyName); } else if (pOldCfg->fBound != pNewCfg->fBound) { // // bound/unbound state is different -- we do async // fConnectivityChange = TRUE; if (pNewCfg->fBound) { TRACE_CRIT("Analyze: Request to bind NLB to %ws", szFriendlyName); } else { TRACE_CRIT("Analyze: Request to unbind NLB from %ws", szFriendlyName); } } else { if (pNewCfg->fBound) { TRACE_CRIT("Analyze: Request to change NLB configuration on %ws", szFriendlyName); } else { TRACE_CRIT("Analyze: NLB not bound and to remain not bound on %ws", szFriendlyName); } } if (pNewCfg->fBound) { const WLBS_REG_PARAMS *pOldParams = NULL; if (pOldCfg->fBound) { pOldParams = &pOldCfg->NlbParams; } // // We may have been bound before and we remain bound, let's check if we // still need to do async, and also vaidate pNewCfg wlbs params in the // process // WBEMSTATUS TmpStatus = CfgUtilsAnalyzeNlbUpdate( pOldParams, &pNewCfg->NlbParams, &fConnectivityChange ); if (FAILED(TmpStatus)) { TRACE_CRIT("Analyze: Error analyzing nlb params for %ws", szFriendlyName); switch(TmpStatus) { case WBEM_E_INVALID_PARAMETER: nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION; break; case WBEM_E_INITIALIZATION_FAILURE: nerr = NLBERR_INITIALIZATION_FAILURE; break; default: nerr = NLBERR_LLAPI_FAILURE; break; } goto end; } // // NOTE: CfgUtilsAnalyzeNlbUpdate can return WBEM_S_FALSE if // the update is a no-op. We should be careful to preserve this // on success. // if (TmpStatus == WBEM_S_FALSE) { // // Let's check if a new password has been specified... // if (pNewCfg->NewRemoteControlPasswordSet()) { fSettingsChanged = TRUE; } } else { fSettingsChanged = TRUE; } // // Check the supplied list of IP addresses, to make sure that // includes the dedicated IP first and the cluster vip and the // per-port-rule vips. // NumIpAddresses = pNewCfg->NumIpAddresses; if ((NumIpAddresses == 0) != (pNewCfg->pIpAddressInfo == NULL)) { // Bogus input TRACE_CRIT("Analze: mismatch between NumIpAddresses and pIpInfo"); goto end; } nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION; if (NumIpAddresses == 0) { BOOL fRet; NlbIpAddressList IpList; if (pOldCfg->fBound && pOldCfg->fValidNlbCfg) { // // NLB is currently bound with a valid configuration. // // // If we we're told to do so, we try to preserve // old IP addresses as far as possible. So we start with the // old config, remove the old dedicated IP address (if present), // and primary VIP, and add the new dedicated IP address (if // present) and cluster vip. If subnet masks have changed for // these we update them. // // All other IP addresses are left intact. // // if (pNewCfg->fAddClusterIps) { // // Start with the original set of ip addresses. // fRet = IpList.Set( pOldCfg->NumIpAddresses, pOldCfg->pIpAddressInfo, 0 ); if (!fRet) { TRACE_CRIT("!FUNC!: IpList.Set (orig ips) failed"); goto end; } if (_wcsicmp(pNewCfg->NlbParams.cl_ip_addr, pOldCfg->NlbParams.cl_ip_addr) ) { // // If the cluster IP has changed, // remove the old cluster IP address. // // 1/25/02 josephj NOTE: we only do this // if the cluster IP has CHANGED, // otherwise, by taking it out, we lose it's position // in the old config, so we may end up changing it's // position unnecessarily (added the wcsicmp // check above today). // // We don't care if it fails. // (VOID) IpList.Modify( pOldCfg->NlbParams.cl_ip_addr, NULL, NULL ); } // // Remove the old dedicated IP address first // We don't care if this fails. // (VOID) IpList.Modify( pOldCfg->NlbParams.ded_ip_addr, NULL, // new ip address NULL // new subnet mask ); } } if (pNewCfg->fAddClusterIps) { // // Now add the new cluster Ip address // fRet = IpList.Modify( NULL, pNewCfg->NlbParams.cl_ip_addr, pNewCfg->NlbParams.cl_net_mask ); if (!fRet) { TRACE_CRIT("!FUNC!: IpList.Modify (new cl ip) failed"); goto end; } } if (pNewCfg->fAddDedicatedIp) { // // Add the new dedicated IP address -- // to ensure when we add it, it's at the head of the list. // // // We won't add it if it is null, of course. // if (!pNewCfg->IsBlankDedicatedIp()) { fRet = IpList.Modify( NULL, pNewCfg->NlbParams.ded_ip_addr, pNewCfg->NlbParams.ded_net_mask ); if (!fRet) { TRACE_CRIT("!FUNC!: IpList.Modify (new ded ip) failed"); goto end; } } } // // Finally, set these new addresses. // pNewCfg->SetNetworkAddressesRaw(NULL,0); IpList.Extract( REF pNewCfg->NumIpAddresses, REF pNewCfg->pIpAddressInfo ); nerr = NLBERR_OK; } // End case that NumIpAddresses is zero. // // We're done munging IP addresses; Now get the latest // ip address info and count and make sure things look ok. // pNewIpInfo = pNewCfg->pIpAddressInfo; NumIpAddresses = pNewCfg->NumIpAddresses; nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION; // // Check that dedicated ip address, if present is first. // if (pNewCfg->fAddDedicatedIp && !pNewCfg->IsBlankDedicatedIp()) { if (NumIpAddresses == 0) { // // We don't expect to get here because of checks above, but // neverthless... // TRACE_CRIT("%!FUNC! address list unexpectedly zero"); nerr = NLBERR_INTERNAL_ERROR; goto end; } if (_wcsicmp(pNewIpInfo[0].IpAddress, pNewCfg->NlbParams.ded_ip_addr)) { TRACE_CRIT("%!FUNC! ERROR: dedicated IP address(%ws) is not first IP address(%ws)", pNewCfg->NlbParams.ded_ip_addr, pNewIpInfo[0].IpAddress); goto end; } if (_wcsicmp(pNewIpInfo[0].SubnetMask, pNewCfg->NlbParams.ded_net_mask)) { TRACE_CRIT("%!FUNC! ERROR: dedicated net mask(%ws) does not match IP net mask(%ws)", pNewCfg->NlbParams.ded_net_mask, pNewIpInfo[0].SubnetMask); goto end; } } // // Check that cluster-vip is present // if (fAddClusterIps) { for (u=0; u< NumIpAddresses; u++) { if (!_wcsicmp(pNewIpInfo[u].IpAddress, pNewCfg->NlbParams.cl_ip_addr)) { // // Found it! Check that the subnet masks match. // if (_wcsicmp(pNewIpInfo[u].SubnetMask, pNewCfg->NlbParams.cl_net_mask)) { TRACE_CRIT("Cluster subnet mask doesn't match that in addr list"); goto end; } break; } } if (u==NumIpAddresses) { TRACE_CRIT("Cluster ip address(%ws) is not in the list of addresses!", pNewCfg->NlbParams.cl_ip_addr); goto end; } // // Check that per-port-rule vips are present. // TODO { } } } else { // // NLB is to be unbound. // NumIpAddresses = pNewCfg->NumIpAddresses; if (NumIpAddresses == 0 && pOldCfg->fBound && pOldCfg->fValidNlbCfg) { // // No ip addresses specified and we're currently bound. // If the DIP is present in the current // list of IP addresses, we keep it even after we unbind. // const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL; pFoundInfo = find_ip_in_ipinfo( pOldCfg->NlbParams.ded_ip_addr, pOldCfg->pIpAddressInfo, pOldCfg->NumIpAddresses ); if (pFoundInfo != NULL) { // // Found it -- let's take it. // BOOL fRet; NlbIpAddressList IpList; fRet = IpList.Set(1, pFoundInfo, 0); if (fRet) { TRACE_VERB( "%!FUNC! preserving dedicated ip address %ws on unbind", pFoundInfo->IpAddress ); IpList.Extract( REF pNewCfg->NumIpAddresses, REF pNewCfg->pIpAddressInfo ); } } } else { // // We don't do any checking on the supplied // list of IP addresses -- we assume caller knows best. Note that // if NULL // we switch to dhcp/autonet. // } } nerr = NLBERR_INVALID_CLUSTER_SPECIFICATION; // // If there's any change in the list of ipaddresses or subnets, including // a change in the order, we switch to async. // if (pNewCfg->NumIpAddresses != pOldCfg->NumIpAddresses) { TRACE_INFO("Analyze: detected change in list of IP addresses on %ws", szFriendlyName); fConnectivityChange = TRUE; } else { NLB_IP_ADDRESS_INFO *pOldIpInfo = NULL; // // Check if there is a change in the list of ip addresses or // their order of appearance. // NumIpAddresses = pNewCfg->NumIpAddresses; pOldIpInfo = pOldCfg->pIpAddressInfo; pNewIpInfo = pNewCfg->pIpAddressInfo; for (u=0; uNumIpAddresses; NLB_IP_ADDRESS_INFO *pIpAddressInfo = NULL; NLB_EXTENDED_CLUSTER_CONFIGURATION *pCfg = this; // // Free and realloc pCfg's ip info array if rquired. // if (pCfg->NumIpAddresses == NumIpAddresses) { // // we can re-use the existing one // pIpAddressInfo = pCfg->pIpAddressInfo; } else { // // Free the old one and allocate space for the new array if required. // if (NumIpAddresses != 0) { pIpAddressInfo = new NLB_IP_ADDRESS_INFO[NumIpAddresses]; if (pIpAddressInfo == NULL) { TRACE_CRIT(L"Error allocating space for IP address info array"); Status = WBEM_E_OUT_OF_MEMORY; goto end; } } if (pCfg->NumIpAddresses!=0) { delete pCfg->pIpAddressInfo; pCfg->pIpAddressInfo = NULL; pCfg->NumIpAddresses = 0; } } // // Copy over the new ip address info, if there is any. // if (NumIpAddresses) { CopyMemory( pIpAddressInfo, pCfgNew->pIpAddressInfo, NumIpAddresses*sizeof(*pIpAddressInfo) ); } // // Do any other error checks here. // // // Struct copy the entire structure, then fix up the pointer to // ip address info array. // (VOID) pCfg->SetFriendlyName(NULL); delete m_szNewRemoteControlPassword; *pCfg = *pCfgNew; // struct copy pCfg->m_szFriendlyName = NULL; // TODO: clean this up. pCfg->m_szNewRemoteControlPassword = NULL; pCfg->pIpAddressInfo = pIpAddressInfo; pCfg->NumIpAddresses = NumIpAddresses; (VOID) pCfg->SetFriendlyName(pCfgNew->m_szFriendlyName); // // Update does NOT copy over the new remote control password or // new hashed password -- in fact // it ends up clearing the new password fields. // pCfg->ClearNewRemoteControlPassword(); Status = WBEM_NO_ERROR; end: return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddresses( IN LPCWSTR *pszNetworkAddresses, IN UINT NumNetworkAddresses ) /* pszNetworkAddresses is an array of strings. These strings have the format "addr/subnet", eg: "10.0.0.1/255.0.0.0" */ { WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR; NLB_IP_ADDRESS_INFO *pIpInfo = NULL; if (NumNetworkAddresses != 0) { UINT NumBad = 0; // // Allocate space for the new ip-address-info array // pIpInfo = new NLB_IP_ADDRESS_INFO[NumNetworkAddresses]; if (pIpInfo == NULL) { TRACE_CRIT("%!FUNC!: Alloc failure!"); Status = WBEM_E_OUT_OF_MEMORY; goto end; } ZeroMemory(pIpInfo, NumNetworkAddresses*sizeof(*pIpInfo)); // // Convert IP addresses to our internal form. // for (UINT u=0;u=NumBad); Status = address_string_to_ip_and_subnet( szAddr, pIpInfo[u-NumBad].IpAddress, pIpInfo[u-NumBad].SubnetMask ); if (FAILED(Status)) { // // This one of the ip/subnet parms is too large. // TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddr); goto end; } } NumNetworkAddresses -= NumBad; if (NumNetworkAddresses == 0) { delete[] pIpInfo; pIpInfo = NULL; } } // // Replace the old ip-address-info with the new one // if (this->pIpAddressInfo != NULL) { delete this->pIpAddressInfo; this->pIpAddressInfo = NULL; } this->pIpAddressInfo = pIpInfo; pIpInfo = NULL; this->NumIpAddresses = NumNetworkAddresses; Status = WBEM_NO_ERROR; end: if (pIpInfo != NULL) { delete[] pIpInfo; } return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddresses( OUT LPWSTR **ppszNetworkAddresses, // free using delete OUT UINT *pNumNetworkAddresses ) /* ppszNetworkAddresses is filled out on successful return to an array of strings. These strings have the format "addr/subnet", eg: "10.0.0.1/255.0.0.0" */ { WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR; UINT AddrCount = this->NumIpAddresses; NLB_IP_ADDRESS_INFO *pIpInfo = this->pIpAddressInfo; LPWSTR *pszNetworkAddresses = NULL; if (AddrCount != 0) { // // Convert IP addresses from our internal form into // format "addr/subnet", eg: "10.0.0.1/255.0.0.0" // // const UINT cchLen = WLBS_MAX_CL_IP_ADDR // for IP address + WLBS_MAX_CL_NET_MASK // for subnet mask + 1; // for separating '/' pszNetworkAddresses = allocate_string_array( AddrCount, cchLen ); if (pszNetworkAddresses == NULL) { TRACE_CRIT("%!FUNC!: Alloc failure!"); Status = WBEM_E_OUT_OF_MEMORY; goto end; } for (UINT u=0;uWLBS_MAX_DOMAIN_NAME) { TRACE_CRIT("%!FUNC!: Cluster name too large"); } CopyMemory(NlbParams.domain_name, szName, (len+1)*sizeof(WCHAR)); } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::GetDedicatedNetworkAddress( OUT LPWSTR *pszAddress ) { WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY; LPWSTR szAddress = NULL; if (fValidNlbCfg) { szAddress = new WCHAR[NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1]; if (szAddress != NULL) { Status = ip_and_subnet_to_address_string( NlbParams.ded_ip_addr, NlbParams.ded_net_mask, NLBUPD_MAX_NETWORK_ADDRESS_LENGTH+1, szAddress ); if (FAILED(Status)) { delete[] szAddress; szAddress = NULL; } } } *pszAddress = szAddress; return Status; } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetDedicatedNetworkAddress( IN LPCWSTR szAddress ) { if (szAddress == NULL || *szAddress == 0) { ARRAYSTRCPY(NlbParams.ded_ip_addr, CVY_DEF_DED_IP_ADDR); ARRAYSTRCPY(NlbParams.ded_net_mask, CVY_DEF_DED_NET_MASK); } else { (VOID) address_string_to_ip_and_subnet( szAddress, NlbParams.ded_ip_addr, NlbParams.ded_net_mask ); } } NLB_EXTENDED_CLUSTER_CONFIGURATION::TRAFFIC_MODE NLB_EXTENDED_CLUSTER_CONFIGURATION::GetTrafficMode( VOID ) const { TRAFFIC_MODE TrafficMode = TRAFFIC_MODE_UNICAST; if (NlbParams.mcast_support) { if (NlbParams.fIGMPSupport) { TrafficMode = TRAFFIC_MODE_IGMPMULTICAST; } else { TrafficMode = TRAFFIC_MODE_MULTICAST; } } return TrafficMode; } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetTrafficMode( TRAFFIC_MODE Mode ) { switch(Mode) { case TRAFFIC_MODE_UNICAST: NlbParams.mcast_support = 0; NlbParams.fIGMPSupport = 0; break; case TRAFFIC_MODE_IGMPMULTICAST: NlbParams.mcast_support = 1; NlbParams.fIGMPSupport = 1; break; case TRAFFIC_MODE_MULTICAST: NlbParams.mcast_support = 1; NlbParams.fIGMPSupport = 0; break; default: ASSERT(FALSE); break; } } UINT NLB_EXTENDED_CLUSTER_CONFIGURATION::GetHostPriority( VOID ) { return NlbParams.host_priority; } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetHostPriority( UINT Priority ) { NlbParams.host_priority = Priority; } //NLB_EXTENDED_CLUSTER_CONFIGURATION::START_MODE DWORD NLB_EXTENDED_CLUSTER_CONFIGURATION::GetClusterModeOnStart( VOID ) { // // If we decide to make cluster_mode something besides true/false we // need to make the change here too... // /* ASSERT(NlbParams.cluster_mode==TRUE || NlbParams.cluster_mode==FALSE); if (NlbParams.cluster_mode) { return START_MODE_STARTED; } else { return START_MODE_STOPPED; } */ return NlbParams.cluster_mode; } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetClusterModeOnStart( // START_MODE Mode DWORD Mode ) { /* switch(Mode) { case START_MODE_STARTED: NlbParams.cluster_mode = TRUE; break; case START_MODE_STOPPED: NlbParams.cluster_mode = FALSE; break; default: ASSERT(FALSE); break; } */ NlbParams.cluster_mode = Mode; } BOOL NLB_EXTENDED_CLUSTER_CONFIGURATION::GetPersistSuspendOnReboot( VOID ) { // This is a straight lift from wmi\ClusterWrapper.cpp\GetNodeConfig() // -KarthicN return ((NlbParams.persisted_states & CVY_PERSIST_STATE_SUSPENDED) != 0); } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetPersistSuspendOnReboot( BOOL bPersistSuspendOnReboot ) { // This is a straight lift from wmi\ClusterWrapper.cpp\PutNodeConfig() // -KarthicN if (bPersistSuspendOnReboot) { NlbParams.persisted_states |= CVY_PERSIST_STATE_SUSPENDED; } else { NlbParams.persisted_states &= ~CVY_PERSIST_STATE_SUSPENDED; } } BOOL NLB_EXTENDED_CLUSTER_CONFIGURATION::GetRemoteControlEnabled( VOID ) const { return (NlbParams.rct_enabled!=FALSE); } VOID NLB_EXTENDED_CLUSTER_CONFIGURATION::SetRemoteControlEnabled( BOOL fEnabled ) { NlbParams.rct_enabled = (fEnabled!=FALSE); } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNetworkAddressesSafeArray( IN SAFEARRAY *pSA ) { LPWSTR *pStrings=NULL; UINT NumStrings = 0; WBEMSTATUS Status; Status = CfgUtilStringsFromSafeArray( pSA, &pStrings, // delete when done useing pStrings &NumStrings ); if (FAILED(Status)) { pStrings=NULL; goto end; } Status = this->SetNetworkAddresses( (LPCWSTR*)pStrings, NumStrings ); if (pStrings != NULL) { delete pStrings; } end: return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::GetNetworkAddressesSafeArray( OUT SAFEARRAY **ppSA ) { LPWSTR *pszNetworkAddresses = NULL; UINT NumNetworkAddresses = 0; SAFEARRAY *pSA=NULL; WBEMSTATUS Status; Status = this->GetNetworkAddresses( &pszNetworkAddresses, &NumNetworkAddresses ); if (FAILED(Status)) { pszNetworkAddresses = NULL; goto end; } Status = CfgUtilSafeArrayFromStrings( (LPCWSTR*) pszNetworkAddresses, NumNetworkAddresses, // can be zero &pSA ); if (FAILED(Status)) { pSA = NULL; } end: *ppSA = pSA; if (pszNetworkAddresses != NULL) { delete pszNetworkAddresses; pszNetworkAddresses = NULL; } if (FAILED(Status)) { TRACE_CRIT("%!FUNC!: couldn't extract network addresses from Cfg"); } return Status; } LPWSTR * allocate_string_array( UINT NumStrings, UINT MaxStringLen // excluding ending NULL ) /* Allocate a single chunk of memory using the new LPWSTR[] operator. The first NumStrings LPWSTR values of this operator contain an array of pointers to WCHAR strings. Each of these strings is of size (MaxStringLen+1) WCHARS. The rest of the memory contains the strings themselve. Return NULL if NumStrings==0 or on allocation failure. Each of the strings are initialized to be empty strings (first char is 0). */ { return CfgUtilsAllocateStringArray(NumStrings, MaxStringLen); } WBEMSTATUS address_string_to_ip_and_subnet( IN LPCWSTR szAddress, OUT LPWSTR szIp, // max WLBS_MAX_CL_IP_ADDR including NULL OUT LPWSTR szSubnet // max WLBS_MAX_CL_NET_MASK including NULL ) // Special case: if szAddress == "", we zero out both szIp and szSubnet; { WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR; if (*szAddress == 0) {szAddress = L"/";} // Special case mentioned above // from the "addr/subnet" format insert it into a // NLB_IP_ADDRESS_INFO structure. // // SAMPLE: 10.0.0.1/255.0.0.0 // LPCWSTR pSlash = NULL; LPCWSTR pSrcSub = NULL; *szIp = 0; *szSubnet = 0; pSlash = wcsrchr(szAddress, (int) '/'); if (pSlash == NULL) { TRACE_CRIT("%!FUNC!:missing subnet portion in %ws", szAddress); Status = WBEM_E_INVALID_PARAMETER; goto end; } pSrcSub = pSlash+1; UINT len = (UINT) (pSlash - szAddress); UINT len1 = wcslen(pSrcSub); if ( (len < WLBS_MAX_CL_IP_ADDR) && (len1 < WLBS_MAX_CL_NET_MASK)) { CopyMemory(szIp, szAddress, len*sizeof(WCHAR)); szIp[len] = 0; CopyMemory(szSubnet, pSrcSub, (len1+1)*sizeof(WCHAR)); } else { // // One of the ip/subnet parms is too large. // TRACE_CRIT("%!FUNC!:ip or subnet part too large: %ws", szAddress); Status = WBEM_E_INVALID_PARAMETER; goto end; } Status = WBEM_NO_ERROR; end: return Status; } WBEMSTATUS ip_and_subnet_to_address_string( IN LPCWSTR szIp, IN LPCWSTR szSubnet, IN UINT cchAddress, OUT LPWSTR szAddress// max WLBS_MAX_CL_IP_ADDR // + 1(for slash) + WLBS_MAX_CL_NET_MASK + 1 (for NULL) ) { WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER; UINT len = wcslen(szIp)+wcslen(szSubnet) + 1; // +1 for separating '/' if (len >= NLBUPD_MAX_NETWORK_ADDRESS_LENGTH) { goto end; } else { HRESULT hr; hr = StringCchPrintf( szAddress, cchAddress, L"%ws/%ws", szIp, szSubnet ); if (hr == S_OK) { Status = WBEM_NO_ERROR; } else { Status = WBEM_E_INVALID_PARAMETER; } } end: return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::GetFriendlyName( OUT LPWSTR *pszFriendlyName // Free using delete ) const { WBEMSTATUS Status = WBEM_E_NOT_FOUND; LPWSTR szName = NULL; *pszFriendlyName = NULL; if (m_szFriendlyName != NULL) { UINT len = wcslen(m_szFriendlyName); szName = new WCHAR[len+1]; // +1 for ending 0 if (szName == NULL) { Status = WBEM_E_OUT_OF_MEMORY; } else { Status = WBEM_NO_ERROR; CopyMemory(szName, m_szFriendlyName, (len+1)*sizeof(WCHAR)); } } *pszFriendlyName = szName; return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::SetFriendlyName( IN LPCWSTR szFriendlyName // Saves a copy of szFriendlyName ) { WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY; LPWSTR szName = NULL; if (szFriendlyName != NULL) { UINT len = wcslen(szFriendlyName); szName = new WCHAR[len+1]; // +1 for ending 0 if (szName == NULL) { goto end; } else { CopyMemory(szName, szFriendlyName, (len+1)*sizeof(WCHAR)); } } Status = WBEM_NO_ERROR; if (m_szFriendlyName != NULL) { delete m_szFriendlyName; m_szFriendlyName = NULL; } m_szFriendlyName = szName; end: return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION::SetNewRemoteControlPassword( IN LPCWSTR szRemoteControlPassword // Saves a copy of szRemoteControlPassword ) { WBEMSTATUS Status = WBEM_E_OUT_OF_MEMORY; LPWSTR szName = NULL; if (szRemoteControlPassword != NULL) { UINT len = wcslen(szRemoteControlPassword); szName = new WCHAR[len+1]; // +1 for ending 0 if (szName == NULL) { goto end; } else { CopyMemory(szName, szRemoteControlPassword, (len+1)*sizeof(WCHAR)); } m_fSetPassword = TRUE; } else { m_fSetPassword = FALSE; } Status = WBEM_NO_ERROR; if (m_szNewRemoteControlPassword != NULL) { delete m_szNewRemoteControlPassword; m_szNewRemoteControlPassword = NULL; } m_szNewRemoteControlPassword = szName; end: return Status; } WBEMSTATUS NLB_EXTENDED_CLUSTER_CONFIGURATION:: ModifyNetworkAddress( IN LPCWSTR szOldIpAddress, OPTIONAL // network order IN LPCWSTR szNewIpAddress, OPTIONAL IN LPCWSTR szNewSubnetMask OPTIONAL ) // // NULL, NULL: clear all network addresses // NULL, szNew: add // szOld, NULL: remove // szOld, szNew: replace (or add, if old doesn't exist) // { WBEMSTATUS Status = WBEM_E_INVALID_PARAMETER; BOOL fRet; NlbIpAddressList IpList; fRet = IpList.Set(this->NumIpAddresses, this->pIpAddressInfo, 0); if (fRet) { fRet = IpList.Modify( szOldIpAddress, szNewIpAddress, szNewSubnetMask ); } if (fRet) { this->SetNetworkAddressesRaw(NULL,0); IpList.Extract(REF this->NumIpAddresses, REF this->pIpAddressInfo); Status = WBEM_NO_ERROR; } else { Status = WBEM_E_INVALID_PARAMETER; } return Status; } BOOL NLB_EXTENDED_CLUSTER_CONFIGURATION:: IsBlankDedicatedIp( VOID ) const // // Dedicated IP is either the empty string or all zeros. // { return (NlbParams.ded_ip_addr[0]==0) || (_wcsspnp(NlbParams.ded_ip_addr, L".0")==NULL); } const NLB_IP_ADDRESS_INFO * NlbIpAddressList::Find( LPCWSTR szIp // IF NULL, returns first address ) const // // Looks for the specified IP address -- returns an internal pointer // to the found IP address info, if fount, otherwise NULL. // { const NLB_IP_ADDRESS_INFO *pInfo = NULL; if (szIp == NULL) { // // return the first if there is one, else NULL. // if (m_uNum != 0) { pInfo = m_pIpInfo; } } else { pInfo = find_ip_in_ipinfo(szIp, m_pIpInfo, m_uNum); } return pInfo; } BOOL NlbIpAddressList::Copy(const NlbIpAddressList &refList) { BOOL fRet; fRet = this->Set(refList.m_uNum, refList.m_pIpInfo, 0); return fRet; } BOOL NlbIpAddressList::Validate(void) // checks that there are no dups and all valid ip/subnets { BOOL fRet = FALSE; NLB_IP_ADDRESS_INFO *pInfo = m_pIpInfo; UINT uNum = m_uNum; for (UINT u = 0; u set(%lu, %p, %lu): m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n", // uNew, pNewInfo, uExtraCount, // m_uNum, m_uMax, m_pIpInfo); if (uMax > m_uMax) { // // We'll re-allocate to get more space. // pInfo = new NLB_IP_ADDRESS_INFO[uMax]; if (pInfo == NULL) { TRACE_CRIT("%!FUNC! allocation failure"); goto end; } } else { // // The current m_pIpInfo is large enough; we'll keep it. // pInfo = m_pIpInfo; uMax = m_uMax; } if (uNew != 0) { if (pNewInfo == pInfo) { // Caller has passed m_pInfo as pNewInfo. // No need to copy. } else { // // MoveMemory can deal with overlapping regions. // MoveMemory(pInfo, pNewInfo, sizeof(NLB_IP_ADDRESS_INFO)*uNew); } } if (uMax > uNew) { // // Zero out the empty space. // ZeroMemory(pInfo+uNew, sizeof(NLB_IP_ADDRESS_INFO)*(uMax-uNew)); } m_uNum = uNew; m_uMax = uMax; if (m_pIpInfo != pInfo) { delete[] m_pIpInfo; m_pIpInfo = pInfo; } fRet = TRUE; end: // printf("<- set: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n", // fRet, m_uNum, m_uMax, m_pIpInfo); return fRet; } VOID NlbIpAddressList::Extract(UINT &uNum, NLB_IP_ADDRESS_INFO * &pNewInfo) /* Sets pNewInfo to the ip list (not a copy) and sets the internal list to null. Free using delete[]. */ { uNum = m_uNum; pNewInfo = m_pIpInfo; m_uNum=0; m_uMax=0; m_pIpInfo = NULL; } static VOID uint_to_szipaddr( UINT uIpAddress, // Ip address or subnet -- no validation, network order UINT cchLen, // length of rgAddress, incluing space for NULL WCHAR *rgAddress // Expected to be at least 17 chars long ) { BYTE *pb = (BYTE*) &uIpAddress; StringCchPrintf(rgAddress, cchLen, L"%lu.%lu.%lu.%lu", pb[0], pb[1], pb[2], pb[3]); } BOOL NlbIpAddressList::Modify( LPCWSTR szOldIp, LPCWSTR szNewIp, LPCWSTR szNewSubnet ) // // NULL, NULL, -: clear all network addresses // NULL, szNew, -: add // szOld, NULL, -: remove // szOld, szNew, -: remove szOld if found; add or replace szNew. // { WBEMSTATUS Status = WBEM_E_CRITICAL_ERROR; BOOL fRet = FALSE; UINT uFoundOldOffset = 0; BOOL fFoundOldAddress = FALSE; // printf("-> modify: m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n", // m_uNum, m_uMax, m_pIpInfo); if (szOldIp==NULL && szNewIp==NULL) { this->Clear(); fRet = TRUE; goto end; } if (szOldIp != NULL && szNewIp != NULL) { // // Both szOld and szNew are specified. // We'll first call ourselves recursively to remove szNewIp, if // it exists. Later on below we'll replace szOldIp with szNewIp // if szOldIp exists (i.e. at the same LOCATION of szOldIp), or // add it to the beginning if szOldIp doesn't exist. // (void) this->Modify(szNewIp, NULL, NULL); } if (szOldIp == NULL) { szOldIp = szNewIp; // so we don't add dups. } if (szOldIp != NULL) { const NLB_IP_ADDRESS_INFO *pFoundInfo = NULL; pFoundInfo = find_ip_in_ipinfo(szOldIp, m_pIpInfo, m_uNum); if(pFoundInfo != NULL) { uFoundOldOffset = (ULONG) (UINT_PTR) (pFoundInfo-m_pIpInfo); fFoundOldAddress = TRUE; } } if (szNewIp == NULL) { // // Remove old Ip address // if (!fFoundOldAddress) { // // Old one not found // fRet = FALSE; goto end; } // // We bump up everything beyond this one // m_uNum--; // that this was at least 1 because we found the old for (UINT u=uFoundOldOffset; uSet(m_uNum, m_pIpInfo, 2); if (!fRet) { goto end; } } // // Move existing stuff one place down, to make place for the // new one. // if (m_uNum >= m_uMax) { // Ahem, should never get here because we just added // two extra spaces above. fRet = FALSE; goto end; } if (m_uNum) { // Note the regions overlap -- MoveMemory can handle this. // MoveMemory(m_pIpInfo+1, m_pIpInfo, m_uNum*sizeof(*m_pIpInfo)); } // // Add a new one -- we'll add it to the beginning. // m_pIpInfo[0] = NewIpInfo; // struct copy. m_uNum++; } } fRet = TRUE; end: // printf("<- modify: fRet=%lu, m_uNum=%lu m_uMax=%lu m_pIpInfo=0x%p\n", // fRet, m_uNum, m_uMax, m_pIpInfo); return fRet; } BOOL NlbIpAddressList::sfn_validate_info( const NLB_IP_ADDRESS_INFO &Info, UINT &uIpAddress ) { WBEMSTATUS Status; UINT uSubnetMask = 0; Status = CfgUtilsValidateNetworkAddress( Info.IpAddress, &uIpAddress, NULL, NULL ); if (!FAILED(Status)) { Status = CfgUtilsValidateNetworkAddress( Info.SubnetMask, &uSubnetMask, NULL, NULL ); } return (!FAILED(Status)); } UINT * ipaddresses_from_ipaddressinfo( const NLB_IP_ADDRESS_INFO *pInfo, UINT NumAddresses ) /* Free return value using "delete" operator. */ { UINT *rgOut = NULL; if (NumAddresses == 0) goto end; // // Allocate space. // rgOut = new UINT[NumAddresses]; if (rgOut==NULL) goto end; // // Validate each address, thereby getting the ip address info. // for (UINT *pOut = rgOut; NumAddresses--; pOut++, pInfo++) { WBEMSTATUS wStat; wStat = CfgUtilsValidateNetworkAddress( pInfo->IpAddress, pOut, NULL, NULL ); if (FAILED(wStat)) { TRACE_CRIT("%!FUNC! -- Validate address \"%ws\" failed!\n", pInfo->IpAddress); delete[] rgOut; rgOut = NULL; goto end; } } end: return rgOut; } BOOL NlbIpAddressList::Apply(UINT NumNew, const NLB_IP_ADDRESS_INFO *pNewInfo) /* Set our internal list to be a permutation of the ip addresses in pInfo. The permutation attempts to minimize the differences between the new and the current version: basically the relative order of any adresses that remain in new is preserved, and any new addresses are tacked on at the end. */ { BOOL fRet = FALSE; UINT *rgOldIps = NULL; UINT *rgNewIps = NULL; NLB_IP_ADDRESS_INFO *rgNewInfo = NULL; UINT NumFilled = 0; UINT NumOld = m_uNum; if (NumNew == 0) { this->Clear(); fRet = TRUE; goto end; } if (NumOld!=0) { rgOldIps = ipaddresses_from_ipaddressinfo( m_pIpInfo, m_uNum ); if (rgOldIps == NULL) goto end; } rgNewIps = ipaddresses_from_ipaddressinfo( pNewInfo, NumNew ); if (rgNewIps==NULL) goto end; rgNewInfo = new NLB_IP_ADDRESS_INFO[NumNew]; if (rgNewInfo == NULL) { TRACE_CRIT("%!FUNC! allocation failure!"); goto end; } // // We try to preserve our current order of IP addresses // as far as possible. To do this, we go through each ip address // in our list in order -- if we find it in the new list, we // add it to our new copy -- thereby preserving the order of all // old IP addresses that are still present in the new list. // { for (UINT uOld = 0; uOld < NumOld; uOld++) { UINT uOldIp = rgOldIps[uOld]; // // See if it exists in new version -- if so add to new // for (UINT uNew=0; uNew