none
How Do I Programatically Change From DHCP to Static IP, and Back Again?

    Question

  • I'm developing a PC application at work that must talk ethernet to an embedded system that has static IP 192.168.0.214.  This embedded system expects my host PC to have static IP 192.168.0.215.  My PC application must:

    1. Change from DHCP to static IP 192.168.0.215 when the program first starts up.
    2. Communicate via ethernet to the embedded system (send and receive miscellaneous messages).
    3. Change back to DHCP when the program ends.

    I have some closely related code that I borrowed from another project.  This code has functions to get the PC IP address, add another IP address to the network adapter's IP list, and send/receive ethernet messages.  And these functions work very well.  So, I guess the only thing I need is to develop a function that will change the PC back and forth between DHCP and static IP.

    I do not want to use netsh, or any other such utility.  I want to do this programatically.

    I'm using Microsoft Visual Studio 2005 Professional Edition.  My host PC is running Windows XP (with Service Pack 2).  It has a single network adapter named "Local Area Connection".

    At the expense of being very verbose, I've included the source code I've borrowed from another project (it appears below), in case this will help you help me.  There are 3 functions:

    1. ethernetIfGetMyIPAddress (gets the IP address of the current PC).
    2. ethernetIfAddIpToPC (adds an IP address to the network adapter's IP list).
    3. ethernetIfCleanUp (deletes the IP address that was added).

    Thanks in advance.


    DCA_API int ethernetIfGetMyIPAddress(int hostIndex, char *theAddr)
    {
        static hostent *pHostEnt = NULL;
        static char    szHostName[128] = {NULL};
        char           tempNo[4];
        int            j;
        unsigned int   anOctet;
        int            rtnStatus = EI_SUCCESS;

        /*
         * Initialize the returned IP address to a NULL string.
         */
        *theAddr = NULL;

        if (WSAStartup (MAKEWORD(2,2), &WSAData) != 0)
            rtnStatus = EI_WSAStartup_FAIL;

        /*
         * Always update the host entry table. This is required for the simple fact
         * that the host computer will be connected/disconnected from the Eternet in
         * a dynamic environment. If the host entry table will reflect the current
         * state of the IP address. An address of 127.0.0.1 indicates that the host
         * PC is not attached and the default loopback IP address is returned.
         */
           else if (gethostname(szHostName, 128) != 0)
        {
            rtnStatus = EI_HOSTNAME_UNAVAIL;
        }

        else if ((pHostEnt = gethostbyname(szHostName)) == NULL)
        {
            rtnStatus = EI_HOSTENTRY_UNAVAIL;
        }

        /*
         * Assuming that only one adapter is attached... the last
         * adapter in the list "pHostEnt->h_addr_list" is assumed to be the
         * desired adapter utilized for reprogramming.
         */
        else if ((pHostEnt != NULL) &&
                 (pHostEnt->h_addr_list[hostIndex] != NULL))
        {
            for (j=0; j<pHostEnt->h_length; j++)
            {
                /*
                 * Build the string defining the IP address of the first
                 * adapter.
                 */
                if (j>0)
                    strcat(theAddr,".");

                anOctet = (unsigned int)(unsigned char)
                            (pHostEnt->h_addr_list[hostIndex][j]);
                sprintf(tempNo,
                        "%i",
                        anOctet);
                strcat(theAddr, tempNo);
            }

            if (debugMode)
                printf("ethernetIfGetMyIPAddress reported IP of %s\r\n",
                       theAddr);
        }

        /*
         * Return a string with nothing in it to indicate the selected adapter
         * index does not exist.
         */
        else
        {
            rtnStatus = EI_HOSTENTRY_NOT_FOUND;
        }

        reportStatus("ethernetIfGetMyIPAddress",rtnStatus);

        return rtnStatus;

    } /* ethernetIfGetMyIPAddress */

    DCA_API int ethernetIfAddIpToPC(char  *szPCIP)
    {
        // IP and mask we will be adding
        UINT iaIPAddress;
        UINT imIPMask;

        int   rtnStatus = EI_SUCCESS;
        DWORD index;
        DWORD dwRetVal;
        DWORD dwSize = 0;

       // if (initComplete != TRUE)
        //{
        //    rtnStatus = EI_INITERROR;
        //    reportStatus("ethernetIfAddIpToPC",rtnStatus);
        //    return rtnStatus;
        //}

        // Before calling AddIPAddress we use GetIpAddrTable to get
        // an adapter to which we can add the IP.
        PMIB_IPADDRTABLE pIPAddrTable;

        // Format the IP address from a character string to an IP address value.
        iaIPAddress = inet_addr(szPCIP);
        imIPMask    = inet_addr("255.255.255.0");  // Always

        pIPAddrTable = (MIB_IPADDRTABLE*) malloc(sizeof(MIB_IPADDRTABLE));

        // Make an initial call to GetIpAddrTable to get the
        // necessary size into the dwSize variable
        if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
        {
            free( pIPAddrTable );
            pIPAddrTable = (MIB_IPADDRTABLE *) malloc ( dwSize );
        }

        // Make a second call to GetIpAddrTable to get the
        // actual data we want and check for a duplicate IP address.
        if ( (dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 )) == NO_ERROR )
        {
            for (index=0;index<pIPAddrTable->dwNumEntries;index++)
            {
                if (pIPAddrTable->table[index].dwAddr == iaIPAddress)
                    rtnStatus = EI_DUPIP;
            }
        }

        else if (dwRetVal == ERROR_INVALID_PARAMETER)
            rtnStatus = EI_INVALIDPARAMETER;

        else if (dwRetVal == ERROR_NOT_SUPPORTED)
            rtnStatus = EI_UNSUPPRTEDOS;

        else
        {
            LPVOID lpMsgBuf;

            if (debugMode)
                printf("Error getting IP address, error = %d (0x%08X).\n",
                       dwRetVal,dwRetVal);

            if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                              FORMAT_MESSAGE_FROM_SYSTEM |
                              FORMAT_MESSAGE_IGNORE_INSERTS,
                              NULL,
                              dwRetVal,
                              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                              (LPTSTR) &lpMsgBuf,
                              0,
                              NULL ))
            {
                if (debugMode)
                    printf("\tError: %s", lpMsgBuf);
            }

            else
            {
                if (debugMode)
                    printf("FormatMessage1 returned an error of %d\r\n",
                           GetLastError());
            }

            rtnStatus = EI_FAIL;
        }

        // Check for an unhadled error
        if (rtnStatus != EI_SUCCESS)
        {
            free(pIPAddrTable);
            reportStatus("ethernetIfAddIpToPC",rtnStatus);
            return rtnStatus;
        }

        if ( (dwRetVal = AddIPAddress(iaIPAddress,
                                      imIPMask,
                                      pIPAddrTable->table[0].dwIndex,
                                      &NTEContext,
                                      &NTEInstance) ) == NO_ERROR)
        {
            if (debugMode)
                printf("IP address added.\n");
        }

        // Not sure what this error code is but appears to work fine.
        // Thought it might be that the IP address already exists, no harm done.
        else if (dwRetVal == 0xC000022A)
        {
            if (debugMode)
                printf("*** IP address already exists at %s, continuing ***\n",
                       szPCIP);
        }

        // Check for known errors as defined by the the documentation.
        else if (dwRetVal == ERROR_DEV_NOT_EXIST)
            rtnStatus = EI_INVALIDADAPTER;

        else if (dwRetVal == ERROR_DUP_DOMAINNAME)
            rtnStatus = EI_DUPDOMAIN;

        else if (dwRetVal == ERROR_INVALID_HANDLE)
            rtnStatus = EI_NOADMINPRIV;

        else if (dwRetVal == ERROR_INVALID_PARAMETER)
            rtnStatus = EI_INVALIDPARAMETER;

        else if (dwRetVal == ERROR_NOT_SUPPORTED)
            rtnStatus = EI_UNSUPPRTEDOS;

        // If any other error occurs, then attempt to print a string defining the
        // error.
        else
        {
            LPVOID lpMsgBuf;

            if (debugMode)
                printf("Error adding IP address, error = %d (0x%08X).\n",
                       dwRetVal,dwRetVal);

            if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                              FORMAT_MESSAGE_FROM_SYSTEM |
                              FORMAT_MESSAGE_IGNORE_INSERTS,
                              NULL,
                              dwRetVal,
                              0, //MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                              (LPTSTR) &lpMsgBuf,
                              0,
                              NULL ))
            {
                if (debugMode)
                    printf("\tError: %s", lpMsgBuf);
            }

            else
            {
                if (debugMode)
                    printf("FormatMessage2 returned an error of %d\r\n",
                           GetLastError());
            }

            rtnStatus = EI_FAIL;
        }

        free(pIPAddrTable);

        reportStatus("ethernetIfAddIpToPC",rtnStatus);

        return rtnStatus;

    } /* ethernetIfAddIpToPC */

    DCA_API void ethernetIfCleanUp(void)
    {
        DWORD dwRetVal;

        // Reset flag denoting that the DCA has not be found. A new search
        // is required to "re-acquire" the DCA.
        LocalDCAFound = FALSE;

        // Delete the IP we just added using the NTEContext
        // variable where the handle was returned
        if ((dwRetVal = DeleteIPAddress(NTEContext)) != NO_ERROR)
        {
            if (debugMode)
                printf("\tCall to DeleteIPAddress failed with error %d.\n",
                        dwRetVal);
        }

    } /* ethernetIfCleanUp */
    Sunday, May 10, 2009 12:14 AM

