From a15e5dda8c004ad1b1234c3833c9295c896c071f Mon Sep 17 00:00:00 2001 From: Vijaya Kumar Abbaraju Date: Mon, 8 Apr 2024 03:20:34 -0700 Subject: [PATCH] HOSTPAD driver changes for PAC --- debian/config/hostapd/linux | 7 + hostapd/Makefile | 8 + hostapd/config_file.c | 118 ++++++++- hostapd/config_file.h | 27 +++ hostapd/main.c | 103 ++++++++ src/drivers/driver_wired_sonic.c | 405 +++++++++++++++++++++++++++++++ 6 files changed, 667 insertions(+), 1 deletion(-) create mode 100644 src/drivers/driver_wired_sonic.c diff --git a/debian/config/hostapd/linux b/debian/config/hostapd/linux index 50612c603..3577b6612 100644 --- a/debian/config/hostapd/linux +++ b/debian/config/hostapd/linux @@ -385,3 +385,10 @@ CONFIG_SAE=y # Override default value for the wpa_disable_eapol_key_retries configuration # parameter. See that parameter in hostapd.conf for more details. #CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1 +# +# SONIC HOSTAPD +CONFIG_SONIC_HOSTAPD=y + +# SONIC RADIUS attribute parser +CONFIG_SONIC_RADIUS=y +# # diff --git a/hostapd/Makefile b/hostapd/Makefile index 2a7283a92..e4510d888 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -182,6 +182,10 @@ CFLAGS += -DHOSTAPD_DUMP_STATE OBJS += ../src/eapol_auth/eapol_auth_dump.o endif +ifdef CONFIG_SONIC_HOSTAPD +CFLAGS += -DCONFIG_SONIC_HOSTAPD +endif + ifdef CONFIG_NO_RADIUS CFLAGS += -DCONFIG_NO_RADIUS CONFIG_NO_ACCOUNTING=y @@ -189,6 +193,10 @@ else OBJS += ../src/radius/radius.o OBJS += ../src/radius/radius_client.o OBJS += ../src/radius/radius_das.o +ifdef CONFIG_SONIC_RADIUS +CFLAGS += -DCONFIG_SONIC_RADIUS +OBJS += ../src/radius/radius_attr_parse.o +endif endif ifdef CONFIG_NO_ACCOUNTING diff --git a/hostapd/config_file.c b/hostapd/config_file.c index ce32f3c04..18858cf38 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -23,7 +23,9 @@ #include "ap/wpa_auth.h" #include "ap/ap_config.h" #include "config_file.h" - +#ifdef CONFIG_SONIC_HOSTAPD +#include "utils/json.h" +#endif #ifndef CONFIG_NO_VLAN static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss, @@ -4694,3 +4696,117 @@ int hostapd_set_iface(struct hostapd_config *conf, return 0; } + +#ifdef CONFIG_SONIC_HOSTAPD +int hostapd_sonic_json_file_read(hostapd_json_data_t *parsed_data) +{ + FILE *f; + long len; + char *content = NULL; + struct json_token *root, *deleted_interfaces, *modified_interfaces, *new_interfaces; + struct json_token *elem, *if_name, *if_path; + int rc = 0; + int i; + +/* open the config file and read the content */ + f=fopen(HOSTAPD_SONIC_JSON_PATH,"rb"); + fseek(f,0,SEEK_END); + len=ftell(f); + fseek(f,0,SEEK_SET); + + content=(char*)malloc(len+1); + if (!content) { + return -1; + } + + fread(content,1,len,f); + fclose(f); + + /* delete the json file */ + + if (remove (HOSTAPD_SONIC_JSON_PATH)) + { + wpa_printf(MSG_ERROR, "json file delete failed"); + } + else + { + wpa_printf(MSG_DEBUG, "json file delete successful"); + } + + root=json_parse(content, len); + if (!root) { + wpa_printf(MSG_ERROR, "Error parsing JSON !!"); + rc = -1; + goto clean_up; + } + + /* Obtain deleted interfaces */ + deleted_interfaces = json_get_member(root, "deleted_interfaces"); + if (NULL != deleted_interfaces) + { + /* Read the deleted interfaces */ + parsed_data->deleted_count = json_get_array_size(deleted_interfaces); + + for (i = 0; i < parsed_data->deleted_count; i++) + { + elem = json_get_array_item(deleted_interfaces, i); + if (elem) + { + if_name = json_get_member(elem, "if_name"); + strncpy (&parsed_data->deleted_intf[i].if_name[0], if_name->string, strlen(if_name->string)); + } + } + } + + /* Obtain modified interfaces */ + modified_interfaces = json_get_member(root, "modified_interfaces"); + if (NULL != modified_interfaces) + { + parsed_data->modified_count = json_get_array_size(modified_interfaces); + + /* Read the modified interfaces */ + for (i = 0; i < parsed_data->modified_count; i++) + { + elem = json_get_array_item(modified_interfaces, i); + if (elem) + { + if_name = json_get_member(elem, "if_name"); + strncpy (&parsed_data->modified_intf[i].if_name[0], if_name->string, strlen(if_name->string)); + if_path = json_get_member(elem, "path"); + strncpy (&parsed_data->modified_intf[i].file_path[0], if_path->string, strlen(if_path->string)); + } + } + } + + /* Obtain new interfaces */ + new_interfaces = json_get_member(root, "new_interfaces"); + if (NULL != new_interfaces) + { + /* Read the new interfaces */ + parsed_data->new_count = json_get_array_size(new_interfaces); + + /* Read the modified interfaces */ + for (i = 0; i < parsed_data->new_count; i++) + { + elem = json_get_array_item(new_interfaces, i); + if (elem) + { + if_name = json_get_member(elem, "if_name"); + strncpy (&parsed_data->new_intf[i].if_name[0], if_name->string, strlen(if_name->string)); + if_path = json_get_member(elem, "path"); + strncpy (&parsed_data->new_intf[i].file_path[0], if_path->string, strlen(if_path->string)); + } + } + } + +clean_up: + + if (root) + json_free(root); + + if (content) + free (content); + + return rc; +} +#endif diff --git a/hostapd/config_file.h b/hostapd/config_file.h index 9830f5a22..f4632e905 100644 --- a/hostapd/config_file.h +++ b/hostapd/config_file.h @@ -9,6 +9,33 @@ #ifndef CONFIG_FILE_H #define CONFIG_FILE_H +#ifdef CONFIG_SONIC_HOSTAPD + +#define HOSTAPD_JSON_MAX_INTF 512 +#define HOSTAPD_SONIC_JSON_PATH "/etc/hostapd/hostapd_config.json" + +typedef struct hostapd_intf_json_s +{ + char if_name[64]; + char file_path[64]; +}hostapd_intf_json_t; + +typedef struct hostapd_json_data_s +{ + hostapd_intf_json_t deleted_intf[HOSTAPD_JSON_MAX_INTF]; + unsigned int deleted_count; + + hostapd_intf_json_t modified_intf[HOSTAPD_JSON_MAX_INTF]; + unsigned int modified_count; + + hostapd_intf_json_t new_intf[HOSTAPD_JSON_MAX_INTF]; + unsigned int new_count; +}hostapd_json_data_t; + +int hostapd_sonic_json_file_read(hostapd_json_data_t *parsed_data); + +#endif + struct hostapd_config * hostapd_config_read(const char *fname); int hostapd_set_iface(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *field, diff --git a/hostapd/main.c b/hostapd/main.c index 4f2d1f216..6b94a5742 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -315,6 +315,8 @@ static int handle_reload_iface(struct hostapd_iface *iface, void *ctx) /** * handle_reload - SIGHUP handler to reload configuration */ +#ifndef CONFIG_SONIC_HOSTAPD + static void handle_reload(int sig, void *signal_ctx) { struct hapd_interfaces *interfaces = signal_ctx; @@ -323,6 +325,97 @@ static void handle_reload(int sig, void *signal_ctx) hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); } +#else + +static void handle_reload(int sig, void *signal_ctx) +{ + int i; + struct hostapd_data *hapd; + struct hostapd_iface *hapd_iface = NULL; + struct hostapd_iface **tmp; + struct hapd_interfaces *interfaces = signal_ctx; + hostapd_json_data_t *intf_changed = (hostapd_json_data_t *)malloc(sizeof(hostapd_json_data_t)); + + wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration", sig); + + if (!intf_changed) + { + wpa_printf(MSG_DEBUG, "couldn't allocate memory while reloading configuration"); + return; + } + memset(intf_changed, 0, sizeof(*intf_changed)); + + /* read the sonic json file */ + + if (!hostapd_sonic_json_file_read(intf_changed)) + { + /* purge the deleted interfaces */ + for (i = 0; i < intf_changed->deleted_count; i++) { + hapd = hostapd_get_iface(interfaces, intf_changed->deleted_intf[i].if_name); + + /* skip already deleted interface*/ + if (!hapd) + continue; + + if (hostapd_disable_iface(hapd->iface)) + wpa_printf(MSG_DEBUG, "Could not disable iface"); + + if (hostapd_remove_iface(interfaces, hapd->conf->iface)) + wpa_printf(MSG_DEBUG, "Could not remove iface"); + } + + unsigned int j = 0; + /* now reload the interfaces that are modified */ + /*hostapd_for_each_interface(interfaces, handle_reload_iface, NULL); */ + for (i = 0; i < intf_changed->modified_count; i++) { + for (j = 0; j < interfaces->count; j++) + { + hapd_iface = interfaces->iface[j]; + if (0 == strcmp(hapd_iface->conf->bss[0]->iface, intf_changed->modified_intf[i].if_name)) + { + wpa_printf(MSG_DEBUG, "Reloading iface %s", intf_changed->modified_intf[i].if_name); + handle_reload_iface(interfaces->iface[j], NULL); + } + } + } + + + for (i = 0; i < intf_changed->new_count; i++) + { + /* append the new interfaces and start them*/ + hapd_iface = hostapd_interface_init(interfaces, + intf_changed->new_intf[i].if_name, intf_changed->new_intf[i].file_path, 0); + if (!hapd_iface) + goto clean_up; + + tmp = os_realloc_array(interfaces->iface, + interfaces->count + 1, + sizeof(struct hostapd_iface *)); + if (!tmp) { + hostapd_interface_deinit_free(hapd_iface); + goto clean_up; + } + interfaces->iface = tmp; + interfaces->iface[interfaces->count++] = hapd_iface; + if (interfaces->driver_init(hapd_iface)) + goto clean_up; + + if (hostapd_setup_interface(hapd_iface)) { + hostapd_deinit_driver( + hapd_iface->bss[0]->driver, + hapd_iface->bss[0]->drv_priv, + hapd_iface); + goto clean_up; + } + } + } + +clean_up: + free(intf_changed); + + return; +} +#endif static void handle_dump_state(int sig, void *signal_ctx) { @@ -442,6 +535,16 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, } } +#ifdef CONFIG_SONIC_HOSTAPD + if (pid_file) { + FILE *f = fopen(pid_file, "w"); + if (f) { + fprintf(f, "%u\n", getpid()); + fclose(f); + } + } +#endif + eloop_run(); return 0; diff --git a/src/drivers/driver_wired_sonic.c b/src/drivers/driver_wired_sonic.c new file mode 100644 index 000000000..49b6e5ebf --- /dev/null +++ b/src/drivers/driver_wired_sonic.c @@ -0,0 +1,405 @@ +/* + * Wired Ethernet driver interface for Sonic + * Copyright (c) 2005-2009, + * Copyright (c) 2004 + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include +#include +#include +#include "includes.h" +#include "common.h" +#include "driver.h" +#include "driver_wired_common.h" +#include "ap/sta_info.h" +#include "radius/radius_attr_parse.h" +#include "common/eapol_common.h" + +#define STATUS_COPY(_status) static void _status##_##copy(char *intf, clientStatusReply_t *reply, u8 *addr, void *param) +#define STATUS_ENTER(_status, _intf, _reply, _addr, _param) _status##_##copy(_intf, _reply, _addr, _param) + + +#define STATUS_MALLOC(__status, _param, _reply) \ + do { \ + unsigned int _len = 0; \ + if (AUTH_SUCCESS == __status) \ + { \ + struct sta_info * _sta = NULL; \ + _sta = (struct sta_info *)_param;\ + \ + }\ + _reply = (clientStatusReply_t *)malloc(sizeof(*_reply) + _len); \ + memset(_reply, 0, sizeof(*_reply)+ _len); \ + } while(0); + + +typedef struct status_map_s +{ + char *status; + unsigned int val; +}status_map_t; + +static int wpa_pac_send_data (char *buf, int bufLen) +{ + struct sockaddr_in saddr; + int fd, ret_val; + struct hostent *local_host; /* need netdb.h for this */ + int i; + char *ptr = buf; + struct linger sl; + struct sockaddr_in client; + socklen_t clientlen = sizeof(client); + + printf("buffer: "); + for (i =0; i<10; i++) + { + printf("0x%x ", ptr[i]); + } + printf("\n"); + + /* Step1: create a TCP socket */ + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + fprintf(stderr, "socket failed [%s]\n", strerror(errno)); + return -1; + } + printf("Created a socket with fd: %d\n", fd); + + /* Let us initialize the server address structure */ + saddr.sin_family = AF_INET; + saddr.sin_port = htons(3434); + local_host = gethostbyname("127.0.0.1"); + saddr.sin_addr = *((struct in_addr *)local_host->h_addr); + + + /* Step2: connect to the server socket */ + ret_val = connect(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)); + if (ret_val == -1) + { + fprintf(stderr, "connect failed [%s]\n", strerror(errno)); + close(fd); + return -1; + } + + sl.l_onoff = 1; /* enable linger option */ + sl.l_linger = 30; /* timeout interval in seconds */ + if (-1 == setsockopt(fd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl))) + { + printf("unable to set SO_LINGER option socket with fd: %d\n", fd); + } + + getsockname(fd, (struct sockaddr *) &client, &clientlen); + + printf ("The Socket is now connected fd %d [%s:%u] \n", fd, inet_ntoa(client.sin_addr), ntohs(client.sin_port)); + + /* Next step: send some data */ + ret_val = send(fd, buf, bufLen, 0); + printf("fd :%d Successfully sent data (len %d bytes): %s\n", + fd, bufLen, buf); + + /* Last step: close the socket */ + close(fd); + return 0; +} + +STATUS_COPY(AUTH_SUCCESS) +{ + struct sta_info * sta = NULL; + sta = (struct sta_info *)param; + + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = AUTH_SUCCESS; + strncpy (reply->intf, intf, strlen(intf)); + + /* copy user details */ + strncpy((char *)reply->info.authInfo.userName, (const char *)sta->attr_info.userName, strlen((char *)sta->attr_info.userName)); + reply->info.authInfo.userNameLength = strlen((const char *)sta->attr_info.userName); + + /* since this host-apd code is 2004 version, version is 2 */ + reply->info.authInfo.eapolVersion = 2; + + /* copy bam used for authentication */ + strncpy(reply->info.authInfo.bam_used, "radius", strlen("radius")+1); + + /* copy all the attributes received from radius/ or backend method */ + reply->info.authInfo.attrInfo = sta->attr_info; + +} + + +STATUS_COPY(NEW_CLIENT) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = NEW_CLIENT; + //strncpy (reply->status, "new_client", strlen("new_client")); + strncpy (reply->intf, intf, strlen(intf)); + +} + + +STATUS_COPY(AUTH_FAIL) +{ + struct sta_info * sta = NULL; + sta = (struct sta_info *)param; + + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = AUTH_FAIL; + + /* copy user details */ + strncpy(reply->info.authInfo.userName, sta->attr_info.userName, strlen(sta->attr_info.userName)); + reply->info.authInfo.userNameLength = strlen(sta->attr_info.userName); + + //strncpy (reply->status, "auth_fail", strlen("auth_fail")); + strncpy (reply->intf, intf, strlen(intf)); + +} + + +STATUS_COPY(AUTH_TIMEOUT) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = AUTH_TIMEOUT; + + //strncpy (reply->status, "auth_timeout", strlen("auth_timeout")); + strncpy (reply->intf, intf, strlen(intf)); + +} + + +STATUS_COPY(AUTH_SERVER_COMM_FAILURE) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = AUTH_SERVER_COMM_FAILURE; + + //strncpy (reply->status, "auth_server_comm_failure", strlen("auth_server_comm_failure")); + strncpy (reply->intf, intf, strlen(intf)); + +} + + +STATUS_COPY(CLIENT_DISCONNECTED) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = CLIENT_DISCONNECTED; + + //strncpy (reply->status, "client_disconnected", strlen("client_disconnected")); + strncpy (reply->intf, intf, strlen(intf)); + +} + +STATUS_COPY(METHOD_CHANGE) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = METHOD_CHANGE; + //strncpy (reply->status, "method_change", strlen("method_change")); + strncpy (reply->intf, intf, strlen(intf)); + strncpy (reply->info.enableStatus, (char *)param, strlen((char *)param)); + +} + +STATUS_COPY(RADIUS_SERVERS_DEAD) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = RADIUS_SERVERS_DEAD; + + //strncpy (reply->status, "radius_servers_dead", strlen("radius_servers_dead")); + strncpy (reply->intf, intf, strlen(intf)); + +} + +#if 0 +STATUS_COPY(RADIUS_FIRST_PASS_DACL_DATA) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")); + strncpy (reply->status, "radius_first_pass_dacl_data", strlen("radius_first_pass_dacl_data")); + strncpy (reply->intf, intf, strlen(intf)); + +} +#endif + +STATUS_COPY(RADIUS_DACL_INFO) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = RADIUS_DACL_INFO; + //strncpy (reply->status, "radius_dacl_info", strlen("radius_dacl_info")); + strncpy (reply->intf, intf, strlen(intf)); +} + + + +STATUS_COPY(MKA_PEER_TIMEOUT) +{ + memset(reply, 0, sizeof(*reply)); + if (addr) + { + memcpy(reply->info.authInfo.addr, addr, 6); + } + strncpy (reply->method, "802.1X", strlen("802.1X")+1); + reply->status = MKA_PEER_TIMEOUT; + //strncpy (reply->status, "mka_peer_timeout", strlen("mka_peer_timeout")); + strncpy (reply->intf, intf, strlen(intf)); + +} + +static int client_resp_val_get(char *in) +{ + unsigned int i = 0; + + static status_map_t status_map[] = { + {"new_client", NEW_CLIENT}, + {"auth_fail", AUTH_FAIL}, + {"auth_success", AUTH_SUCCESS}, + {"auth_timeout", AUTH_TIMEOUT}, + {"auth_server_comm_failure", AUTH_SERVER_COMM_FAILURE}, + {"client_disconnected", CLIENT_DISCONNECTED}, + {"method_change", METHOD_CHANGE}, + {"radius_server_dead", RADIUS_SERVERS_DEAD}, + {"radius_first_pass_dacl_data", RADIUS_FIRST_PASS_DACL_DATA}, + {"radius_dacl_info", RADIUS_DACL_INFO}, + {"mka_peer_timeout", MKA_PEER_TIMEOUT}, + }; + + for (i = 0; i < sizeof(status_map)/sizeof(status_map_t); i++) + { + if (0 == strcmp(in, status_map[i].status)) + { + return status_map[i].val; + } + } + return -1; +} + +int wired_driver_auth_resp_send(char *intf, u8 *addr, char *status, void *param) +{ + clientStatusReply_t *reply; + + unsigned int val = 0; + int rv = 0; + + val = client_resp_val_get(status); + + STATUS_MALLOC(val, param, reply); + // reply = (clientStatusReply_t *)malloc(sizeof(*reply)); +// memset(reply, 0, sizeof(*reply)); + + switch (val) + { + case NEW_CLIENT: + STATUS_ENTER(NEW_CLIENT, intf, reply, addr, param); + break; + + case AUTH_FAIL: + STATUS_ENTER(AUTH_FAIL, intf, reply, addr, param); + break; + + case AUTH_SUCCESS: + STATUS_ENTER(AUTH_SUCCESS, intf, reply, addr, param); + break; + + case AUTH_TIMEOUT: + STATUS_ENTER(AUTH_TIMEOUT, intf, reply, addr, param); + break; + + case AUTH_SERVER_COMM_FAILURE: + STATUS_ENTER(AUTH_SERVER_COMM_FAILURE, intf, reply, addr, param); + break; + + case CLIENT_DISCONNECTED: + STATUS_ENTER(CLIENT_DISCONNECTED, intf, reply, addr, param); + break; + + case METHOD_CHANGE: + STATUS_ENTER(METHOD_CHANGE, intf, reply, addr, param); + break; + + case RADIUS_SERVERS_DEAD: + STATUS_ENTER(RADIUS_SERVERS_DEAD, intf, reply, addr, param); + break; + + case RADIUS_DACL_INFO: + STATUS_ENTER(RADIUS_DACL_INFO, intf, reply, addr, param); + break; + + case MKA_PEER_TIMEOUT: + STATUS_ENTER(MKA_PEER_TIMEOUT, intf, reply, addr, param); + break; + + default: + /* unknown response is received */ + return -1; + + } + + /* send msg */ + + rv = wpa_pac_send_data((char *)reply, sizeof(*reply)); + + if (addr) + { + printf("rv = %d " MACSTR " status %s\n", rv, MAC2STR(addr), status); + } + else + { + printf("rv = %d status %s\n", rv, status); + } + + if (reply) + free (reply); + + return rv; +} + +