DA: Skip initializing failed_bssids list when eapol failure case
[platform/upstream/connman.git] / vpn / plugins / vici-client.c
index c1361e4..67e365a 100644 (file)
@@ -68,6 +68,8 @@ static const char *vici_cmd_str[] = {
        "unload-authority",
        "load-key",
        "initiate",
+       "terminate",
+       "child-updown",
        NULL,
 };
 
@@ -89,9 +91,13 @@ struct _VICIClient {
        /* io data */
        int client_sock_fd;
        int client_watch;
+       unsigned int rcv_pkt_size;
+       char *rcvbuf;
        GSList *request_list;
-       vici_connect_reply_cb reply;
-       void *ipsec_user_data;
+       vici_request_reply_cb reply_cb;
+       vici_event_cb event_cb;
+       void *reply_user_data;
+       void *event_user_data;
 };
 
 struct _VICISection {
@@ -274,7 +280,18 @@ static char *load_cert_from_path(const char *path)
        }
 
        fd = fileno(fp);
-       fstat(fd, &st);
+       if (fd == -1) {
+               connman_error("fp is not a valid stream");
+               fclose(fp);
+               return NULL;
+       }
+
+       if (fstat(fd, &st) != 0) {
+               connman_error("fstat failed");
+               fclose(fp);
+               return NULL;
+       }
+
        file_size = st.st_size;
        file_buff = g_try_malloc0(sizeof(char)*st.st_size);
        if (file_buff == NULL) {
@@ -429,7 +446,6 @@ static void destroy_vici_request(gpointer data)
                return;
 
        g_free(req->sndbuf);
-       g_free(req->rcvbuf);
        g_free(req);
 }
 
@@ -627,27 +643,31 @@ static int write_socket(int sock, char *data, int data_len)
 int send_vici_command(struct request *req, VICIClient *vici_client)
 {
        unsigned int size = 0;
+       int sock_fd = 0;
        int res = 0;
 
-       if (req == NULL) {
+       if (req == NULL ||  vici_client == NULL) {
                connman_error("request is NULL\n");
                return -EINVAL;
        }
+       sock_fd = vici_client->client_sock_fd;
 
        size = htonl(req->used);
-       res = write_socket(vici_client->client_sock_fd, (char *)&size, sizeof(size));
+       res = write_socket(sock_fd, (char *)&size, sizeof(size));
        if (res != 0) {
                connman_error("failed to send size with network byte order\n");
                return -EIO;
        }
 
-       res = write_socket(vici_client->client_sock_fd, req->sndbuf, req->used);
+       res = write_socket(sock_fd, req->sndbuf, req->used);
        if (res != 0) {
                connman_error("failed to send pkt\n");
                return -EIO;
        }
 
-       vici_client->request_list = g_slist_append(vici_client->request_list, req);
+       if(req->cmd != VICI_CMD_REGISTER_CHILD_UPDOWN)
+               vici_client->request_list = g_slist_append(vici_client->request_list, req);
+
        return res;
 }
 
@@ -734,7 +754,6 @@ static void debug_vici_message(char *buf, unsigned int size)
                        pos++;
                        g_strlcpy(temp + key_len + 1, (const gchar *)&buf[pos], value_len + 1);
                        pos += value_len;
-                       len = key_len + 1 + value_len;
                }
                        break;
                case VICI_LIST_START:
@@ -838,6 +857,9 @@ static int handle_vici_result(gboolean success, int cmd, char * err)
        case    VICI_CMD_INITIATE:
                ret = ECONNABORTED;
                break;
+       case    VICI_CMD_TERMINATE:
+               ret = EINVAL;
+               break;
        default:
                break;
        }
@@ -892,6 +914,32 @@ int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *r
        return ret;
 }
 
+
+int vici_set_event_cb(VICIClient *vici_client, vici_event_cb cb, gpointer user_data)
+{
+       struct request *req = NULL;
+       int ret;
+
+       DBG("%s",vici_cmd_str[VICI_EVENT_CHILD_UP]);
+       ret = create_vici_request(VICI_EVENT_REGISTER, VICI_CMD_REGISTER_CHILD_UPDOWN, &req);
+       if (ret < 0) {
+               connman_error("error on create_request\n");
+               return ret;
+       }
+
+       ret = send_vici_command(req, vici_client);
+       if (ret < 0) {
+               connman_error("error on send_command\n");
+       }
+
+       destroy_vici_request(req);
+       vici_client->event_cb = cb;
+       vici_client->event_user_data = user_data;
+
+       return ret;
+
+}
+
 static int get_socket_from_source(GIOChannel *source, GIOCondition condition)
 {
        int sock = -1;
@@ -930,31 +978,32 @@ static int read_socket(int sock, char *data, unsigned int data_len)
        return total_rbytes;
 }
 
