diff options
author | Matt Ranostay <matt.ranostay@konsulko.com> | 2017-06-29 19:01:55 -0700 |
---|---|---|
committer | Matt Ranostay <matt.ranostay@konsulko.com> | 2017-06-30 11:57:16 -0700 |
commit | dfd034fb6016ad056131b17b30a0457789b791b9 (patch) | |
tree | c3b0e1ae6d892a44a011f080f978da37e3365473 /binding-wifi/wifi-api.c | |
parent | ca66ba0579e6c1e9a6d484f18633fdbd223a5bb5 (diff) |
binding: wifi: make system wide service
Allow WiFi binding to be build separately and installed
as a system wide service
Bug-AGL: SPEC-661 SPEC-715
Change-Id: Id9eb9d9efae3f0bc3ab00641eb26cd1b5dae9d53
Signed-off-by: Matt Ranostay <matt.ranostay@konsulko.com>
Diffstat (limited to 'binding-wifi/wifi-api.c')
-rw-r--r-- | binding-wifi/wifi-api.c | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/binding-wifi/wifi-api.c b/binding-wifi/wifi-api.c new file mode 100644 index 0000000..30552e8 --- /dev/null +++ b/binding-wifi/wifi-api.c @@ -0,0 +1,789 @@ +/* Copyright 2016 ALPS ELECTRIC CO., LTD. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** + * \file + * + * \brief Implementation of WiFi Binder for AGL's App Framework + * + * \author ALPS Electric + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <json-c/json.h> +#include <afb/afb-binding.h> + +#include "wifi-api.h" +#include "wifi-connman.h" + + + +static int need_passkey_flag = 0; +static int passkey_not_correct_flag = 0; + +char *passkey; +callback ptr_my_callback; +callback wifiListChanged_clbck; + +GSList *wifi_list = NULL; + + +/** + * \brief Input the passkey for connection to AP. + * + * \param[in] passkey pasword for the network + * + * The user should first subscribe for the event 'passkey' and then provide passkey + * when this event has been received. + * + * */ +static void insertpasskey(struct afb_req request) { + + + const char *passkey_from_user; + + /* retrieves the argument, expects passkey string */ + passkey_from_user = afb_req_value(request, "passkey"); + + NOTICE(afbitf, "Passkey inserted: %s\n", passkey_from_user); + + sendPasskey(passkey_from_user); + + + if (passkey != NULL) { + + registerPasskey(passkey); + } else { + NOTICE(afbitf, "Please enter the passkey first\n"); + + } +} + + + +struct event +{ + struct event *next; + struct afb_event event; + char tag[1]; +}; + +static struct event *events = 0; + +/** + * \internal + * \brief Helper function that searches for a specific event. + * + * \param[in] tag of the event + */ +static struct event *event_get(const char *tag) +{ + struct event *e = events; + while(e && strcmp(e->tag, tag)) + e = e->next; + return e; +} + +/** + * \internal + * \brief Helper function that actually pushes the event. + * + * \param[in] tag of the event + * \param[in] *args json object that contains data for the event + * + */ +static int do_event_push(struct json_object *args, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_event_push(e->event, json_object_get(args)) : -1; +} + +/** + * \internal + * \brief Pushes the event of 'tag' with the 'data + * + * \param[in] tag + * \param[in] data + * + */ +static void eventpush (struct afb_req request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *data = afb_req_value(request, "data"); + json_object *object = data ? json_tokener_parse(data) : NULL; + + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 > do_event_push(object, tag)) + afb_req_fail(request, "failed", "push error"); + else + afb_req_success(request, NULL, NULL); +} + +/** + * + * \brief Notify user that passkey is necessary. + * + * \param[in] number additional integer data produced by Agent + * \param[in] asciidata additional ascii data produced by Agent + * + * This function is called from the registered agent on RequestInput() call. + * + */ +void ask_for_passkey(int number, const char* asciidata) { + NOTICE(afbitf, "Passkey for %s network needed.", asciidata); + NOTICE(afbitf, "Sending event."); + + json_object *jresp = json_object_new_object(); + + json_object *int1 = json_object_new_int(number); + json_object *string = json_object_new_string(asciidata); + + json_object_object_add(jresp, "data1", int1); + json_object_object_add(jresp, "data2", string); + + + do_event_push(jresp, "passkey"); +} + +/** + * \internal + * \brief Notify GUI that wifi list has changed. + * + * \param[in] number number of event that caused the callback + * \param[in] asciidata additional data, e.g "BSSRemoved" + * + * User should first subscribe for the event 'networkList' and then wait for this event. + * When notification comes, update the list if networks by scan_result call. + * + */ +void wifiListChanged(int number, const char* asciidata) { + + //WARNING(afbitf, "wifiListChanged, reason:%d, %s",number, asciidata ); + + + json_object *jresp = json_object_new_object(); + + json_object *int1 = json_object_new_int(number); + json_object *string = json_object_new_string(asciidata); + + json_object_object_add(jresp, "data1", int1); + json_object_object_add(jresp, "data2", string); + + do_event_push(jresp, "networkList"); + + + +} + + +/** + * \brief Initializes the binder and activates the WiFi HW, should be called first. + * + * \param[in] request no specific data needed + * + * \return result of the request, either "success" or "failed" with description of error + * + * This will fail if + * - agent for handling passkey requests cannot be registered + * - some error is returned from connman + */ +static void activate(struct afb_req request) /*AFB_SESSION_CHECK*/ +{ + json_object *jresp; + GError *error = NULL; + + if (ptr_my_callback == NULL) { + + ptr_my_callback = ask_for_passkey; + register_callbackSecurity(ptr_my_callback); + + } + + if (wifiListChanged_clbck == NULL) { + + wifiListChanged_clbck = wifiListChanged; + register_callbackWiFiList(wifiListChanged_clbck); + + } + + jresp = json_object_new_object(); + json_object_object_add(jresp, "activation", json_object_new_string("on")); + + error = do_wifiActivate(); + + if (error == NULL) { + + afb_req_success(request, jresp, "Wi-Fi - Activated"); + + } else + + afb_req_fail(request, "failed", error->message); + +} + +/** + * \brief Deinitializes the binder and deactivates the WiFi HW. + * + * \param[in] request no specific data needed + * + * \return result of the request, either "success" or "failed" with description of error + * + * This will fail if + * - agent for handling passkey requests cannot be unregistered + * - some error is returned from connman + * + */ +static void deactivate(struct afb_req request) /*AFB_SESSION_CHECK*/ +{ + + json_object *jresp; + GError *error = NULL; + + ptr_my_callback = NULL; + + jresp = json_object_new_object(); + json_object_object_add(jresp, "deactivation", json_object_new_string("on")); + + error = do_wifiDeactivate(); + + if (error == NULL) { + + afb_req_success(request, jresp, "Wi-Fi - Activated"); + + } else + + afb_req_fail(request, "failed", error->message); +} + +/** + * \brief Starts scan for access points. + * + * \param[in] request no specific data needed + * + * \return result of the request, either "success" or "failed" with description of error + * + * User should first subscribe for the event 'networkList' and then wait for event to come. + * When notification comes, update the list of networks by scan_result call. + */ +static void scan(struct afb_req request) /*AFB_SESSION_NONE*/ +{ + GError *error = NULL; + + error = do_wifiScan(); + + if (error == NULL) { + + afb_req_success(request, NULL, "Wi-Fi - Scan success"); + + } else + + afb_req_fail(request, "failed", error->message); + +} + +/** + * \brief Return network list. + * + * \param[in] request no specific data needed + * + * \return result of the request, either "success" or "failed" with description of error \n + * result is array of following json objects: Number, Strength, ESSID, Security, IPAddress, State. + * E.g. {"Number":0,"Strength":82,"ESSID":"wifidata02","Security":"ieee8021x","IPAddress":"unsigned","State":"idle"}, or \n + * {"Number":1,"Strength":51,"ESSID":"ALCZM","Security":"WPA-PSK","IPAddress":"192.168.1.124","State":"ready"} + */ +static void scan_result(struct afb_req request) /*AFB_SESSION_CHECK*/ +{ + struct wifi_profile_info *wifiProfile = NULL; + GSList *list = NULL; + GSList *holdMe = NULL; + wifi_list = NULL; + char *essid = NULL; + char *address = NULL; + char *security = NULL; + char *state = NULL; + unsigned int strength = 0; + int number = 0; + GError *error = NULL; + + error = do_displayScan(&wifi_list); /*Get wifi scan list*/ + if (error == NULL) { + json_object *my_array = json_object_new_array(); + + for (list = wifi_list; list; list = list->next) { /*extract wifi scan result*/ + wifiProfile = (struct wifi_profile_info *) list->data; + security = wifiProfile->Security.sec_type; + strength = wifiProfile->Strength; + //if (essid == NULL || security == NULL) + // continue; + + essid = wifiProfile->ESSID == NULL ? + "HiddenSSID" : wifiProfile->ESSID; + address = + wifiProfile->wifiNetwork.IPaddress == NULL ? + "unsigned" : wifiProfile->wifiNetwork.IPaddress; + state = wifiProfile->state; + //TODO: is there a case when security is NULL? + + json_object *int1 = json_object_new_int(number); + json_object *int2 = json_object_new_int(strength); + json_object *jstring1 = json_object_new_string(essid); + json_object *jstring2 = json_object_new_string(security); + json_object *jstring3 = json_object_new_string(address); + json_object *jstring4 = json_object_new_string(state); + + json_object *jresp = json_object_new_object(); + json_object_object_add(jresp, "Number", int1); + json_object_object_add(jresp, "Strength", int2); + json_object_object_add(jresp, "ESSID", jstring1); + json_object_object_add(jresp, "Security", jstring2); + json_object_object_add(jresp, "IPAddress", jstring3); + json_object_object_add(jresp, "State", jstring4); + + DEBUG(afbitf, "The object json: %s\n", json_object_to_json_string(jresp)); + + /*input each scan result into my_array*/ + json_object_array_add(my_array, jresp); + number += 1; + + //set the HMI icon according to strength, only if "ready" or "online" + + int error = 0; + struct wifiStatus *status; + + status = g_try_malloc0(sizeof(struct wifiStatus)); + error = wifi_state(status); /*get current status of power and connection*/ + if (!error) { + + if (status->connected == 1) { + + if ((strcmp(state, "ready") == 0) + || ((strcmp(state, "online") == 0))) { + + if (strength < 30) + setHMIStatus(BAR_1); + else if (strength < 50) + setHMIStatus(BAR_2); + else if (strength < 70) + setHMIStatus(BAR_3); + else + setHMIStatus(BAR_FULL); + } + } else + setHMIStatus(BAR_NO); + } + + } + while (list != NULL) { + holdMe = list->next; + g_free(list); + list = holdMe; + } + afb_req_success(request, my_array, "Wi-Fi - Scan Result is Displayed"); + } else + afb_req_fail(request, "failed", error->message); +} + +/** + * \brief Connects to a specific network. + * + * \param[in] request Number of network to connect to. + * + * \return result of the request, either "success" or "failed" with description of error + * + * Specify number of network to connect to obtained by scan_result(). + * User should first subscribe for the event 'passkey', if passkey + * is needed for connection this event is pushed. + * + */ +static void connect(struct afb_req request) { + + struct wifi_profile_info *wifiProfileToConnect = NULL; + + const char *network; + int network_index = 0; + GError *error = NULL; + GSList *item = NULL; + + /* retrieves the argument, expects the network number */ + network = afb_req_value(request, "network"); + + if (network == NULL) + //TODO:better error message + afb_req_fail(request, "failed", + "specify a network number to connect to"); + + else { + network_index = atoi(network); + NOTICE(afbitf,"Joining network number %d\n", network_index); + + + } + + //get information about desired network + item = g_slist_nth_data(wifi_list, network_index); + + if (item == NULL) { + //Index starts from 1 + ERROR(afbitf, "Network with number %d not found.\n", network_index + 1); + //TODO:better error message + afb_req_fail(request, "failed", "bad arguments"); + } + + else { + wifiProfileToConnect = (struct wifi_profile_info *) item; + INFO(afbitf, "Name: %s, strength: %d, %s\n", wifiProfileToConnect->ESSID, + wifiProfileToConnect->Strength, + wifiProfileToConnect->NetworkPath); + } + error = do_connectNetwork(wifiProfileToConnect->NetworkPath); + + if (error == NULL) + afb_req_success(request, NULL, NULL); + + else if (passkey_not_correct_flag) { + need_passkey_flag = 0; + passkey_not_correct_flag = 0; + afb_req_fail(request, "passkey-incorrect", NULL); + } else if (need_passkey_flag) { + need_passkey_flag = 0; + afb_req_fail(request, "need-passkey", NULL); + + } else + afb_req_fail(request, "failed", error->message); +} + +/** + * \brief Disconnects from a network. + * + * \param[in] request number of network to disconnect from + * + * \return result of the request, either "success" or "failed" with description of error + * + * Specify number of network to disconnect from obtained by scan_result(). + */ +static void disconnect(struct afb_req request) { + + struct wifi_profile_info *wifiProfileToConnect = NULL; + + const char *network; + int network_index = 0; + GError *error = NULL; + GSList *item = NULL; + + /* retrieves the argument, expects the network number */ + network = afb_req_value(request, "network"); + + if (network == NULL) + //TODO:better error message + afb_req_fail(request, "failed", + "specify a network number to disconnect from"); + + else { + network_index = atoi(network); + NOTICE(afbitf, "Joining network number %d\n", network_index); + + } + + //get information about desired network + item = g_slist_nth_data(wifi_list, network_index); + + if (item == NULL) { + //Index starts from 1 + ERROR(afbitf,"Network with number %d not found.\n", network_index + 1); + //TODO:better error message + afb_req_fail(request, "failed", "bad arguments"); + } + + else { + wifiProfileToConnect = (struct wifi_profile_info *) item; + INFO(afbitf, "Name: %s, strength: %d, %s\n", wifiProfileToConnect->ESSID, + wifiProfileToConnect->Strength, + wifiProfileToConnect->NetworkPath); + } + error = do_disconnectNetwork(wifiProfileToConnect->NetworkPath); + + if (error == NULL) + afb_req_success(request, NULL, NULL); + else + afb_req_fail(request, "failed", error->message); +} + +/** + * \brief Return current status of a connection. + * + * \param[in] request no specific data needed + * + * \return result of the request, either "success" with status or "failed" with description of error + */ +static void status(struct afb_req request) { + int error = 0; + wifi_list = NULL; + struct wifiStatus *status; + json_object *jresp = json_object_new_object(); + + status = g_try_malloc0(sizeof(struct wifiStatus)); + error = wifi_state(status); /*get current status of power and connection*/ + if (!error) { + if (status->state == 0) {/*Wi-Fi is OFF*/ + json_object_object_add(jresp, "Power", + json_object_new_string("OFF")); + //json_object_object_add(jresp, "Connection", json_object_new_string("Disconnected")); + DEBUG(afbitf, "Wi-Fi OFF\n"); + } else {/*Wi-Fi is ON*/ + json_object_object_add(jresp, "Power", + json_object_new_string("ON")); + if (status->connected == 0) {/*disconnected*/ + json_object_object_add(jresp, "Connection", + json_object_new_string("Disconnected")); + DEBUG(afbitf, "Wi-Fi ON - Disconnected \n"); + } else {/*Connected*/ + json_object_object_add(jresp, "Connection", + json_object_new_string("Connected")); + DEBUG(afbitf, "Wi-Fi ON - Connected \n"); + } + } + afb_req_success(request, jresp, "Wi-Fi - Connection Status Checked"); + } else { + afb_req_fail(request, "failed", "Wi-Fi - Connection Status unknown"); + } +} + +static void reconnect() { + /*TBD*/ +} + + + +/** + * \internal + * \brief Helper functions that actually delete the tag. + * + * \param[in] tag tag to delete + * + * \return result of the request, either "success" or "failed" with description of error + */ +static int event_del(const char *tag) +{ + struct event *e, **p; + + /* check exists */ + e = event_get(tag); + if (!e) return -1; + + /* unlink */ + p = &events; + while(*p != e) p = &(*p)->next; + *p = e->next; + + /* destroys */ + afb_event_drop(e->event); + free(e); + return 0; +} + +/** + * \internal + * \brief Helper functions that actually creates event of the tag. + * + * \param[in] tag tag to add + * \param[in] name name to add + * + * \return result of the request, either "success" or "failed" with description of error + */ +static int event_add(const char *tag, const char *name) +{ + struct event *e; + + /* check valid tag */ + e = event_get(tag); + if (e) return -1; + + /* creation */ + e = malloc(strlen(tag) + sizeof *e); + if (!e) return -1; + strcpy(e->tag, tag); + + /* make the event */ + e->event = afb_daemon_make_event(afbitf->daemon, name); + if (!e->event.closure) { free(e); return -1; } + + /* link */ + e->next = events; + events = e; + return 0; +} + +/** + * \brief Creates event of the tag. + * + * \param[in] request tag and name of the event + * + * \return result of the request, either "success" or "failed" with description of error + */ +static void eventadd (struct afb_req request) +{ + const char *tag = afb_req_value(request, "tag"); + const char *name = afb_req_value(request, "name"); + + json_object *query = afb_req_json(request); + + if (tag == NULL || name == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_add(tag, name)) + afb_req_fail(request, "failed", "creation error"); + else + afb_req_success(request, NULL, NULL); +} + +/** + * \brief Deletes the event of tag. + * + * \param[in] request tag to delete + * + * \return result of the request, either "success" or "failed" with description of error + */ +static void eventdel (struct afb_req request) +{ + const char *tag = afb_req_value(request, "tag"); + + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_del(tag)) + afb_req_fail(request, "failed", "deletion error"); + else + afb_req_success(request, NULL, NULL); +} + + +/** + * \internal + * \brief Helper functions to subscribe for the event of tag. + * + * \param[in] request tag to subscribe for + * + * \return result of the request, either "success" or "failed" with description of error + */ +static int event_subscribe(struct afb_req request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_subscribe(request, e->event) : -1; +} + +/** + * \internal + * \brief Helper functions to unsubscribe for the event of tag. + * + * \param[in] request tag to unsubscribe for + * + * \return result of the request, either "success" or "failed" with description of error + */ +static int event_unsubscribe(struct afb_req request, const char *tag) +{ + struct event *e; + e = event_get(tag); + return e ? afb_req_unsubscribe(request, e->event) : -1; +} + + +/** + * \brief Subscribes for the event of tag. + * + * \param[in] request tag to subscribe for + * + * \return result of the request, either "success" or "failed" with description of error + */ +static void eventsub (struct afb_req request) +{ + const char *tag = afb_req_value(request, "tag"); + + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_subscribe(request, tag)) + afb_req_fail(request, "failed", "subscription error"); + else + afb_req_success(request, NULL, NULL); +} + + +/** + * \brief Unsubscribes for the event of tag. + * + * \param[in] request tag to unsubscribe for + * + * \return result of the request, either "success" or "failed" with description of error + */ +static void eventunsub (struct afb_req request) +{ + const char *tag = afb_req_value(request, "tag"); + + if (tag == NULL) + afb_req_fail(request, "failed", "bad arguments"); + else if (0 != event_unsubscribe(request, tag)) + afb_req_fail(request, "failed", "unsubscription error"); + else + afb_req_success(request, NULL, NULL); +} + + +/* + * array of the verbs exported to afb-daemon + */ +static const struct afb_verb_desc_v1 binding_verbs[] = { +/* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ +{ .name = "activate", .session = AFB_SESSION_NONE, .callback = activate, .info = "Activate Wi-Fi" }, +{ .name = "deactivate", .session = AFB_SESSION_NONE, .callback = deactivate, .info ="Deactivate Wi-Fi" }, +{ .name = "scan", .session = AFB_SESSION_NONE, .callback = scan, .info ="Scanning Wi-Fi" }, +{ .name = "scan_result", .session = AFB_SESSION_NONE, .callback = scan_result, .info = "Get scan result Wi-Fi" }, +{ .name = "connect", .session = AFB_SESSION_NONE, .callback = connect, .info ="Connecting to Access Point" }, +{ .name = "status", .session = AFB_SESSION_NONE, .callback = status, .info ="Check connection status" }, +{ .name = "disconnect", .session = AFB_SESSION_NONE, .callback = disconnect, .info ="Disconnecting connection" }, +{ .name = "reconnect", .session = AFB_SESSION_NONE, .callback = reconnect, .info ="Reconnecting to Access Point" }, +{ .name = "insertpasskey",.session = AFB_SESSION_NONE, .callback = insertpasskey, .info ="inputs the passkey after it has been requsted"}, +{ .name = "eventadd", .session = AFB_SESSION_NONE, .callback = eventadd, .info ="adds the event of 'name' for the 'tag'"}, +{ .name = "eventsub", .session = AFB_SESSION_NONE, .callback = eventsub, .info ="unsubscribes to the event of 'tag'"}, +{ .name = "eventpush", .session = AFB_SESSION_NONE, .callback = eventpush, .info ="pushes the event of 'tag' with the 'data'"}, +{ .name = "eventunsub", .session = AFB_SESSION_NONE, .callback = eventunsub, .info ="unsubscribes to the event of 'tag'"}, +{ .name = "eventdel", .session = AFB_SESSION_NONE, .callback = eventdel, .info ="deletes the event of 'tag'"}, + +{ .name = NULL } /* marker for end of the array */ +}; + +/* + * description of the binding for afb-daemon + */ +static const struct afb_binding binding_description = { +/* description conforms to VERSION 1 */ +.type = AFB_BINDING_VERSION_1, .v1 = { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ +.prefix = "wifi-manager", /* the API name (or binding name or prefix) */ +.info = "wifi API", /* short description of of the binding */ +.verbs = binding_verbs /* the array describing the verbs of the API */ +} }; + +/* + * activation function for registering the binding called by afb-daemon + */ +const struct afb_binding *afbBindingV1Register( + const struct afb_binding_interface *itf) { + afbitf = itf; // records the interface for accessing afb-daemon + return &binding_description; // returns the description of the binding +} + |