diff options
-rwxr-xr-x | packaging/connman.spec | 2 | ||||
-rw-r--r-- | vpn/plugins/ipsec.c | 110 | ||||
-rw-r--r-- | vpn/plugins/vici-client.c | 268 | ||||
-rw-r--r-- | vpn/plugins/vici-client.h | 13 | ||||
-rwxr-xr-x | vpn/plugins/vpn.c | 55 |
5 files changed, 335 insertions, 113 deletions
diff --git a/packaging/connman.spec b/packaging/connman.spec index 241b8353..e653e084 100755 --- a/packaging/connman.spec +++ b/packaging/connman.spec @@ -5,7 +5,7 @@ Name: connman Version: 1.29 -Release: 22 +Release: 23 License: GPL-2.0+ Summary: Connection Manager Url: http://connman.net diff --git a/vpn/plugins/ipsec.c b/vpn/plugins/ipsec.c index b5205f7e..70f3433a 100644 --- a/vpn/plugins/ipsec.c +++ b/vpn/plugins/ipsec.c @@ -76,9 +76,13 @@ struct openssl_private_data { struct ipsec_private_data { struct vpn_provider *provider; struct openssl_private_data openssl_data; - vpn_provider_connect_cb_t cb; + vpn_provider_connect_cb_t connect_cb; + void *connect_user_data; +}; - void *user_data; +struct ipsec_event_data { + vpn_event_callback event_cb; + void *event_user_data; }; struct { @@ -162,6 +166,8 @@ static const char *ikev2_esp_proposals = "aes256-aes128-sha256-sha1"; static const char *ikev2_proposals = "aes256-aes128-sha512-sha384-sha256-sha1-modp2048-modp1536-modp1024"; +static struct ipsec_event_data event_data; + static void init_openssl(void) { /* Load the human readable error strings for libcrypto */ @@ -482,6 +488,14 @@ static int ipsec_notify(DBusMessage *msg, struct vpn_provider *provider) return 0; } +static void ipsec_set_event_cb(vpn_event_callback event_cb, struct vpn_provider *provider) +{ + DBG("set event cb!"); + event_data.event_cb = event_cb; + event_data.event_user_data = provider; + return; +} + static int ipsec_is_same_auth(const char* req, const char* target) { if (req == NULL || target == NULL) @@ -869,16 +883,71 @@ static int ipsec_load_cert(struct vpn_provider *provider) return ret; } -void connect_reply_cb(int err, void *user_data) +static int ipsec_terminate(struct vpn_provider *provider) +{ + VICISection *sect; + int ret = 0; + + sect = vici_create_section(NULL); + if (!sect) + return -ENOMEM; + + vici_add_kv(sect, "child", "net", NULL); + vici_add_kv(sect, "ike", vpn_provider_get_string(provider, "Name"), NULL); + vici_add_kv(sect, "timeout", "-1", NULL); + ret = vici_send_request(vici_client, VICI_CMD_TERMINATE, sect); + if (ret < 0) + connman_error("vici_send_request failed"); + + vici_destroy_section(sect); + + return ret; +} + +static void request_reply_cb(int err, void *user_data) { struct ipsec_private_data *data; data = (struct ipsec_private_data *)user_data; - data->cb(data->provider, data->user_data, err); + DBG("request reply cb"); + + if(err != 0) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE); + /* TODO: Does close socket needed? */ + } else { + DBG("Series of requests are succeeded"); + /* TODO: Not sure about below */ + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_CONNECT); + } free_private_data(data); } +static void ipsec_vici_event_cb(VICIClientEvent event, void *user_data) +{ + struct vpn_provider *provider; + + provider = (struct vpn_provider *)user_data; + if (!provider) { + DBG("Invalid user data"); + return; + } + + if(event == VICI_EVENT_CHILD_UP) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_READY); + } else if (event == VICI_EVENT_CHILD_DOWN) { + if (event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_DISCONNECT); + } else { + DBG("Unknown event"); + } + + return; +} + static struct ipsec_private_data* create_ipsec_private_data(struct vpn_provider *provider, vpn_provider_connect_cb_t cb, void* user_data) { @@ -892,8 +961,8 @@ static struct ipsec_private_data* create_ipsec_private_data(struct vpn_provider init_openssl(); data->provider = provider; - data->cb = cb; - data->user_data = user_data; + data->connect_cb = cb; + data->connect_user_data = user_data; return data; } @@ -907,7 +976,7 @@ static void vici_connect(struct ipsec_private_data *data) IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid data parameter"); provider = data->provider; - cb = data->cb; + cb = data->connect_cb; if (!provider || !cb) IPSEC_ERROR_CHECK_GOTO(-1, done, "Invalid provider or callback"); @@ -922,8 +991,15 @@ static void vici_connect(struct ipsec_private_data *data) /* TODO :remove this after debug */ DBG("success to initialize vici socket"); - vici_set_connect_reply_cb(vici_client, (vici_connect_reply_cb)connect_reply_cb, data); + vici_set_request_reply_cb(vici_client, (vici_request_reply_cb)request_reply_cb, data); + /* + * Sets child-updown event + */ + err = vici_set_event_cb(vici_client, (vici_event_cb)ipsec_vici_event_cb, provider); + IPSEC_ERROR_CHECK_GOTO(err, done, "register event failed"); + /* TODO :remove this after debug */ + DBG("success to vici_set_event_cb"); /* * Send the load-conn command */ @@ -984,8 +1060,9 @@ static void vici_connect(struct ipsec_private_data *data) done: /* refer to connect_cb on vpn-provider.c for cb */ - if(err != 0 && cb) - cb(provider, data->user_data, -err); + if(cb) + cb(provider, data->connect_user_data, -err); + /* TODO: Does close socket needed? when err is not zero */ return; } @@ -1014,6 +1091,8 @@ static void monitor_vici_socket(struct ipsec_private_data *data) if (error) { connman_error("g_file_monitor_directory failed: %s / %d", error->message, error->code); g_error_free(error); + if(event_data.event_cb) + event_data.event_cb(event_data.event_user_data, VPN_STATE_FAILURE); return; } /* TODO :remove this after debug */ @@ -1161,14 +1240,22 @@ static int ipsec_save(struct vpn_provider *provider, GKeyFile *keyfile) static void ipsec_disconnect(struct vpn_provider *provider) { int err = 0; + /* + * Send the terminate command + */ + err = ipsec_terminate(provider); + IPSEC_ERROR_CHECK_RETURN(err, "terminate failed"); err = vici_deinitialize(vici_client); IPSEC_ERROR_CHECK_RETURN(err, "failed to deinitialize vici_client"); + + return; } static struct vpn_driver vpn_driver = { .flags = VPN_FLAG_NO_TUN, .notify = ipsec_notify, + .set_event_cb = ipsec_set_event_cb, .connect = ipsec_connect, .error_code = ipsec_error_code, .save = ipsec_save, @@ -1179,6 +1266,9 @@ static int ipsec_init(void) { connection = connman_dbus_get_connection(); + event_data.event_cb = NULL; + event_data.event_user_data = NULL; + return vpn_register("ipsec", &vpn_driver, IPSEC); } diff --git a/vpn/plugins/vici-client.c b/vpn/plugins/vici-client.c index c1361e41..dc651cfd 100644 --- a/vpn/plugins/vici-client.c +++ b/vpn/plugins/vici-client.c @@ -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 { @@ -429,7 +435,6 @@ static void destroy_vici_request(gpointer data) return; g_free(req->sndbuf); - g_free(req->rcvbuf); g_free(req); } @@ -627,27 +632,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; } @@ -838,6 +847,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 +904,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 +968,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 +1013,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 +1154,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 +1208,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 +1273,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; diff --git a/vpn/plugins/vici-client.h b/vpn/plugins/vici-client.h index 9d08d7df..a33a8e46 100644 --- a/vpn/plugins/vici-client.h +++ b/vpn/plugins/vici-client.h @@ -39,15 +39,23 @@ typedef enum { VICI_CMD_UNLOAD_AUTH, VICI_CMD_LOAD_KEY, VICI_CMD_INITIATE, + VICI_CMD_TERMINATE, + VICI_CMD_REGISTER_CHILD_UPDOWN, VICI_CMD_MAX, } VICIClientCmd; +typedef enum { + VICI_EVENT_CHILD_UP, + VICI_EVENT_CHILD_DOWN, + VICI_EVENT_MAX, +} VICIClientEvent; #define VICI_DEFAULT_URI "/var/run/charon.vici" typedef int (*vici_add_element)(VICISection *sect, const char *key, const char *value, const char *subsection); -typedef void (*vici_connect_reply_cb)(int err, void *user_data); +typedef void (*vici_request_reply_cb)(int err, void *user_data); +typedef void (*vici_event_cb)(VICIClientEvent event, void *user_data); VICISection* vici_create_section(const char *name); int add_subsection(const char* name, VICISection* child, VICISection* section); @@ -65,8 +73,9 @@ int vici_add_cert_kvl(VICISection *section, const char *key, int vici_initialize(VICIClient **vici_client); int vici_deinitialize(VICIClient *vici_client); -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); int vici_send_request(VICIClient *vici_client, VICIClientCmd cmd, VICISection *root); +int vici_set_event_cb(VICIClient *vici_client, vici_event_cb cb, gpointer user_data); #ifdef __cplusplus } diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c index b48b6bca..e65dacac 100755 --- a/vpn/plugins/vpn.c +++ b/vpn/plugins/vpn.c @@ -310,15 +310,10 @@ static DBusMessage *vpn_notify(struct connman_task *task, #if defined TIZEN_EXT static void vpn_event(struct vpn_provider *provider, int state) { - struct vpn_data *data; struct vpn_driver_data *vpn_driver_data; const char *name; - int index, err; - - data = vpn_provider_get_data(provider); name = vpn_provider_get_driver_name(provider); - if (!name) { DBG("Cannot find VPN driver for provider %p", provider); vpn_provider_set_state(provider, VPN_PROVIDER_STATE_FAILURE); @@ -336,52 +331,12 @@ static void vpn_event(struct vpn_provider *provider, int state) switch (state) { case VPN_STATE_CONNECT: + vpn_provider_set_state(provider, + VPN_PROVIDER_STATE_CONNECT); + break; case VPN_STATE_READY: - if (data->state == VPN_STATE_READY) { - /* - * This is the restart case, in which case we must - * just set the IP address. - * - * We need to remove first the old address, just - * replacing the old address will not work as expected - * because the old address will linger in the interface - * and not disapper so the clearing is needed here. - * - * Also the state must change, otherwise the routes - * will not be set properly. - */ - vpn_provider_set_state(provider, - VPN_PROVIDER_STATE_CONNECT); - - vpn_provider_clear_address(provider, AF_INET); - vpn_provider_clear_address(provider, AF_INET6); - - vpn_provider_change_address(provider); - vpn_provider_set_state(provider, - VPN_PROVIDER_STATE_READY); - break; - } - - index = vpn_provider_get_index(provider); - vpn_provider_ref(provider); - data->watch = vpn_rtnl_add_newlink_watch(index, - vpn_newlink, provider); - err = connman_inet_ifup(index); - if (err < 0) { - if (err == -EALREADY) - /* - * So the interface is up already, that is just - * great. Unfortunately in this case the - * newlink watch might not have been called at - * all. We must manually call it here so that - * the provider can go to ready state and the - * routes are setup properly. - */ - vpn_newlink(IFF_UP, 0, provider); - else - DBG("Cannot take interface %d up err %d/%s", - index, -err, strerror(-err)); - } + vpn_provider_set_state(provider, + VPN_PROVIDER_STATE_READY); break; case VPN_STATE_UNKNOWN: |