This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC3220: DNS server not published by internal DHCP server in AP mode

Part Number: CC3220

Hi,

I tried to configure the AP mode in Uniflash so that the only enabled network applications are HTTP and DHCP (mDNS and DNS are OFF).

Also, I have entered IP addresses in the network settings (including a DNS server).

I found out that the DNS server does not get sent/communicated to the clients that connect to the DHCP server.

If the DNS application is running, the DNS server address is sent correctly.

Please note that in this example the DNS IP is equal to the gateway IP, but the same happens if you use another DNS IP.

How can you force the DHCP server to send the DNS IP when a client connects... ?

BR,

Salvatore

  • Hi Salvatore,

    "I found out that the DNS server does not get sent/communicated to the clients that connect to the DHCP server.
    If the DNS application is running, the DNS server address is sent correctly."
    Can you clarify here? Is the DNS server not working when you have the DNS enabled in application code?

    Best regards,
    Sarah
  • Hi Sarah,

    let me try to rephrase;

    when you disable the DNS server, the DHCP server will not publish the DNS server IP address that was configured in the network settings. 

    Imagine the scenario where you wish the CC3220 to be set as AP, with the address 10.0.0.1, gateway 10.0.0.2, subnetmask 255.255.255.0 and DNS 10.0.0.5 (=> could be external DNS server running in local network).

    In this scenario, the internal DNS server is disabled. Now, when a client connects to the DHCP server in our AP, it will get an IP address, it will receive the subnetmask, the gateway, but NOT the DNS server IP.

    (When the DNS server is enabled on the CC3220, then this DNS IP is published by the DHCP server to the clients to connect to it)

    Best regards,

    Salvatore 

  • Hi Salvatore,

    I think I understand your question: You'd like the CC3220 acting as the AP to forward the DNS from your external DNS server to a station connected to the CC3220. I do not believe the CC3220 supports this functionality.

    I'm still confused about what your use case is for this application. The CC3220 is a Soft AP, so it is not connected to the internet. What use would an external DNS server be in this situation?

    Best regards,
    Sarah
  • Hi Sarah,
    I understand your confusion; perhaps I am not explaining correctly.

    Let me explain the use case I have/need.
    I wish to use my own DNS server implementation (which I have working fine) because the internal one is too restricted for my application.
    The problem is:
    1. If I configure the DNS server as "enabled" in Uniflash, I am unable to shut it down with sl_NetAppStop => does not work (see my other post)
    2. If I configure the DNS server as "disabled" in Uniflash, the internal DNS server is not running, but then, the internal DHCP server does not publish the configured DNS IP in Uniflash to the connected client.

    Unless sl_NetAppStop() gets fixed or the DHCP server publishes the configured DNS IP to clients that are connecting, I see no other option than to run my own DHCP server code...

    BR,
    Salvatore
  • Hi Salvatore,

    Unfortunately, the DHCP is not set up to work with other DNS server implementations. You would have to implement your own DHCP for that case.

    May I ask what functions are restricted in the internal DNS that you'd like to use?

    Best regards,
    Sarah

  • Hi Sarah,

    I would like the DHCP server to *always* publish the option "DOMAIN NAME SERVER" as described in RFC2132.

    My point is, the internal DHCP server implementation seems to do it, but *only* if the DNS server is marked as enabled at provisioning.
    Even if you configure one in the network settings (in Uniflash).

    As for the internal DNS server, I can not use the internal one, because I would the DNS server to resolve *every* request to a fixed IP address. 

    BR,
    Salvatore

  • Hi Salvatore,

    You are correct, we only support this option when the domain name server on our device is enabled.

    You can use any external DNS server in station mode and set it according to section IPv4 Addresses of the NWP Programmer's Guide: http://www.ti.com/lit/swru455
    As an AP, we do not have the option to specify a given IP address for a DNS server since our device was not designed as internet gateway or router. I can file an internal feature request for review, but it would not be a quick turnaround.

    Best regards,
    Sarah
  • Hi Sarah,
    thanks for the update.
    Meanwhile, I have implemented my own basic DNS and DHCP server, which serve my purpose perfectly.
    For those interested, I am now able to provide a nice captive portal.
    BR,
    Salvatore
  • Salvatore,

    I've been watching this thread as I've had issues with the reliability of the CC3220 DHCP server in AP mode and am considering the custom DHCP.  Any chance you would be willing to share your DHCP implementation?  I think this would be nice since it would give people the ability to control their server behavior rather than rely on the TI R&D team.

    Thanks

  • Hi,
    sure. Please give me some time to clean up the code :-)
    Also know that it is a very basic implementation.
    I will post it here in a few days.
    BR,
    Salvatore
  • Thanks Salvatore! I'm glad your custom implementation worked for you.
  • Hi Andrew,

    as promised, please find attached a zip file with my custom DHCP server implementation which runs on CC3220S using the TI-RTOS.

    Start a task with the dhcpServer() method (fyi; I used 8KB of stack just to be sure).

    Note that this implementation is very basic and limited in its functionality; yet it serves my purpose; which is allowing clients to connect with a captive portal to enter provisioning info for the WiFi network to use in STA mode. (you need a custom DNS as well; but that is really easy to implement)

    Have fun with it, and if you find bugs/improvements, please; let me know.

    BR,

    Salvatore

    2437.DHCPServer.zip

  • Salvatore, thanks for sharing. I read through it a bit and it appears quite good. I'll try it out and see how it does. Just to clarify, do you mean to start it you just create a task that calls void* dhcpTask(void *pvParameters) . I'm assuming this is what you mean because I did not find dhcpServer() method.
  • Salvatore,

    Where do you get the following file? I don't see it anywhere in the SDK?

    #include <ti/net/slnetutils.h>

    I believe you need it for the following: SlNetUtil_htonl()
  • Hi,

    I am not sure which (part of) SDK it is part of; SlNetUtils ... ?

    Anyway, you can change it without worries to either sl_Htonl(xxx) (part of /ti/drivers/net/wifi/ I believe)

    OR simply htonl(xxx); it simply changes the byte order.

    If you can not find the SlNetUtil_htonl() implementation, and wish to see it; here it goes:

    //*****************************************************************************
    //
    // SlNetUtil_htonl - Reorder the bytes of a 32-bit unsigned value from host
    //                   order to network order(Big endian)
    //
    //*****************************************************************************
    uint32_t SlNetUtil_htonl(uint32_t val)
    {
        uint32_t i = 1;
        int8_t  *p = (int8_t *)&i;
    
        /* When the LSB of i stored in the smallest address of *p                */
        if (p[0] == 1) /* little endian */
        {
            /* Swap the places of the value                                      */
            p[0] = ((int8_t *)&val)[3];
            p[1] = ((int8_t *)&val)[2];
            p[2] = ((int8_t *)&val)[1];
            p[3] = ((int8_t *)&val)[0];
    
            /* return the reordered bytes                                        */
            return i;
        }
        else /* big endian */
        {
            /* return the input without any changes                              */
            return val;
        }
    }
    

    BR,

    Salvatore

  • Hi Andrew,

    The network utility and network socket layers were added in SDK v1.60 in part to provide standard BSD sockets across the SimpleLink platform. You should see this file in source/ti/net/ if you download the latest SDK.

    Best regards,
    Sarah
  • Yes I figured it out. Thank you. I'm trying to work this code into the out of box demo. I created a DHCP task where the rest of the tasks are created. I seem to get errors and I'm not sure why...



    //****************************AP DHCP SERVER*********************************/
    pthread_attr_init(&pAttrs);
    priParam.sched_priority = 3;
    RetVal = pthread_attr_setschedparam(&pAttrs, &priParam);
    RetVal |= pthread_attr_setstacksize(&pAttrs, DHCP_STACK_SIZE);

    if(RetVal)
    {
    /* Handle Error */
    UART_PRINT("Unable to configure DHCPTask thread parameters \n");
    while(1);
    }

    RetVal = pthread_create(&gDHCPThread, &pAttrs, dhcpTask, NULL);

    if(RetVal)
    {
    /* Handle Error */
    UART_PRINT("Unable to create DHCPTask thread \n");
    while(1);
    }
    //***************************************************************/


    Inside dhcp_server.c

    void* dhcpTask(void *pvParameters) {
    _i16 status;
    _i16 server;
    SlSockAddrIn_t localAddr;

    initConnectionPool();

    UART_PRINT("STOPPING INTERNAL DHCP\n\r");
    sl_NetAppStop(SL_NETAPP_DHCP_SERVER_ID);
    UART_PRINT("STARTING DHCP\n\r");


    I get the following printed out on the UART:

    STARTING DHCP
    STOPPING INTERNAL DHCP
    DHCP Error: socket not created. Code: -2018

    This supposedly means the device is not started.  Even if I add sl_start(0,0,0) after initConnectionPool() it still fails.

  • Salvatore,

    I guess I was starting the task at a point where sl_start hadn't been called. Not sure why, but I got it going and see no errors. Sorry about that.

    However, I do only see the code get as far as just before:

    int n = sl_RecvFrom(server, &request.hdr, sizeof(request.hdr), 0, (SlSockAddr_t*)&clientAddr, &addrlen);

    I never see it execute further even when a station connects to the CC3220. I'm pretty sure I have this configured correctly
  • I got a little farther by making RecvFrom() non binding and having the software loop on it. I just always get RecvFrom() returning 0 even with a client attempting connection. I would think disabling the onboard DHCP server with sl_NetAppStop() would free up the ports 67 and 68. It almost acts like they are not available.  sl_RecvFrom() always returns 0 which I did not expect.

    void* dhcpTask(void *pvParameters) {
        _i16 status;
        _i16 server;
        SlSockAddrIn_t  localAddr;
    
        initConnectionPool();
    
        //sl_Start(0, 0, 0);
    
        //Task_sleep(5000);
        UART_PRINT("STOPPING INTERNAL DHCP\n\r");
        sl_NetAppStop(SL_NETAPP_DHCP_SERVER_ID);
        UART_PRINT("STARTING DHCP\n\r");
    
        while (1) {
    
            server = sl_Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if (server < 0) {
                UART_PRINT("DHCP Error: socket not created. Code: %d\r\n", server);
                goto shutdown;
            }
    
            // Make non-blocking 
            SlSockNonblocking_t BlockingOption;
            BlockingOption.NonBlockingEnabled = 1;
            sl_SetSockOpt(server,SL_SOL_SOCKET,SL_SO_NONBLOCKING,(_u8*)&BlockingOption,sizeof(BlockingOption));
            // Make non-blocking 
    
            memset(&localAddr, 0, sizeof(SlSockAddrIn_t));
            localAddr.sin_family = AF_INET;
            localAddr.sin_addr.s_addr = sl_Htonl(INADDR_ANY);
            localAddr.sin_port = sl_Htons(67);
    
            status = sl_Bind(server, (SlSockAddr_t *)&localAddr, sizeof(SlSockAddrIn_t));
            if (status < 0) {
                UART_PRINT("DHCP Error: bind failed. Code: %d\r\n", status);
                goto shutdown;
            }
    
            UART_PRINT("Got through DHCP init\n\r");
    
            while (1) {
                DhcpMessage request;
                DhcpMessage reply;
                SlSockAddrIn_t  clientAddr;
                SlSocklen_t addrlen = sizeof(clientAddr);
    
                Task_sleep(1000);
                int n = sl_RecvFrom(server, &request.hdr, sizeof(request.hdr), 0, (SlSockAddr_t*)&clientAddr, &addrlen);
    
                UART_PRINT("n = %d\n\r", n);
    
    
                if(n == SL_EAGAIN || n == 0)
                {
    
                }
                else if (n >= DHCP_HEADER_SIZE + 5) {
    
    
                    cleanConnectionPool();
    
                    if (request.hdr.op != BOOTREQUEST) {
                        UART_PRINT("DHCP Error: No BOOTREQUEST found.\r\n");
                        continue;
                    }
                    uint8_t type = _expandRequest(&request, n);
                    if (type == 0) {
                        UART_PRINT("DHCP Error: No Type found.\r\n");
                        continue;
                    }
    
                    _initReply(&request, &reply);
                    switch (type) {
                    case DHCP_DISCOVER:     type = _serveDhcpDiscover(&request, &reply); break;
                    case DHCP_REQUEST:      type = _serveDhcpRequest(&request, &reply); break;
                    case DHCP_DECLINE:      type = _serveDhcpDecline(&request, &reply); break;
                    case DHCP_RELEASE:      type = _serveDhcpRelease(&request, &reply); break;
                    case DHCP_INFORM:       type = _serveDhcpInform(&request, &reply); break;
                    default:    UART_PRINT("DHCP Error: Invalid DHCP Type found.\r\n"); type = 0; break;
    
                    UART_PRINT("DHCP TYPE: %d\n\r", type);
    
                    }
                    if (type != 0) {
                        _sendDhcpReply(server, &clientAddr, &reply, type);
                    }
                } else {
                    UART_PRINT("DHCP Error: Strange. Error on RecvFrom. Code: %d\r\n", n);
                    goto shutdown;
                }
            };
    shutdown:
            // if this occurs a couple of times (errorCount); perform a full system reset?
            // but make sure to "reset" the errorCount in case we do continue
            if (server >= 0) {
                sl_Close(server);
            }
            sleep(5);
        }
    }

  • Hi,

    I'm not exactly sure what is different in your setup; please try the same code I sent before but use the following initialisation code. I think the setup of the NWP is different and causing you troubles.

    Important note; make sure the DHCP (and DNS) are UNchecked in Uniflash when you flash your device.

    Also; I am using the latest versions; SDK v2.20... and latest servicepack (v3.8.0.3...).

    Tip; I use Wireshark in order to capture the data traffic between client <-> DHCP server. Helps a lot to see what is actually sent :-)

    //...
        _startNewTask(&gWifiThread, sl_Task, 9, WIFI_STACK_SIZE);
    //...
    
    // I took out error handling for readability, make sure to check every step 
        int8_t RetVal;
        RetVal = sl_Start(0, 0, 0);
        RetVal = sl_WlanSetMode(ROLE_AP);
        RetVal = sl_Stop(0);
        RetVal = sl_Start(0, 0, 0);
    
        wifiConfigure(); // see below for implementation
    //...
    
    void wifiConfigure(void) {
    
        UART_PRINT("[DEBUG] - wifiConfigure\r\n");
    
        // Set policy to auto only
        UART_PRINT("[*] - Set policy to auto only\r\n");
        int16_t RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION, SL_WLAN_CONNECTION_POLICY(1,0,0,0), NULL ,0);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // Disable Auto Provisioning
        UART_PRINT("[*] - Disable Auto Provisioning\r\n");
        RetVal = sl_WlanProvisioning(SL_WLAN_PROVISIONING_CMD_STOP, 0xFF, 0, NULL, 0x0);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        UART_PRINT("[*] - Configure AP IP configuration\r\n");
        SlNetCfgIpV4Args_t ipV4;
        ipV4.Ip = (_u32)SL_IPV4_VAL(10,0,0,1);        // IP address
        ipV4.IpMask = (_u32)SL_IPV4_VAL(255,255,255,0); // Subnet mask
        ipV4.IpGateway = (_u32)SL_IPV4_VAL(10,0,0,1); // Default gateway address
        ipV4.IpDnsServer = (_u32)SL_IPV4_VAL(10,0,0,1); // _u32 DNS server address
        RetVal = sl_NetCfgSet(SL_NETCFG_IPV4_AP_ADDR_MODE, SL_NETCFG_ADDR_STATIC, sizeof(SlNetCfgIpV4Args_t), (_u8*)&ipV4);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Tried this to 'trick' internal DHCP server; didn't work
        UART_PRINT("[*] - Configure Second DNS Client\r\n");
        SlNetCfgIpV4DnsClientArgs_t DnsOpt;
        DnsOpt.DnsSecondServerAddr = SL_IPV4_VAL(10,0,0,1);
        RetVal = sl_NetCfgSet(SL_NETCFG_IPV4_DNS_CLIENT, 0, sizeof(SlNetCfgIpV4DnsClientArgs_t), (unsigned char *)&DnsOpt);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Enable DHCP client
        UART_PRINT("[*] - Enable STA DHCP client\r\n");
        RetVal = sl_NetCfgSet(SL_NETCFG_IPV4_STA_ADDR_MODE, SL_NETCFG_ADDR_DHCP, 0, 0);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Disable ipv6
        UART_PRINT("[*] - Disable ipv6\r\n");
        const uint32_t IfBitmap = !(SL_NETCFG_IF_IPV6_STA_LOCAL | SL_NETCFG_IF_IPV6_STA_GLOBAL);
        RetVal = sl_NetCfgSet(SL_NETCFG_IF, SL_NETCFG_IF_STATE, sizeof(IfBitmap), (const unsigned char *)&IfBitmap);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Configure scan parameters to default
        UART_PRINT("[*] - Configure scan parameters to default\r\n");
        const SlWlanScanParamCommand_t ScanDefault = { .ChannelsMask = CHANNEL_MASK_ALL, .RssiThreshold = RSSI_TH_MAX };
        RetVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, SL_WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS, sizeof(ScanDefault), (uint8_t *)&ScanDefault);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // Disable scans
        UART_PRINT("[*] - Disable scans\r\n");
        const uint8_t ucConfigOpt = SL_WLAN_SCAN_POLICY(0, 0);
        RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_SCAN , ucConfigOpt, NULL, 0);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // Set TX power lvl to max
        UART_PRINT("[*] - Set TX power lvl to max\r\n");
        const uint8_t ucPower = 0;
        RetVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, SL_WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, 1, (uint8_t *)&ucPower);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // Set NWP Power policy to 'Always ON' => seems to be important for ARP packets - read it online somewhere
        UART_PRINT("[*] - Set NWP Power policy to 'Always ON'\r\n");
        RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_PM, SL_WLAN_ALWAYS_ON_POLICY, NULL, 0);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // Set new device name
        UART_PRINT("[*] - Set new device name\r\n");
        const _u8* const device_name = "myexample";
        RetVal = sl_NetAppSet(SL_NETAPP_DEVICE_ID, SL_NETAPP_DEVICE_URN, strlen((const char*)device_name), (_u8*)device_name);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Set new device url
        UART_PRINT("[*] - Set new device url\r\n");
        const _u8* const device_url = "myexample.com";
        RetVal = sl_NetAppSet(SL_NETAPP_DEVICE_ID, SL_NETAPP_DEVICE_DOMAIN, strlen((const char*)device_url), (_u8*)device_url);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Unregister mDNS services
        UART_PRINT("[*] - Unregister mDNS services\r\n");
        RetVal = sl_NetAppMDNSUnRegisterService(0, 0, 0);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Stop DHCP service
        UART_PRINT("[*] - Stop the DHCP service\r\n");
        RetVal = sl_NetAppStop(SL_NETAPP_DHCP_SERVER_ID);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Stop mDNS service
        UART_PRINT("[*] - Stop the mDNS service\r\n");
        RetVal = sl_NetAppStop(SL_NETAPP_MDNS_ID);
        ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Stop DNS service - doesn't work ?!
        UART_PRINT("[*] - Stop the DNS service\r\n");
        RetVal = sl_NetAppStop(SL_NETAPP_DNS_SERVER_ID);
        if (RetVal < 0) {
            UART_PRINT("  Error: %d\r\n", RetVal);
        }
    //    ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);
    
        // Remove all 64 RX filters (8*8)
        UART_PRINT("[*] - Remove all 64 RX filters (8*8)\r\n");
        SlWlanRxFilterOperationCommandBuff_t RxFilterIdMask = {{0}};
        memset(RxFilterIdMask.FilterBitmap , 0xFF, 8);
        RetVal = sl_WlanSet(SL_WLAN_RX_FILTERS_ID, SL_WLAN_RX_FILTER_REMOVE, sizeof(SlWlanRxFilterOperationCommandBuff_t),(uint8_t *)&RxFilterIdMask);
        ASSERT_ON_ERROR(RetVal, WLAN_ERROR);
    
        // For changes to take affect, we restart the NWP
        UART_PRINT("[*] - For changes to take affect, we restart the NWP\r\n");
        RetVal = sl_Stop(0xFF);
        ASSERT_ON_ERROR(RetVal, DEVICE_ERROR);
    
        RetVal = sl_Start(0, 0, 0);
        ASSERT_ON_ERROR(RetVal, DEVICE_ERROR);
    
        UART_PRINT("[*] - Done!\r\n");
    }
    
    
    

  • OK, I will try it tonight. Why do I need to turn off the DNS server? That is on port 53 which should not interfere with DHCP. Or am I misunderstanding?

    I am also using wireshark but only see DHCP requests from the client.  No response from CC3220.  The existing code already configures it for AP, DHCP, DNS, mDNS, and DHCP.  All I did was disable DHCP.  I don't see why it wouldn't work unless there is some dependency I don't understand.

  • I got it working. There was a task dependency where sl_start had not been called before the recvfrom() call. DHCP appears to work good, although I haven't tested it too much.

    I have run into a new issue. If I enable the DHCP task, the onboard HTTP server does not work and the CPU locks up when a device requests the webpage. Stack size is good all all tasks (DHCP task only uses ~2K). Are you having issues using the onboard web server? I find this very strange. If I disable DHCP task and use CC3220 DHCP, everything works fine and web page comes up just fine.
  • I got it all working now with my code. I will test more and report back on the reliability. Thank you again for sharing! I did notice that your DHCP messages don't show up in wireshark when I filter "bootp".
  • Hi,

    glad you got it working. :-)

    1. The DNS server does not have to be disabled; you are correct; in my case it had to, because I use my own DNS server, in order to have my captive portal working.

    2. I am not sure why you are not seeing the DHCP server responses in Wireshark; are you using the multicast address 255.255.255.255 in the UDP sendto() method ? In my setup here, I see all responses using the bootp filter in Wireshark.

    3. If you have any feedback, please do let me know! :-)

    BR,

    Salvatore