SuperHouse / esp-open-rtos

Open source FreeRTOS-based ESP8266 software framework
BSD 3-Clause "New" or "Revised" License
1.54k stars 489 forks source link

STATIONAP_MODE not working #367

Open psankovic opened 7 years ago

psankovic commented 7 years ago

Hello,

I've been trying to set up STATIONAP_MODE without success. ESP is connecting to my local Wifi network, and I can see that ESP Wifi network is created. However when I try to connect to it via iphone or windows PC or Mac I get IP address but always I get "No internet access". I was looking into DHCP process and noticed ESP is not returning some parameters (like Router address). Also I noticed that sometimes I lose connection from ESP to local wifi after I connect to AP with my phone. Any advice?

My wifi task is as following:

static void  wifi_task(void *pvParameters) {

    uint8_t status  = 0;
        uint8_t retries = 30;
    sdk_wifi_set_opmode(STATIONAP_MODE);
    printf("WiFi: connecting to WiFi\n\r");
    struct sdk_station_config config = {
        .ssid = WIFI_SSID,
        .password = WIFI_PASS,
    .bssid_set=0,

    };

    sdk_wifi_station_set_config(&config);
    struct ip_info ap_ip;
    IP4_ADDR(&ap_ip.ip, 172, 16, 0, 1);
    IP4_ADDR(&ap_ip.gw, 172, 16, 0, 1);
    IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
    sdk_wifi_set_ip_info(1, &ap_ip);
    struct sdk_softap_config *cfg=(struct sdk_softap_config *)malloc(sizeof(struct sdk_softap_config));
    sdk_wifi_softap_get_config(cfg);
    sprintf((char *)cfg->ssid,AP_SSID);
    sprintf((char *)cfg->password,AP_PSK);
    cfg->ssid_hidden=0;
    cfg->channel=3;
    cfg->ssid_len=strlen(AP_SSID);
    cfg->authmode=AUTH_WPA2_PSK;
    cfg->max_connection=30;
    cfg->beacon_interval=100;
    sdk_wifi_softap_set_config(cfg);
    ip_addr_t first_client_ip;
    IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
    dhcpserver_start(&first_client_ip, 4);
    while(1)
    {
        while ((status != STATION_GOT_IP) && (retries)){
            status = sdk_wifi_station_get_connect_status();
            printf("%s: status = %d\n\r", __func__, status );
            if( status == STATION_WRONG_PASSWORD ){
                printf("WiFi: wrong password\n\r");
                break;
            } else if( status == STATION_NO_AP_FOUND ) {
                printf("WiFi: AP not found\n\r");
                break;
            } else if( status == STATION_CONNECT_FAIL ) {
                printf("WiFi: connection failed\r\n");
                break;
            }
            vTaskDelay( 1000 / portTICK_PERIOD_MS );
            --retries;
        }
        if (status == STATION_GOT_IP) {
            printf("WiFi: Connected\n\r");
            retries=30;
            xSemaphoreGive( wifi_alive );
            taskYIELD();
        }
        while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) {
            xSemaphoreGive( wifi_alive );
            taskYIELD();
        }
        printf("WiFi: disconnected\n\r");
        sdk_wifi_station_disconnect();
        sdk_wifi_set_opmode(STATIONAP_MODE);
        sdk_wifi_station_set_config(&config);
        sdk_wifi_softap_set_config(cfg);

        xSemaphoreTake(wifi_alive, 10000 / portTICK_PERIOD_MS);
        vTaskDelay( 1000 / portTICK_PERIOD_MS );
    }
}
stschake commented 7 years ago

When the ESP is hosting a network, there is no internet access - where should that come from? The ESP can't simultaneously be a hotspot and logged into another network as a client. That is also why it makes no sense to send a router for DHCP - there is no other network the ESP can route into.

Smartphones have lots of heuristics to decide when they should be in WLAN or on the mobile network, and since the ESP hotspot has no internet connectivity, yours might simply decide it's not worthwhile to stick around and instead goes back to mobile data.

kanflo commented 7 years ago

A good explanation @stschake, I will close this issue.

psankovic commented 7 years ago

Do what's the point of having stationap mode. I assumed that in stationap mode esp would route traffic from one wifi network to other. Never the less that is not my biggest problem. I wanted to have ap and station mode at the same time so i could have mqtt traffic sent over station interface to my mosquitto server and use ap interface for telneting to esp and be able to change settings over it. /pp, Petar

kanflo commented 7 years ago

StationAP is used for configuring the wifi thingy. You connect and set your wifi credentials after which the ESP connects to your wifi. Access Point mode (what you are looking for) is not supported is it would require two network interfaces.

pfalcon commented 7 years ago

it would require two network interfaces.

