Using the Zephyr net_mgmt_xxx callback events to determine when wifi & TCP/IP stack is ready to use?

I have used the wifi sta samples as the base for my wifi/network handling code running on custom product board using nrf5340/nrf7002 with NCS 2.8.

However, I have trouble understanding a couple of things about the net_mgmt events/callbacks, and can't work out how to reliably start network dependant code on top of them.

Q1: I use the following code to say 'tell me when the events I want happen':

	net_mgmt_init_event_callback(&(ctx->wifi_sta_mgmt_cb),
				_wifi_mgmt_event_handler,
				// bizarre to or these when they are not bitmask seperated..
				NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | NET_EVENT_WIFI_IFACE_STATUS| NET_EVENT_WIFI_CMD_DISCONNECT_COMPLETE);

	net_mgmt_add_event_callback(&(ctx->wifi_sta_mgmt_cb));

	net_mgmt_init_event_callback(&(ctx->net_addr_mgmt_cb),
				_net_mgmt_event_handler,
				NET_EVENT_IPV4_DHCP_START|NET_EVENT_IPV4_DHCP_BOUND|NET_EVENT_IPV4_DHCP_STOP);

	net_mgmt_add_event_callback(&(ctx->net_addr_mgmt_cb));

	net_mgmt_init_event_callback(&(ctx->net_l4_mgmt_cb),
				_net_l4_event_handler,
				NET_EVENT_L4_CONNECTED|NET_EVENT_L4_DISCONNECTED);

	net_mgmt_add_event_callback(&(ctx->net_l4_mgmt_cb));

How does the 'event mask' parameter work, given that the various event enums are not in fact bit masks (they are just 1, 2, 3 valued, not 1,2,4,8 etc)? Seems like if I OR these toegther the mask is not going to match an event very well?

Q2: as you can see in the code, I want to get a NET_EVENT_L4_CONNECTED event. This was what I expected would tell me that the networking stack was ready to be used for IP based operation. Specifically, the definition of this event in net_event.h is:

/** Event emitted when the system is considered to be connected.
 * The connected in this context means that the network interface is up,
 * and the interface has either IPv4 or IPv6 address assigned to it.
 */
#define NET_EVENT_L4_CONNECTED                  \
    (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_CONNECTED)