-static int recv_vici_pkt(int sock, struct request *req)
+static int recv_vici_pkt(int sock, struct _VICIClient *vici_client)
 {
-       if(!req)
+       if(!vici_client)
                return -1;
 
-       if (req->rcv_pkt_size == 0) {
+       if (vici_client->rcv_pkt_size == 0) {
                unsigned int pkt_size = 0;
                if (read_socket(sock, (char *)&pkt_size, sizeof(pkt_size)) < 0)
                        return -1;
 
-               req->rcv_pkt_size = ntohl(pkt_size);
+               vici_client->rcv_pkt_size = ntohl(pkt_size);
                /* TODO :REMOVE THIS AFTER DEBUG */
-               DBG("rcv_pkt_size [%d] will be recved\n", req->rcv_pkt_size);
+               DBG("rcv_pkt_size [%d] will be recved\n", vici_client->rcv_pkt_size);
        } else {
 
+               DBG("rcv_pkt_size [%d] is recved\n", vici_client->rcv_pkt_size);
                char *buf = NULL;
-               buf = g_try_malloc0(req->rcv_pkt_size);
+               buf = g_try_malloc0(vici_client->rcv_pkt_size);
                if (buf == NULL)
                        return -1;
 
-               if (read_socket(sock, buf, req->rcv_pkt_size) < 0) {
+               if (read_socket(sock, buf, vici_client->rcv_pkt_size) < 0) {
                        g_free(buf);
                        return -1;
                }
-               req->rcvbuf = buf;
+               vici_client->rcvbuf = buf;
        }
 
        return 0;
@@ -974,14 +1023,138 @@ static struct request *pop_vici_request(VICIClient *vici_client)
        return list->data;
 }
 
-static gboolean process_reply(GIOChannel *source,
+static void process_vici_reply(VICIClient *vici_client)
+{
+       struct request *req;
+       int ret = 0;
+
+       if (!vici_client)
+               return;
+
+       /* get first request */
+       req = pop_vici_request(vici_client);
+       if (!req)
+               return;
+
+       req->rcvbuf = vici_client->rcvbuf;
+       req->rcv_pkt_size = vici_client->rcv_pkt_size;
+
+       ret = process_vici_response(req);
+       vici_client->request_list = g_slist_remove(vici_client->request_list, req);
+       destroy_vici_request(req);
+
+       /* TODO :remove this after debug */
+       DBG("left request reply : %d", g_slist_length(vici_client->request_list));
+
+       if (ret != 0 || g_slist_length(vici_client->request_list) == 0)
+               vici_client->reply_cb(ret, vici_client->reply_user_data);
+
+}
+
+static int extract_event_name(char *buf, unsigned int size, char *temp)
+{
+       int pos = 1;
+       int name_len = 0;
+       name_len = buf[pos];
+       pos++;
+       DBG("event len: %d", name_len);
+       while(pos <  size && pos - 2 < name_len) {
+               temp[pos - 2] = buf[pos];
+               pos++;
+       }
+       temp[pos] = '\0';
+       DBG("event name: %s", temp);
+       return pos;
+}
+
+static char *vici_get_value(char *buf, unsigned int pos, unsigned int size, char *search_key)
+{
+       int type = -1;
+
+       pos = 1;
+       while (pos < size) {
+
+               type = buf[pos];//3
+               pos++;
+               if (type == VICI_KEY_VALUE) {
+                       char *key = NULL;
+                       char *value = NULL;
+                       pos = extract_key_value(buf, pos, &key, &value);
+                       if (g_strcmp0(search_key, key) == 0) {
+                               g_free(key);
+                               return value;
+                       }
+
+                       g_free(key);
+                       g_free(value);
+               }
+       }
+       return NULL;
+}
+
+static void process_child_updown(VICIClient *vici_client,char *buf, unsigned int size)
+{
+       char *state = NULL;
+
+       state = vici_get_value(buf, 0, size, "state");
+       if (g_strcmp0(state, "ESTABLISHED") == 0) {
+               DBG("ESTABLISHED");
+               vici_client->event_cb(VICI_EVENT_CHILD_UP, vici_client->event_user_data);
+       } else if (g_strcmp0(state, "DELETING") == 0) {
+               DBG("DELETING");
+               vici_client->event_cb(VICI_EVENT_CHILD_DOWN, vici_client->event_user_data);
+       } else {
+               DBG("Unknown event");
+       }
+       g_free(state);
+       return;
+}
+
+static void process_vici_event(VICIClient *vici_client)
+{
+       char *buf = NULL;
+       unsigned int size = 0;
+       unsigned int pos = 0;
+       char temp[256] = {0,};
+       if (!vici_client || !(vici_client->rcvbuf) || vici_client->rcv_pkt_size == 0)
+               return;
+
+       buf = vici_client->rcvbuf;
+       size = vici_client->rcv_pkt_size;
+
+       pos = extract_event_name(buf, size, temp);
+       /* TODO: remove below after debug */
+       /* add parser */
+       if (g_strcmp0(temp, "child-updown") == 0)
+               process_child_updown(vici_client, buf + pos -1, size - pos);
+}
+
+static void process_vici_packet(VICIClient *vici_client, char *buf)
+{
+
+       if (!vici_client || !buf)
+               return;
+
+       if (buf[0] == VICI_CMD_RESPONSE) {
+               DBG("VICI_CMD_RESPONSE\n");
+               process_vici_reply(vici_client);
+       } else if (buf[0] == VICI_EVENT_CONFIRM) {
+               DBG("VICI_EVENT_CONFIRM\n");
+       } else if (buf[0] == VICI_EVENT) {
+               DBG("VICI_EVENT");
+               process_vici_event(vici_client);
+       } else {
+               DBG("Not handled [%u]", buf[0]);
+       }
+       return;
+}
+
+static gboolean process_vici_msg(GIOChannel *source,
                                           GIOCondition condition,
                                           gpointer user_data)
 {
        VICIClient *vici_client = NULL;
-       struct request * req = NULL;
        int sock = 0;
-       int ret = 0;
 
        vici_client = (VICIClient *)user_data;
        if (!vici_client)
@@ -991,27 +1164,18 @@ static gboolean process_reply(GIOChannel *source,
        if (sock < 0)
                return FALSE;
 
-       /* get first request */
-       req = pop_vici_request((VICIClient *)user_data);
-       if (!req)
-               return FALSE;
 
-       if(recv_vici_pkt(sock, req) < 0)
+       if(recv_vici_pkt(sock, vici_client) < 0)
                return FALSE;
 
-       if (!req->rcvbuf) {
+       if (!vici_client->rcvbuf) {
                return TRUE;
        }
 
-       ret = process_vici_response(req);
-       vici_client->request_list = g_slist_remove(vici_client->request_list, req);
-       destroy_vici_request(req);
-
-       /* TODO :remove this after debug */
-       DBG("left request reply : %d", g_slist_length(vici_client->request_list));
-
-       if (ret!= 0 || g_slist_length(vici_client->request_list) == 0)
-               vici_client->reply(ret, vici_client->ipsec_user_data);
+       process_vici_packet(vici_client, vici_client->rcvbuf);
+       g_free(vici_client->rcvbuf);
+       vici_client->rcvbuf = NULL;
+       vici_client->rcv_pkt_size = 0;
 
        return TRUE;
 }
@@ -1054,47 +1218,60 @@ static int connect_socket(const char *uri)
        return fd;
 }
 
-int vici_initialize(VICIClient **vici_client)
+static int initialize_vici_source(VICIClient *vici_client)
 {
        GIOChannel *vici_channel;
-
-       *vici_client = g_try_new0(VICIClient, 1);
-       if (!*vici_client) {
-               connman_error("out of memory");
+       if (!vici_client) {
                return -ENOMEM;
        }
 
-       (*vici_client)->client_sock_fd = connect_socket(VICI_DEFAULT_URI);
-       if ((*vici_client)->client_sock_fd < 0) {
+       vici_client->client_sock_fd = connect_socket(VICI_DEFAULT_URI);
+       if (vici_client->client_sock_fd < 0) {
                connman_error("connect_socket failed");
-               g_free(*vici_client);
                return -EIO;
        }
 
-       vici_channel = g_io_channel_unix_new((*vici_client)->client_sock_fd);
+       vici_channel = g_io_channel_unix_new(vici_client->client_sock_fd);
        if (!vici_channel) {
                connman_error("g_io_channel_unix_new failed");
-               close((*vici_client)->client_sock_fd);
-               g_free(*vici_client);
+               close(vici_client->client_sock_fd);
                return -ENOMEM;
        }
 
-       (*vici_client)->client_watch = g_io_add_watch_full(vici_channel,
+       vici_client->client_watch = g_io_add_watch_full(vici_channel,
                                                 G_PRIORITY_LOW,
                                                 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                                (GIOFunc)process_reply,
-                                                (gpointer)*vici_client,
+                                                (GIOFunc)process_vici_msg,
+                                                (gpointer)vici_client,
                                                 NULL);
        g_io_channel_unref(vici_channel);
+       return 0;
+}
+
+int vici_initialize(VICIClient **vici_client)
+{
+       int ret = 0;
+
+       *vici_client = g_try_new0(VICIClient, 1);
+       if (!*vici_client) {
+               connman_error("out of memory");
+               return -ENOMEM;
+       }
+
+       ret = initialize_vici_source(*vici_client);
+       if (ret != 0) {
+               g_free(*vici_client);
+               return ret;
+       }
 
        DBG("connected");
        return 0;
 }
 
-void vici_set_connect_reply_cb(VICIClient *vici_client, vici_connect_reply_cb reply_cb, gpointer user_data)
+void vici_set_request_reply_cb(VICIClient *vici_client, vici_request_reply_cb reply_cb, gpointer user_data)
 {
-       vici_client->reply = reply_cb;
-       vici_client->ipsec_user_data = user_data;
+       vici_client->reply_cb = reply_cb;
+       vici_client->reply_user_data = user_data;
 }
 
 int vici_deinitialize(VICIClient *vici_client)
@@ -1106,6 +1283,7 @@ int vici_deinitialize(VICIClient *vici_client)
 
        close(vici_client->client_sock_fd);
        g_slist_free_full(vici_client->request_list, destroy_vici_request);
+       g_free(vici_client->rcvbuf);
        g_free(vici_client);
 
        return 0;