|
@@ -1092,6 +1092,191 @@ void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
|
|
|
}
|
|
|
|
|
|
|
|
|
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
|
|
|
+ void *sock_ctx)
|
|
|
+{
|
|
|
+ char buf[256];
|
|
|
+ int res;
|
|
|
+ struct sockaddr_un from;
|
|
|
+ socklen_t fromlen = sizeof(from);
|
|
|
+ char reply[24];
|
|
|
+ int reply_len;
|
|
|
+
|
|
|
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
|
|
|
+ (struct sockaddr *) &from, &fromlen);
|
|
|
+ if (res < 0) {
|
|
|
+ perror("recvfrom(ctrl_iface)");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ buf[res] = '\0';
|
|
|
+
|
|
|
+ os_memcpy(reply, "OK\n", 3);
|
|
|
+ reply_len = 3;
|
|
|
+
|
|
|
+ if (os_strcmp(buf, "PING") == 0) {
|
|
|
+ os_memcpy(reply, "PONG\n", 5);
|
|
|
+ reply_len = 5;
|
|
|
+ } else {
|
|
|
+ wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
|
|
|
+ "ignored");
|
|
|
+ reply_len = -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (reply_len < 0) {
|
|
|
+ os_memcpy(reply, "FAIL\n", 5);
|
|
|
+ reply_len = 5;
|
|
|
+ }
|
|
|
+
|
|
|
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
|
|
|
+{
|
|
|
+ char *buf;
|
|
|
+ size_t len;
|
|
|
+
|
|
|
+ if (interface->global_iface_path == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ len = os_strlen(interface->global_iface_path) +
|
|
|
+ os_strlen(interface->global_iface_name) + 2;
|
|
|
+ buf = os_malloc(len);
|
|
|
+ if (buf == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
|
|
|
+ interface->global_iface_name);
|
|
|
+ buf[len - 1] = '\0';
|
|
|
+ return buf;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
|
|
|
+{
|
|
|
+ struct sockaddr_un addr;
|
|
|
+ int s = -1;
|
|
|
+ char *fname = NULL;
|
|
|
+
|
|
|
+ if (interface->global_iface_path == NULL) {
|
|
|
+ wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
|
|
|
+ if (errno == EEXIST) {
|
|
|
+ wpa_printf(MSG_DEBUG, "Using existing control "
|
|
|
+ "interface directory.");
|
|
|
+ } else {
|
|
|
+ perror("mkdir[ctrl_interface]");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (os_strlen(interface->global_iface_path) + 1 +
|
|
|
+ os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
+ if (s < 0) {
|
|
|
+ perror("socket(PF_UNIX)");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ os_memset(&addr, 0, sizeof(addr));
|
|
|
+#ifdef __FreeBSD__
|
|
|
+ addr.sun_len = sizeof(addr);
|
|
|
+#endif /* __FreeBSD__ */
|
|
|
+ addr.sun_family = AF_UNIX;
|
|
|
+ fname = hostapd_global_ctrl_iface_path(interface);
|
|
|
+ if (fname == NULL)
|
|
|
+ goto fail;
|
|
|
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
|
|
|
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
|
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
|
|
|
+ strerror(errno));
|
|
|
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
|
|
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
|
|
|
+ " allow connections - assuming it was left"
|
|
|
+ "over from forced program termination");
|
|
|
+ if (unlink(fname) < 0) {
|
|
|
+ perror("unlink[ctrl_iface]");
|
|
|
+ wpa_printf(MSG_ERROR, "Could not unlink "
|
|
|
+ "existing ctrl_iface socket '%s'",
|
|
|
+ fname);
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
|
|
|
+ 0) {
|
|
|
+ perror("bind(PF_UNIX)");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
|
|
|
+ "ctrl_iface socket '%s'", fname);
|
|
|
+ } else {
|
|
|
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
|
|
|
+ "be in use - cannot override it");
|
|
|
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
|
|
|
+ "not used anymore", fname);
|
|
|
+ os_free(fname);
|
|
|
+ fname = NULL;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
|
|
|
+ perror("chmod[ctrl_interface/ifname]");
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ os_free(fname);
|
|
|
+
|
|
|
+ interface->global_ctrl_sock = s;
|
|
|
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
|
|
|
+ interface, NULL);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+fail:
|
|
|
+ if (s >= 0)
|
|
|
+ close(s);
|
|
|
+ if (fname) {
|
|
|
+ unlink(fname);
|
|
|
+ os_free(fname);
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
|
|
|
+{
|
|
|
+ char *fname = NULL;
|
|
|
+
|
|
|
+ if (interfaces->global_ctrl_sock > -1) {
|
|
|
+ eloop_unregister_read_sock(interfaces->global_ctrl_sock);
|
|
|
+ close(interfaces->global_ctrl_sock);
|
|
|
+ interfaces->global_ctrl_sock = -1;
|
|
|
+ fname = hostapd_global_ctrl_iface_path(interfaces);
|
|
|
+ if (fname) {
|
|
|
+ unlink(fname);
|
|
|
+ os_free(fname);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (interfaces->global_iface_path &&
|
|
|
+ rmdir(interfaces->global_iface_path) < 0) {
|
|
|
+ if (errno == ENOTEMPTY) {
|
|
|
+ wpa_printf(MSG_DEBUG, "Control interface "
|
|
|
+ "directory not empty - leaving it "
|
|
|
+ "behind");
|
|
|
+ } else {
|
|
|
+ perror("rmdir[ctrl_interface]");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ os_free(interfaces->global_iface_path);
|
|
|
+ interfaces->global_iface_path = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
|
|
|
const char *buf, size_t len)
|
|
|
{
|