mirror of
https://github.com/OpenSolo/OpenSolo.git
synced 2025-04-30 06:34:38 +02:00
193 lines
5.3 KiB
C
193 lines
5.3 KiB
C
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/un.h>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include "util.h"
|
|
#include "hostapd_ctrl.h"
|
|
|
|
#define IF_NAME_MAX 32
|
|
|
|
#define HOSTAPD_REPLY_TIMEOUT_US 1000000
|
|
|
|
typedef struct {
|
|
char if_name[IF_NAME_MAX];
|
|
struct sockaddr_un sa_loc;
|
|
struct sockaddr_un sa_dst;
|
|
int fd;
|
|
} hostapd_ctrl_info_t;
|
|
|
|
/*
|
|
* hostapd_ctrl_new - create a hostapd control connection
|
|
*
|
|
* Returns non-NULL handle on success, or NULL on error.
|
|
*/
|
|
void *hostapd_ctrl_new(const char *if_name)
|
|
{
|
|
hostapd_ctrl_info_t *ctrl;
|
|
struct timeval timeout;
|
|
|
|
ctrl = (hostapd_ctrl_info_t *)malloc(sizeof(hostapd_ctrl_info_t));
|
|
if (ctrl == NULL)
|
|
goto hostapd_ctrl_new_error_1;
|
|
|
|
memset(ctrl, 0, sizeof(*ctrl));
|
|
|
|
strncpy(ctrl->if_name, if_name, IF_NAME_MAX - 1);
|
|
|
|
ctrl->fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
if (ctrl->fd == -1)
|
|
goto hostapd_ctrl_new_error_2;
|
|
|
|
ctrl->sa_loc.sun_family = AF_UNIX;
|
|
sprintf(ctrl->sa_loc.sun_path, "/tmp/hostapd_ctrl.%ld", syscall(SYS_gettid));
|
|
if (bind(ctrl->fd, (struct sockaddr *)&(ctrl->sa_loc), sizeof(ctrl->sa_loc)) != 0)
|
|
goto hostapd_ctrl_new_error_3;
|
|
|
|
timeout.tv_sec = HOSTAPD_REPLY_TIMEOUT_US / 1000000;
|
|
timeout.tv_usec = HOSTAPD_REPLY_TIMEOUT_US % 1000000;
|
|
if (setsockopt(ctrl->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) != 0)
|
|
goto hostapd_ctrl_new_error_3;
|
|
|
|
ctrl->sa_dst.sun_family = AF_UNIX;
|
|
if (snprintf(ctrl->sa_dst.sun_path, sizeof(ctrl->sa_dst.sun_path), "/var/run/hostapd/%s",
|
|
if_name) >= sizeof(ctrl->sa_dst.sun_path))
|
|
goto hostapd_ctrl_new_error_3;
|
|
|
|
return (void *)ctrl;
|
|
|
|
hostapd_ctrl_new_error_3:
|
|
close(ctrl->fd);
|
|
hostapd_ctrl_new_error_2:
|
|
memset(ctrl, 0, sizeof(*ctrl));
|
|
free(ctrl);
|
|
hostapd_ctrl_new_error_1:
|
|
return NULL;
|
|
|
|
} /* hostapd_ctrl_new */
|
|
|
|
/*
|
|
* hostapd_ctrl_delete - delete a hostapd control connection
|
|
*/
|
|
int hostapd_ctrl_delete(void *handle)
|
|
{
|
|
hostapd_ctrl_info_t *ctrl = (hostapd_ctrl_info_t *)handle;
|
|
|
|
close(ctrl->fd);
|
|
unlink(ctrl->sa_loc.sun_path);
|
|
memset(ctrl, 0, sizeof(*ctrl));
|
|
free(ctrl);
|
|
|
|
return 0;
|
|
|
|
} /* hostapd_ctrl_delete */
|
|
|
|
/*
|
|
* hostapd_ctrl_get_stations - query hostapd for all attached stations
|
|
*
|
|
* On entry, station_info points to a caller-supplied table of *station_entries
|
|
* hostapd_station_info_t structures. This function fills in the table, up to
|
|
* *station_entries entries. On return, *station_entries is the number of
|
|
* stations associated. If there are more stations than will fit in the table,
|
|
* the table is filled up, then *station_entries is set to the actual number of
|
|
* stations.
|
|
*
|
|
* Returns 0 on success, or nonzero on error. If an error is returned, neither
|
|
* the contents of station_info nor *station_entries is valid.
|
|
*/
|
|
int hostapd_ctrl_get_stations(const void *handle, hostapd_station_info_t *station_info,
|
|
int *station_entries)
|
|
{
|
|
const hostapd_ctrl_info_t *ctrl = (const hostapd_ctrl_info_t *)handle;
|
|
char request[64];
|
|
int request_len;
|
|
ssize_t status;
|
|
char reply[1024];
|
|
char *saveptr;
|
|
char *mac;
|
|
int mac_len;
|
|
int entries = 0;
|
|
|
|
strcpy(request, "STA-FIRST");
|
|
request_len = strlen(request);
|
|
status = sendto(ctrl->fd, request, request_len, 0, (struct sockaddr *)&(ctrl->sa_dst),
|
|
sizeof(ctrl->sa_dst));
|
|
if (status != request_len) {
|
|
perror("sendto");
|
|
return -1;
|
|
}
|
|
|
|
do {
|
|
|
|
memset(reply, 0, sizeof(reply));
|
|
status = recv(ctrl->fd, reply, sizeof(reply), 0);
|
|
if (status < 0) {
|
|
perror("recv");
|
|
return -1;
|
|
} else if (status == 0) {
|
|
/* normal return; get this after the last station */
|
|
break;
|
|
}
|
|
|
|
/*printf("%d bytes: \"%s\"\n", status, reply);*/
|
|
|
|
/* get first token (mac) */
|
|
mac = strtok_r(reply, "\n", &saveptr);
|
|
if (mac == NULL) {
|
|
printf("ERROR: getting mac from reply\n");
|
|
return -1;
|
|
}
|
|
mac_len = strlen(mac);
|
|
if (mac_len != 17) {
|
|
printf("ERROR: mac is strange length\n");
|
|
return -1;
|
|
}
|
|
|
|
/* only save info if there is room; otherwise, we are just counting
|
|
stations so we can set station_entries */
|
|
if (entries < *station_entries) {
|
|
|
|
if (mac_aton(mac, station_info[entries].mac) == NULL) {
|
|
printf("ERROR: parsing mac\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
entries++;
|
|
|
|
sprintf(request, "STA-NEXT %s", mac);
|
|
request_len = strlen(request);
|
|
status = sendto(ctrl->fd, request, request_len, 0, (struct sockaddr *)&(ctrl->sa_dst),
|
|
sizeof(ctrl->sa_dst));
|
|
if (status != request_len) {
|
|
perror("sendto");
|
|
return -1;
|
|
}
|
|
|
|
} while (1);
|
|
|
|
*station_entries = entries;
|
|
|
|
return 0;
|
|
|
|
} /* hostapd_ctrl_get_stations */
|
|
|
|
int hostapd_ctrl_find_by_mac(const hostapd_station_info_t *station_info, int station_entries,
|
|
const uint8_t *mac)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < station_entries; i++)
|
|
if (memcmp(mac, station_info[i].mac, MAC_LEN) == 0)
|
|
return i;
|
|
|
|
/* not found */
|
|
return -1;
|
|
|
|
} /* hostapd_ctrl_find_by_mac */
|