1 /*
2  * Copyright (c) 2024 Muhammad Haziq
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/net/wifi_mgmt.h>
10 #include <zephyr/net/dhcpv4_server.h>
11 
12 LOG_MODULE_REGISTER(MAIN);
13 
14 #define MACSTR "%02X:%02X:%02X:%02X:%02X:%02X"
15 
16 #define NET_EVENT_WIFI_MASK                                                                        \
17 	(NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT |                        \
18 	 NET_EVENT_WIFI_AP_ENABLE_RESULT | NET_EVENT_WIFI_AP_DISABLE_RESULT |                      \
19 	 NET_EVENT_WIFI_AP_STA_CONNECTED | NET_EVENT_WIFI_AP_STA_DISCONNECTED)
20 
21 /* AP Mode Configuration */
22 #define WIFI_AP_SSID       "ESP32-AP"
23 #define WIFI_AP_PSK        ""
24 #define WIFI_AP_IP_ADDRESS "192.168.4.1"
25 #define WIFI_AP_NETMASK    "255.255.255.0"
26 
27 /* STA Mode Configuration */
28 #define WIFI_SSID "SSID"     /* Replace `SSID` with WiFi ssid. */
29 #define WIFI_PSK  "PASSWORD" /* Replace `PASSWORD` with Router password. */
30 
31 static struct net_if *ap_iface;
32 static struct net_if *sta_iface;
33 
34 static struct wifi_connect_req_params ap_config;
35 static struct wifi_connect_req_params sta_config;
36 
37 static struct net_mgmt_event_callback cb;
38 
wifi_event_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)39 static void wifi_event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
40 			       struct net_if *iface)
41 {
42 	switch (mgmt_event) {
43 	case NET_EVENT_WIFI_CONNECT_RESULT: {
44 		LOG_INF("Connected to %s", WIFI_SSID);
45 		break;
46 	}
47 	case NET_EVENT_WIFI_DISCONNECT_RESULT: {
48 		LOG_INF("Disconnected from %s", WIFI_SSID);
49 		break;
50 	}
51 	case NET_EVENT_WIFI_AP_ENABLE_RESULT: {
52 		LOG_INF("AP Mode is enabled. Waiting for station to connect");
53 		break;
54 	}
55 	case NET_EVENT_WIFI_AP_DISABLE_RESULT: {
56 		LOG_INF("AP Mode is disabled.");
57 		break;
58 	}
59 	case NET_EVENT_WIFI_AP_STA_CONNECTED: {
60 		struct wifi_ap_sta_info *sta_info = (struct wifi_ap_sta_info *)cb->info;
61 
62 		LOG_INF("station: " MACSTR " joined ", sta_info->mac[0], sta_info->mac[1],
63 			sta_info->mac[2], sta_info->mac[3], sta_info->mac[4], sta_info->mac[5]);
64 		break;
65 	}
66 	case NET_EVENT_WIFI_AP_STA_DISCONNECTED: {
67 		struct wifi_ap_sta_info *sta_info = (struct wifi_ap_sta_info *)cb->info;
68 
69 		LOG_INF("station: " MACSTR " leave ", sta_info->mac[0], sta_info->mac[1],
70 			sta_info->mac[2], sta_info->mac[3], sta_info->mac[4], sta_info->mac[5]);
71 		break;
72 	}
73 	default:
74 		break;
75 	}
76 }
77 
enable_dhcpv4_server(void)78 static void enable_dhcpv4_server(void)
79 {
80 	static struct in_addr addr;
81 	static struct in_addr netmaskAddr;
82 
83 	if (net_addr_pton(AF_INET, WIFI_AP_IP_ADDRESS, &addr)) {
84 		LOG_ERR("Invalid address: %s", WIFI_AP_IP_ADDRESS);
85 		return;
86 	}
87 
88 	if (net_addr_pton(AF_INET, WIFI_AP_NETMASK, &netmaskAddr)) {
89 		LOG_ERR("Invalid netmask: %s", WIFI_AP_NETMASK);
90 		return;
91 	}
92 
93 	net_if_ipv4_set_gw(ap_iface, &addr);
94 
95 	if (net_if_ipv4_addr_add(ap_iface, &addr, NET_ADDR_MANUAL, 0) == NULL) {
96 		LOG_ERR("unable to set IP address for AP interface");
97 	}
98 
99 	if (!net_if_ipv4_set_netmask_by_addr(ap_iface, &addr, &netmaskAddr)) {
100 		LOG_ERR("Unable to set netmask for AP interface: %s", WIFI_AP_NETMASK);
101 	}
102 
103 	addr.s4_addr[3] += 10; /* Starting IPv4 address for DHCPv4 address pool. */
104 
105 	if (net_dhcpv4_server_start(ap_iface, &addr) != 0) {
106 		LOG_ERR("DHCP server is not started for desired IP");
107 		return;
108 	}
109 
110 	LOG_INF("DHCPv4 server started...\n");
111 }
112 
enable_ap_mode(void)113 static int enable_ap_mode(void)
114 {
115 	if (!ap_iface) {
116 		LOG_INF("AP: is not initialized");
117 		return -EIO;
118 	}
119 
120 	LOG_INF("Turning on AP Mode");
121 	ap_config.ssid = (const uint8_t *)WIFI_AP_SSID;
122 	ap_config.ssid_length = strlen(WIFI_AP_SSID);
123 	ap_config.psk = (const uint8_t *)WIFI_AP_PSK;
124 	ap_config.psk_length = strlen(WIFI_AP_PSK);
125 	ap_config.channel = WIFI_CHANNEL_ANY;
126 	ap_config.band = WIFI_FREQ_BAND_2_4_GHZ;
127 
128 	if (strlen(WIFI_AP_PSK) == 0) {
129 		ap_config.security = WIFI_SECURITY_TYPE_NONE;
130 	} else {
131 
132 		ap_config.security = WIFI_SECURITY_TYPE_PSK;
133 	}
134 
135 	enable_dhcpv4_server();
136 
137 	int ret = net_mgmt(NET_REQUEST_WIFI_AP_ENABLE, ap_iface, &ap_config,
138 			   sizeof(struct wifi_connect_req_params));
139 	if (ret) {
140 		LOG_ERR("NET_REQUEST_WIFI_AP_ENABLE failed, err: %d", ret);
141 	}
142 
143 	return ret;
144 }
145 
connect_to_wifi(void)146 static int connect_to_wifi(void)
147 {
148 	if (!sta_iface) {
149 		LOG_INF("STA: interface no initialized");
150 		return -EIO;
151 	}
152 
153 	sta_config.ssid = (const uint8_t *)WIFI_SSID;
154 	sta_config.ssid_length = strlen(WIFI_SSID);
155 	sta_config.psk = (const uint8_t *)WIFI_PSK;
156 	sta_config.psk_length = strlen(WIFI_PSK);
157 	sta_config.security = WIFI_SECURITY_TYPE_PSK;
158 	sta_config.channel = WIFI_CHANNEL_ANY;
159 	sta_config.band = WIFI_FREQ_BAND_2_4_GHZ;
160 
161 	LOG_INF("Connecting to SSID: %s\n", sta_config.ssid);
162 
163 	int ret = net_mgmt(NET_REQUEST_WIFI_CONNECT, sta_iface, &sta_config,
164 			   sizeof(struct wifi_connect_req_params));
165 	if (ret) {
166 		LOG_ERR("Unable to Connect to (%s)", WIFI_SSID);
167 	}
168 
169 	return ret;
170 }
171 
main(void)172 int main(void)
173 {
174 	k_sleep(K_SECONDS(5));
175 
176 	net_mgmt_init_event_callback(&cb, wifi_event_handler, NET_EVENT_WIFI_MASK);
177 	net_mgmt_add_event_callback(&cb);
178 
179 	/* Get AP interface in AP-STA mode. */
180 	ap_iface = net_if_get_wifi_sap();
181 
182 	/* Get STA interface in AP-STA mode. */
183 	sta_iface = net_if_get_wifi_sta();
184 
185 	enable_ap_mode();
186 	connect_to_wifi();
187 
188 	return 0;
189 }
190