There are 2 interfaces supported by ESP. They are virtual interfaces, but still pretty real (and that's a basic wifi feature, i.e. majority of non locked-down devices support that). Routing between interfaces is a completely different matter though.

psankovic commented 7 years ago

Hello, Let me sum up what I know and what I assume:

  1. I'm 99% sure that ESP can work in AP and STATION mode simultaneously (chapter 3.2.4 from ESP RTOS programming guide https://espressif.com/sites/default/files/documentation/20a-esp8266_rtos_sdk_programming_guide_en.pdf )
  2. I assume that by running STATIONAP_ mode I will run Station and AP mode at the same time(notice the name STATIONAP=STATION+AP). Station mode interface will allow ESP to connect to Wifi broadcasted by my Wifi router (SSID: xxxx), and AP mode where ESP will broadcast it's own Wifi network (SSID: yyyy)

In case ESP station instance get IP address from router (e.g.) 192.168.1.20 and own IP address defined by AP mode 192.168.10.1 and by DHCPserver running on ESP any client connect to it will get IP 192.168.10.2 and so on. I assumed that ESP will know how to route traffic from incoming 192.168.10.x network to 192.168.1.x network. ESP MASH topology actually relay on this routing feature. So it is supported by ESP (I believe that I did not configured it properly). However in my case once I connect with client on AP interface and get 192.168.10.x IP addess on my comp, Station interface for some reason goes down since my MQTT traffic generated by ESP toward external mosquitto server dies and it never recover. The only solution is to restart ESP. As long as I do not connect to AP interface with clients my STATION connection and MQTT traffic is running fine. Something similar has been done on this port: https://github.com/ourairquality/esp-open-rtos and discussion about it in https://github.com/SuperHouse/esp-open-rtos/pull/208. I have tried to do local merge with this port, failed miserably :-(

/regards

kanflo commented 7 years ago

I stand corrected. Thanks @pfalcon and sorry @psankovic. I will reopen the issue as this is something that we should be able to get working.

psankovic commented 7 years ago

Thanks. kanflo. I was wondering can it be related to fact that I'm starting wifi from task. I noticed that majority of examples have wifi initialization in user_init(). To be honest I feel that it's issue in my code, since I do not believe that such case was never tried before. But then again I did have crazy ideas that nobody thought off......

kanflo commented 7 years ago

Please let us know if moving wifi init does any difference @psankovic.

psankovic commented 7 years ago

No it did not help. I also tried solution listed in #153 netif_set_default(netif_find("en0"));

or if (sdk_g_ic.s.wifi_mode == 3) { sdk_wifi_station_start(); sdk_wifi_softap_start();

ifdef DEFAULT_IFACE_STATION

    netif_set_default(sdk_g_ic.v.station_netif_info->netif);

else

    netif_set_default(sdk_g_ic.v.softap_netif_info->netif);

endif

}

buth both did not help me.

gpreviato commented 7 years ago

It's working but you have to manage the routing table.

Lwip has poor feature (but it's understandable..).

You have just to manage the routing in lwip defining the LWIP_HOOK_IP4_ROUTE macro in file lwip/src/core/ipv4/ip.c * extract ** struct netif ip_route(ip_addr_t dest) { struct netif *netif;

ifdef LWIP_HOOK_IP4_ROUTE

netif = LWIP_HOOK_IP4_ROUTE(dest); if (netif != NULL) { return netif; }

endif

... hope this helps....

regards,

--gra

rameshKrSah commented 7 years ago

following @gpreviato suggestion, I did this :

            struct ip_info ip_info = {0};
        struct netif * netif_info;
        sdk_wifi_get_ip_info(0, &ip_info);
        netif_info = ip_route(&ip_info.ip);
        netif_set_default(netif_info);

This solved the problem partially and ESP is working properly as a station when in STATION_AP mode. But while trying to connect to the ESP from other wifi device, ESP cannot assign proper IP to the incoming stations and there are multiple DHCP errors. I guess this is due to the fact that I changed the default IP routing table from AP to STATION by using the above code.

Also there is a similar issue here: #153

gpreviato commented 7 years ago

You have to pay attention to some network routing basics: 1) The default router of the stations connecting the ESP must be the ESP itself; 2) The default router of the ESP, must be the address received by the station via dhcp; 3) You need a basic routing table, implemented throw the ip_route function, that send the packets to the right interface: the local one distributed by the AP, to the AP interface, for the address outside your 'ESP net'.

... you want ESP act as a router between two nets, you need to give it the right information...

rameshKrSah commented 7 years ago

@gpreviato thank you for the advice. After a bit of experimenting to relay the packets to the respective interfaces by using the source and destination port to differentiate between the netifs, I was able to run the both mode simultaneously and achieve proper functionality.

What I did was to introduce a function which selects the correct netif based on the source and destination port number just prior to the ip_route function called in the udp_sendto_chksum function in udp.c file, like this:

#if LWIP_IGMP
  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
#else
netif = ip_route_for_dhcpserver(pcb->local_port, dst_port);             //added to selects netifs
  if(netif == NULL) {
    netif = ip_route(dst_ip);
  }
#endif /* LWIP_IGMP */

I also set the station netif to default and manually assined the AP netif to netif for the dhcpserver structure instance state in the dhcpserver.c as:

struct ip_info ip_info;
sdk_wifi_get_ip_info(SOFTAP_IF, &ip_info);
ap_mode_netif = ip_route(&ip_info.ip);
state->server_if = ap_mode_netif;

Also, the defination of the function ip_route_for_dhcpserver is :

static struct netif * ap_mode_netif;
struct netif * ip_route_for_dhcpserver(uint16_t local_port, uint8_t dest_port){
    if((local_port == 67) && (dest_port == 68)){
        return ap_mode_netif;
    }
    return NULL;
}
gpreviato commented 7 years ago

@rameshKrSah I'm glad you have solved your problem. Anyway, to have a most portable solution, I suggest you to use the LWIP_HOOK_IP4_ROUTE macro where you can match addresses and netmasks. Could be, in the future, maintainers will decide to implement a static routing table accessed by a function.