However, I never get this event in the callback. I do get NET_EVENT_DNS_SERVER_ADD - despite not having this in my mask....
Currently I use the  NET_EVENT_IPV4_DHCP_BOUND event instead, but this causes a problem as this event is seen every few minutes (at least on my wifi AP setup) and as I trigger my mqtt reconnection when I see it this means the mqtt connection is continuously restarted...
Is NET_EVENT_L4_CONNECTED  the correct event to wait for? And what did I do wrong with the event mask that I don't get it?
thanks
  • For Q2 : which event to wait for:

    Is NET_EVENT_L4_CONNECTED  the correct event to wait for?

    I found this discussion on the zephyr issues list:

    https://github.com/zephyrproject-rtos/zephyr/issues/63284

    which implies the L4_CONNECTED event is the one to wait for....

    I observe that I get the following events in this order after asking the interface to connect:

    NET_EVENT_IPV4_DHCP_STOP
    NET_EVENT_IPV4_DHCP_START
    WIFI_STATUS_CONN_SUCCESS
    NET_EVENT_DNS_SERVER_ADD
    NET_EVENT_IPV4_ADDR_ADD
    NET_EVENT_IPV4_DHCP_BOUND
    However, never gets the 
    NET_EVENT_L4_CONNECTED
    event.
    I then get 
    NET_EVENT_IPV4_DHCP_BOUND
    every 5 minutes (presumably a DHCP lease refresh from the DHCP server)
    I have switched and use the NET_EVENT_IPV4_ADDR_ADD event to start my use of the network (open mqtt cnx etc). This seems to work, and as this event only occurs at connection time, I don't erroneously re-initialise every 5 minutes... 
    But I would still like to know where the L4_CONNECTED event is!
    For my Q1 about the event mask passed to net_mgmt_init_event_callback():
    How does the 'event mask' parameter work, given that the various event enums are not in fact bit masks (they are just 1, 2, 3 valued, not 1,2,4,8 etc)? Seems like if I OR these toegther the mask is not going to match an event very well?

     - I tried changing to this:

        net_mgmt_init_event_callback(&(ctx->net_l4_mgmt_cb),
                    _net_l4_event_handler,
                    _NET_EVENT_L4_BASE | 0xFF);
    (ie have the event id part be a mask with all bits set)
    No difference as far as I can see. Anyone got any ideas?
     
  • Hi,

    How does the 'event mask' parameter work, given that the various event enums are not in fact bit masks (they are just 1, 2, 3 valued, not 1,2,4,8 etc)? Seems like if I OR these toegther the mask is not going to match an event very well?

    The event mask is provided to ensure that the handler will listen for all relevant events, but it does not exclude irrelevant events.

    In other words, if you define WIFI_MGMT_EVENTS in one of the following ways:

    #define WIFI_MGMT_EVENTS (NET_EVENT_WIFI_CMD_SCAN_RESULT | NET_EVENT_WIFI_CMD_SCAN_DONE | NET_EVENT_WIFI_CMD_DISCONNECT_RESULT)

    #define WIFI_MGMT_EVENTS (NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT)

    It is the same as

    WIFI_MGMT_EVENTS = (_NET_WIFI_EVENT | 3) | (_NET_WIFI_EVENT | 4);

    WIFI_MGMT_EVENTS = (_NET_WIFI_EVENT | 1) | (_NET_WIFI_EVENT | 2) | (_NET_WIFI_EVENT | 4);

    Both of these results in the following:

    WIFI_MGMT_EVENTS = _NET_WIFI_EVENT | 7;

    The handler will listen to all events whose lover bits fit within 7, which means that in both these cases, the handler will listen to all of the following events:

    NET_EVENT_WIFI_CMD_SCAN_RESULT
    NET_EVENT_WIFI_CMD_SCAN_DONE
    NET_EVENT_WIFI_CMD_CONNECT_RESULT
    NET_EVENT_WIFI_CMD_DISCONNECT_RESULT
    NET_EVENT_WIFI_CMD_IFACE_STATUS
    NET_EVENT_WIFI_CMD_TWT
    NET_EVENT_WIFI_CMD_TWT_SLEEP_STATE

    However, this does not cause any issues because the handler is (usually) implemented to ignore irrelevant events in the switch case. For example, if I am only interested in the NET_EVENT_WIFI_CONNECT_RESULT and NET_EVENT_WIFI_DISCONNECT_RESULT events, I can make sure that the handler only cares about these events by only including doing something when these happen:

    static void wifi_mgmt_event_handler(struct net_mgmt_event_callback *cb,
    				     uint32_t mgmt_event, struct net_if *iface)
    {
    	switch (mgmt_event) {
    	case NET_EVENT_WIFI_CONNECT_RESULT:
    		handle_wifi_connect_result(cb);
    		break;
    	case NET_EVENT_WIFI_DISCONNECT_RESULT:
    		handle_wifi_disconnect_result(cb);
    		break;
    	default:
    		break;
    	}
    }

    But I would still like to know where the L4_CONNECTED event is!

    You should get this when the network interface is up and an IPv4 or IPv6 address has been assigned to the interface. I am not sure why you do not get this without knowing more about your application and how you have implemented things.

    Best regards,
    Marte

  • The handler will listen to all events whose lover bits fit within 7, which means that in both these cases, the handler will listen to all of the following events:

    So, to be clear, the mask does not work as one might expect from the documentation, because as well as the event requested you will get a bunch of other events.... Not a problem, just as long as I had not misunderstood the operation.

    You should get this when the network interface is up and an IPv4 or IPv6 address has been assigned to the interface. I am not sure why you do not get this without knowing more about your application and how you have implemented things.

    My code shows how I request the events, and also that I changed to set a mask of 0xFF which should match all the events defined in the header files for L4:

    (_NET_EVENT_L4_BASE | 0xFF)

    I do receive L4 events - specifically 

    NET_EVENT_DNS_SERVER_ADD
    defined in net_event.h as 
    (_NET_EVENT_L4_BASE | NET_EVENT_L4_CMD_DNS_SERVER_ADD)

    But never 

    NET_EVENT_L4_CONNECTED
    or even
    NET_EVENT_L4_IPV4_CONNECTED
    Can you confirm this is NOT normal? (before I go trying to debug it all only to find that its just the doc that is misleading like for the mask...)
    thanks
  • Hi,

    BrianW said:
    because as well as the event requested you will get a bunch of other events

    Yes, the handler will listen for the other events as well. However, you can write it so that it only does something about the events you are interested in by including only these events in the switch case.

    BrianW said:
    Can you confirm this is NOT normal? (before I go trying to debug it all only to find that its just the doc that is misleading like for the mask...)

    I would expect you to receive NET_EVENT_L4_CONNECTED. Have you tried comparing your code with the SDK samples or any of the exercises in the DevAcademy Wi-Fi Fundamentals course? We use NET_EVENT_L4_CONNECTED for connection in the DevAcademy course, and it is also used in some Wi-Fi and networking samples.

    Best regards,
    Marte

  • Related