Answers

  • DHCP controls how the machine obtains an IP address -- once an IP address is set, though, DHCP is meaningless. In other words, using AddIPAddress to change the address doesn't affect DHCP at all...it merely means it obtains the address from the call, rather than from a DHCP server.

    That said, it shouldn't affect your communications with this VxWorks card.  As long as both have valid IP addresses and are on the same LAN segment, the lack of a DHCP server shouldn't be any problem at all.

    However, what Nobugs was saying (and I agree with him) is that an easier solution for you may be one of the following:

      - If you can leave the IP address of your client as 192.168.0.215, then do just that.  Leave it there, and forget changing it programmatically.
      - If you CAN'T leave the IP address set to that address, then buy a second NIC to dedicate to that address, and leave the first one alone.
    Michael Asher
    Sunday, May 10, 2009 7:13 PM

All replies

  • To _persistently_ change the IP address, you need to access the registry key:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet \Services\TcpIp\Parameters\Interfaces

    And then iterate for the proper network card.

    To change it just for a single session, you can use the AddIPAddress/DeleteIPAddress functions.  The following article has a code example to demonstrate how:

    http://msdn.microsoft.com/en-us/library/aa365801(VS.85).aspx


    Michael Asher
    Sunday, May 10, 2009 5:24 AM
  • You are trying to solve a hardware problem in software, that's not the way to do it.  If your LAN doesn't get a heart attack from you claiming that static IP, there's no point in switching back and forth.  Just claim the address permanently.  But it will likely get upset with you, you are going to knock somebody else off the network.  Who will promptly reboot her machine and knock you off.

    You'll have to unplug your machine first.  That gets really old really quickly.  Just buy another NIC, they are a dime a dozen.
    Hans Passant.
    Sunday, May 10, 2009 11:43 AM
    Moderator
  • To _persistently_ change the IP address, you need to access the registry key:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet \Services\TcpIp\Parameters\Interfaces

    And then iterate for the proper network card.

    To change it just for a single session, you can use the AddIPAddress/DeleteIPAddress functions.  The following article has a code example to demonstrate how:

    http://msdn.microsoft.com/en-us/library/aa365801(VS.85).aspx


    Michael Asher

    Thank you very much Michael.

    Actually, I'm already using AddIPAddress and DeleteIPAddress.  They work very well.  For example, when I add IP 192.168.0.215, I can see it in the "Local Area Connection Status" Support tab.  However, when I go to the "Internet Protocol (TCP/IP) Properties" General tab, I see that both the "IP Address" and "DNS Server Address" radio groups are set to "Obtain Automatically".  My (maybe incorrect) understanding is that this means the network adapter is still in DHCP mode.  If it was not in DHCP mode, I would have expected the "IP Address" radio button be set to "Use the Following IP Address" 192.168.0.215 (which is the one I added with AddIPAddress).  But maybe I'm wrong.

    Please allow me to further clarify my application.  The embedded system I must talk to via ethernet is a VxWorks-based board that has adequate but limited on-board TCP support.  When it boots, it expects to become the server (it cannot operate as a client).  And it has absolutely no DHCP support.  It's IP address is static, and it expects to talk to a static client IP address (i.e. my PC app).  No one else will ever be on the network (guaranteed).  And the PC will have only one network adapter, named "Local Area Connection" (guaranteed).

    I'm a rank novice in the ethernet arena.  All I know at this point is that my PC app must talk to a server that has no DHCP support of its own, and both it and the client are at static IPs.  Maybe I can do this while the PC is still in DHCP mode.  I don't know.

    Thanks in advance for any help or clarification you can give.
    Sunday, May 10, 2009 6:24 PM
  • DHCP controls how the machine obtains an IP address -- once an IP address is set, though, DHCP is meaningless. In other words, using AddIPAddress to change the address doesn't affect DHCP at all...it merely means it obtains the address from the call, rather than from a DHCP server.

    That said, it shouldn't affect your communications with this VxWorks card.  As long as both have valid IP addresses and are on the same LAN segment, the lack of a DHCP server shouldn't be any problem at all.

    However, what Nobugs was saying (and I agree with him) is that an easier solution for you may be one of the following:

      - If you can leave the IP address of your client as 192.168.0.215, then do just that.  Leave it there, and forget changing it programmatically.
      - If you CAN'T leave the IP address set to that address, then buy a second NIC to dedicate to that address, and leave the first one alone.
    Michael Asher
    Sunday, May 10, 2009 7:13 PM
  • Hi bigmac44mag,

    Did AddIPAddress work for you. I have tried that API and it doesn't work for me. The code which I have used is exactly the same as you have done.  Any tips on this is highly appreciated.

    Regards,
    Chitra
    Thursday, February 18, 2010 8:27 AM
  • I have been having a similar issue, I deal with several remote system. I never know what I need my IP address to be or what the Mask is going to be when I get there.

    I found an ms dos command to set the IP, Mask and Gateway

    netsh interface ip set address "Local Area Connection" IP MASK GATEWAY

    in C++ you can use system(const char*)  to call an ms dos command

    in c#

    System.Diagnostics.Process.Start("cmd", string args);

    simple c++ code

    #include <iostream>
    #include <string>
    using namespace std;

    void setdhcp()
    {
        system("netsh interface ip set address \"Local Area Connection\" dhcp");
    }

    void setStaticIP(string IP, string Mask, string GateWay)
    {
        string str = "netsh interface ip set address \"Local Area Connection\" static ";
        str.append(IP);
        str.append(" ");
        str.append(Mask);
        str.append(" ");
        str.append(GateWay);
        system(str.data());
    }

    void main()
    {
        string stat;
        cout << "Set Static           : ";
        cin >> stat;
        if(stat[0] == 'N' || stat[0] == 'n')
        {
            setdhcp();
            return;
        }
        
        string IP;
        string Mask;
        string GateWay;
        
        cout << "Enter the IP Address:  ";
        cin >> IP;

        cout << "Enter the Subnet Mask: ";
        cin >> Mask;

        cout << "Enter The Gateway:     ";
        cin >> GateWay;
        setStaticIP(IP, Mask, GateWay);
    }

    c#

    private void btnDhcp_Click(object sender, EventArgs e)
            {
                System.Diagnostics.Process.Start("cmd", "/c netsh interface ip set address \"Local Area Connection\" dhcp");
            }

    private void btnStatucIP_Click(object sender, EventArgs e)
            {
                string args = "/c netsh interface ip set address \"" + txtConnection.Text + "\" static "
                    + ip.ToString()//where IP is some IP address

                    + " "
                    + mask.ToString();//where mask is some IP Mask
                System.Diagnostics.Process.Start("cmd", args);
            }

    Thursday, December 06, 2012 4:59 AM