Add Wifi Direct Service Discovery 04/15604/11
authorJiung Yu <jiung.yu@samsung.com>
Fri, 24 Jan 2014 06:22:00 +0000 (15:22 +0900)
committerJiung Yu <jiung.yu@samsung.com>
Thu, 13 Feb 2014 06:58:54 +0000 (15:58 +0900)
Change-Id: I45c34891817eee90d4ecb10ebf5dca49bde363f9
Signed-off-by: Yu jiung <jiung.yu@samsung.com>
12 files changed:
include/wifi-direct-manager.h
oem/wifi-direct-oem.c
oem/wifi-direct-oem.h
packaging/wifi-direct-manager.changes
packaging/wifi-direct-manager.spec
plugin/wpasupplicant/wfd-plugin-wpasupplicant.c
plugin/wpasupplicant/wfd-plugin-wpasupplicant.h
src/wifi-direct-client.c
src/wifi-direct-event.c
src/wifi-direct-group.c
src/wifi-direct-manager.c
src/wifi-direct-peer.c

index aa87a2d..1567796 100644 (file)
@@ -41,6 +41,7 @@
 #define IPSTR_LEN 16
 #define PINSTR_LEN 8
 #define PASSPHRASE_LEN 8
+#define QUERY_HANDLE_LIMIT 256
 
 #if 0
 typedef enum {
@@ -72,6 +73,21 @@ typedef enum {
        WFD_SCAN_MODE_PASSIVE,
 } wfd_scan_mode_e;
 
+typedef struct {
+       wifi_direct_service_type_e service_type;
+       int ref_counter;
+       char *service_string;
+       int service_str_length;
+} wfd_service_s;
+
+typedef struct {
+       int handle;
+       int ref_counter;
+       unsigned char mac_addr[6];
+       wifi_direct_service_type_e service_type;
+       char *query_string;
+}wfd_query_s;
+
 typedef enum {
        WFD_PEER_STATE_DISCOVERED,
        WFD_PEER_STATE_CONNECTING,
@@ -95,6 +111,8 @@ typedef struct {
        int group_flags;
        int wps_mode;
 
+       GList *services;
+
        int wfd_dev_info;
        int wfd_ctrl_port;
        int wfd_max_tput;
@@ -127,6 +145,8 @@ typedef struct {
 
        void *group;
 
+       GList *query_handles;
+
        void *oem_ops;
        void *plugin_handle;
 } wfd_manager_s;
@@ -152,6 +172,13 @@ int wfd_manager_set_autoconnection(int autoconnection);
 int wfd_manager_get_req_wps_mode(int *req_wps_mode);
 int wfd_manager_set_req_wps_mode(int req_wps_mode);
 
+int wfd_manager_service_add(wfd_manager_s *manager, wifi_direct_service_type_e type, char *data);
+int wfd_manager_service_del(wfd_manager_s *manager, wifi_direct_service_type_e  type, char *data);
+int wfd_manager_serv_disc_req(wfd_manager_s *manager, unsigned char* mad_addr, wifi_direct_service_type_e  type, char *data);
+int wfd_manager_serv_disc_cancel(wfd_manager_s *manager, int handle);
+int wfd_manager_init_service(wfd_device_s *device);
+int wfd_manager_init_query(wfd_manager_s *manager);
+
 int wfd_manager_local_config_set(wfd_manager_s *manager);
 int wfd_manager_activate(wfd_manager_s *manager);
 int wfd_manager_deactivate(wfd_manager_s *manager);
index 99df579..f256072 100644 (file)
@@ -386,3 +386,42 @@ int wfd_oem_set_persistent_reconnect(wfd_oem_ops_s *ops, unsigned char *bssid, i
        return ops->set_persistent_reconnect(bssid, reconnect);
 }
 
+int wfd_oem_service_add(wfd_oem_ops_s *ops, wfd_oem_service_e type, char *data)
+{
+       if (!ops || !ops->service_add) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       return ops->service_add(type, data);
+}
+
+int wfd_oem_service_del(wfd_oem_ops_s *ops, wfd_oem_service_e type, char *data)
+{
+       if (!ops || !ops->service_del) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       return ops->service_del(type, data);
+}
+
+int wfd_oem_serv_disc_req(wfd_oem_ops_s *ops, unsigned char* MAC, wfd_oem_service_e type, char *data)
+{
+       if (!ops || !ops->serv_disc_req) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       return ops->serv_disc_req(MAC, type, data);
+}
+
+int wfd_oem_serv_disc_cancel(wfd_oem_ops_s *ops, int identifier)
+{
+       if (!ops || !ops->serv_disc_cancel) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       return ops->serv_disc_cancel(identifier);
+}
index 92b7330..193b210 100644 (file)
@@ -72,6 +72,8 @@ typedef enum {
        WFD_OEM_EVENT_CONNECTED,        // 25
        WFD_OEM_EVENT_DISCONNECTED,
 
+       WFD_OEM_EVENT_SERV_DISC_RESP,
+
        WFD_OEM_EVENT_TERMINATING,
 
        WFD_OEM_EVENT_MAX,
@@ -149,6 +151,7 @@ typedef enum {
        WFD_OEM_EDATA_TYPE_CONN,
        WFD_OEM_EDATA_TYPE_INVITE,
        WFD_OEM_EDATA_TYPE_GROUP,
+       WFD_OEM_EDATA_TYPE_SERVICE,
 } ws_event_type_e;
 
 typedef enum {
@@ -185,6 +188,16 @@ typedef enum {
        WFD_OEM_DEV_ROLE_GO,
 } wfd_oem_dev_role_e;
 
+typedef enum
+{
+       WFD_OEM_SERVICE_ALL,
+       WFD_OEM_SERVICE_BONJOUR,
+       WFD_OEM_SERVICE_UPNP,
+       WFD_OEM_SERVICE_WSDISCOVERY,
+       WFD_OEM_SERVICE_WIFIDISPLAY,
+       WFD_OEM_SERVICE_VENDORSPEC = 0xff,
+} wfd_oem_service_e;
+
 typedef struct {
        int scan_mode;
        int scan_time;
@@ -255,6 +268,12 @@ typedef struct _wfd_oem_ops_s {
        int (*get_persistent_groups) (wfd_oem_persistent_group_s **groups, int *group_count);
        int (*remove_persistent_group) (char *ssid, unsigned char *bssid);
        int (*set_persistent_reconnect) (unsigned char *bssid, int reconnect);
+
+       int (*service_add) (wfd_oem_service_e type,char *data);
+       int (*service_del) (wfd_oem_service_e type,char *data);
+       int (*serv_disc_req) (unsigned char* MAC, wfd_oem_service_e type,char *data);
+       int (*serv_disc_cancel) (int identifier);
+
 } wfd_oem_ops_s;
 
 int wfd_oem_init(wfd_oem_ops_s *ops, wfd_oem_event_cb event_callback, void *user_data);
@@ -296,4 +315,9 @@ int wfd_oem_get_persistent_groups(wfd_oem_ops_s *ops, wfd_oem_persistent_group_s
 int wfd_oem_remove_persistent_group(wfd_oem_ops_s *ops, char *ssid, unsigned char *bssid);
 int wfd_oem_set_persistent_reconnect(wfd_oem_ops_s *ops, unsigned char *bssid, int reconnect);
 
+int wfd_oem_service_add(wfd_oem_ops_s *ops, wfd_oem_service_e type, char *data);
+int wfd_oem_service_del(wfd_oem_ops_s *ops, wfd_oem_service_e type, char *data);
+int wfd_oem_serv_disc_req(wfd_oem_ops_s *ops, unsigned char* MAC, wfd_oem_service_e type, char *data);
+int wfd_oem_serv_disc_cancel(wfd_oem_ops_s *ops, int identifier);
+
 #endif /* __WIFI_DIRECT_OEM_H__ */
index 5114721..4e4dda6 100644 (file)
@@ -1,3 +1,6 @@
+Fri, 24 Jan 2014 Jiung Yu <jiung.yu@samaung.com> (1.0.8)
+  * Add Wifi Direct Service Discovery
+
 Tue, 15 Jan 2014 Jiung Yu <jiung.yu@samaung.com> (1.0.7)
   * Replace file execution method
 
index d318e74..e28accd 100644 (file)
@@ -1,6 +1,6 @@
 Name:       wifi-direct-manager
 Summary:    Wi-Fi Direct manger
-Version:    1.0.7
+Version:    1.0.8
 Release:    1
 Group:      Network & Connectivity/Wireless
 License:    Apache-2.0
index 378245a..4b7a280 100644 (file)
@@ -81,6 +81,9 @@ ws_string_s ws_event_strs[] = {
        {"P2P-GROUP-STARTED", WS_EVENT_GROUP_STARTED},
        {"P2P-GROUP-REMOVED", WS_EVENT_GROUP_REMOVED},
 
+       //service
+       {"P2P-SERV-DISC-RESP", WS_EVENT_SERV_DISC_RESP},
+
        {"CTRL-EVENT-TERMINATING", WS_EVENT_TERMINATING},
        };
 
@@ -194,6 +197,11 @@ static wfd_oem_ops_s supplicant_ops = {
        .get_persistent_groups = ws_get_persistent_groups,
        .remove_persistent_group = ws_remove_persistent_group,
        .set_persistent_reconnect = ws_set_persistent_reconnect,
+
+       .service_add = ws_service_add,
+       .service_del = ws_service_del,
+       .serv_disc_req = ws_serv_disc_req,
+       .serv_disc_cancel = ws_serv_disc_cancel,
        };
 
 static ws_plugin_data_s *g_pd;
@@ -1571,6 +1579,22 @@ static int _parsing_event_info(char *ifname, char *msg, wfd_oem_event_s *data)
 
                }
                break;
+       case WS_EVENT_SERV_DISC_RESP:
+               {
+                       _ws_txt_to_mac(info_str, data->dev_addr);
+                       info_str += OEM_MACSTR_LEN;
+
+                       WDP_LOGD("service tlv is %s", info_str);
+
+                       if (!strlen(info_str)) {
+                               WDP_LOGD("Nothing to parse anymore");
+                               data->edata_type = WFD_OEM_EDATA_TYPE_NONE;
+                               break;
+                       }
+                       data->edata = (void*)strndup(info_str, strlen(info_str));
+                       data->edata_type = WFD_OEM_EDATA_TYPE_SERVICE;
+               }
+               break;
        default:
                WDP_LOGE("Unknown event");
                break;
@@ -1586,7 +1610,7 @@ static gboolean ws_event_handler(GIOChannel *source,
 {
        __WDP_LOG_FUNC_ENTER__;
        ws_sock_data_s * sd = (ws_sock_data_s*) data;
-       char msg[1024] = {0, };
+       char msg[2048] = {0, };
        char *param;
        int event_id = -1;
        wfd_oem_event_s *event = NULL;
@@ -1698,8 +1722,6 @@ static gboolean ws_event_handler(GIOChannel *source,
                break;
        case WS_EVENT_INVITATION_RECEIVED:
                {
-                       wfd_oem_invite_data_s* edata = NULL;
-                       edata = (wfd_oem_invite_data_s*) event->edata;
                        event_id = WFD_OEM_EVENT_INVITATION_REQ;
                }
                break;
@@ -1712,6 +1734,9 @@ static gboolean ws_event_handler(GIOChannel *source,
        case WS_EVENT_STA_DISCONNECTED:
                event_id = WFD_OEM_EVENT_STA_DISCONNECTED;
                break;
+       case WS_EVENT_SERV_DISC_RESP:
+               event_id = WFD_OEM_EVENT_SERV_DISC_RESP;
+               break;
        case WS_EVENT_TERMINATING:
                event_id = WFD_OEM_EVENT_TERMINATING;
                break;
@@ -2828,6 +2853,229 @@ int _parsing_networks(char* buf, ws_network_info_s networks[], int *network_cnt)
        return 0;
 }
 
+int ws_service_add(wfd_oem_service_e service_type, char *data)
+{
+       __WDP_LOG_FUNC_ENTER__;
+       ws_sock_data_s *sock = g_pd->common;
+       char cmd[256] = {0, };
+       char reply[1024]={0,};
+       int res;
+
+       if (!sock) {
+               WDP_LOGE("Socket is NULL");
+               return -1;
+       }
+       if (!data || !strlen(data)) {
+               WDP_LOGE( "Invalid parameter");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (service_type == WFD_OEM_SERVICE_BONJOUR)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_ADD "bonjour %s", data);
+       else if (service_type == WFD_OEM_SERVICE_UPNP)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_ADD "upnp %s", data);
+       else if (service_type ==WFD_OEM_SERVICE_VENDORSPEC)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_ADD "vendor %s", data);
+       else{
+               WDP_LOGE( "Invalid parameter");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       res = _ws_send_cmd(sock->ctrl_sock, cmd, (char*) reply, sizeof(reply));
+       if (res < 0) {
+               WDP_LOGE("Failed to send command to wpa_supplicant");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (strstr(reply, "FAIL")) {
+               WDP_LOGE("Failed to add service");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+       WDP_LOGD("Succeeded to add service");
+
+       __WDP_LOG_FUNC_EXIT__;
+       return 0;
+}
+
+int ws_service_del(wfd_oem_service_e service_type, char *data)
+{
+       __WDP_LOG_FUNC_ENTER__;
+       ws_sock_data_s *sock = g_pd->common;
+       char cmd[256] = {0, };
+       char reply[1024]={0,};
+       int res;
+
+       if (!sock) {
+               WDP_LOGE("Socket is NULL");
+               return -1;
+       }
+       if (!data || !strlen(data)) {
+               WDP_LOGE( "Invalid parameter");
+               __WDP_LOG_FUNC_EXIT__;
+               return 1;
+       }
+
+       if ( service_type == WFD_OEM_SERVICE_BONJOUR)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_DEL "bonjour %s", data);
+       else if (service_type == WFD_OEM_SERVICE_UPNP)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_DEL "upnp %s", data);
+       else if (service_type ==WFD_OEM_SERVICE_VENDORSPEC)
+               snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERVICE_DEL "vendor %s", data);
+       else{
+               WDP_LOGE( "Invalid parameter");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       res = _ws_send_cmd(sock->ctrl_sock, cmd, (char*) reply, sizeof(reply));
+       if (res < 0) {
+               WDP_LOGE("Failed to send command to wpa_supplicant");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (strstr(reply, "FAIL")) {
+               WDP_LOGE("Failed to delete service");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+       WDP_LOGD("Succeeded to delete service");
+
+       __WDP_LOG_FUNC_EXIT__;
+       return 0;
+}
+
+static int _ws_query_generation(unsigned char* MAC, wfd_oem_service_e type, char *data, char *buff)
+{
+       __WDP_LOG_FUNC_ENTER__;
+       int res=0;
+       int tlv_len=0;
+       char *query=NULL;
+
+       switch(type){
+       case WFD_OEM_SERVICE_ALL:
+               query=strndup(SERVICE_TYPE_ALL,8);
+       break;
+       case WFD_OEM_SERVICE_BONJOUR:
+               query=strndup(SERVICE_TYPE_BONJOUR,8);
+       break;
+       case WFD_OEM_SERVICE_UPNP:
+               query=strndup(SERVICE_TYPE_UPNP,8);
+       break;
+       case WFD_OEM_SERVICE_VENDORSPEC:
+               query=strndup(SERVICE_TYPE_VENDOR_SPECIFIC,8);
+       break;
+       default:
+               WDP_LOGE( "Invalid parameter");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       break;
+       }
+
+       if(data && (tlv_len = strlen(data)))
+       {
+               if(type == WFD_OEM_SERVICE_UPNP)
+               {
+                       snprintf(buff, 256, WS_CMD_P2P_SERV_DISC_REQ MACSTR " upnp %s", MAC2STR(MAC), data);
+               }else{
+
+                       if(type == WFD_OEM_SERVICE_BONJOUR)
+                               tlv_len = tlv_len/2 + 2;
+
+                       query[0] = '0' + (char)(tlv_len/16);
+                       if(tlv_len%16 < 10)
+                               query[1] = '0' + (char)(tlv_len%16);
+                       else
+                               query[1] = 'a' + (char)(tlv_len%16) - 10;
+                       snprintf(buff, 256, WS_CMD_P2P_SERV_DISC_REQ MACSTR " %s%s", MAC2STR(MAC), query, data);
+               }
+       }else{
+               snprintf(buff, 256, WS_CMD_P2P_SERV_DISC_REQ MACSTR " %s", MAC2STR(MAC), query);
+       }
+       if(query != NULL)
+               free(query);
+       __WDP_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int ws_serv_disc_req(unsigned char* MAC, wfd_oem_service_e type, char *data)
+{
+       __WDP_LOG_FUNC_ENTER__;
+       ws_sock_data_s *sock = g_pd->common;
+       char cmd[256] = {0, };
+       char reply[1024]={0,};
+       int res;
+
+       if (!sock) {
+               WDP_LOGE("Socket is NULL");
+               return -1;
+       }
+
+       res = _ws_query_generation(MAC, type, data, cmd);
+       if (res < 0) {
+               WDP_LOGE("Failed to generate query");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       res = _ws_send_cmd(sock->ctrl_sock, cmd, (char*) reply, sizeof(reply));
+       if (res < 0) {
+               WDP_LOGE("Failed to send command to wpa_supplicant");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (strstr(reply, "FAIL")) {
+               WDP_LOGE("Failed to request service discovery");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       res = strtol(reply, NULL, 16);
+       WDP_LOGD("Succeeded to request service discovery(%d)", res);
+       __WDP_LOG_FUNC_EXIT__;
+       return res;
+
+}
+
+int ws_serv_disc_cancel(int identifier)
+{
+       __WDP_LOG_FUNC_ENTER__;
+       ws_sock_data_s *sock = g_pd->common;
+       char cmd[80] = {0, };
+       char reply[1024]={0,};
+       int res;
+
+       if (!sock) {
+               WDP_LOGE("Socket is NULL");
+               return -1;
+       }
+
+       snprintf(cmd, sizeof(cmd), WS_CMD_P2P_SERV_DISC_CANCEL " %x", identifier);
+
+       res = _ws_send_cmd(sock->ctrl_sock, cmd, (char*) reply, sizeof(reply));
+       if (res < 0) {
+               WDP_LOGE("Failed to send command to wpa_supplicant");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       if (strstr(reply, "FAIL")) {
+               WDP_LOGE("Failed to cancel service discovery");
+               __WDP_LOG_FUNC_EXIT__;
+               return -1;
+       }
+       WDP_LOGD("Succeeded to cancel service discovery");
+
+       __WDP_LOG_FUNC_EXIT__;
+       return 0;
+
+}
+
 int ws_get_persistent_groups(wfd_oem_persistent_group_s **groups, int *group_count)
 {
        __WDP_LOG_FUNC_ENTER__;
index f7603d8..4205142 100644 (file)
 #define WS_NETFLAG_LEN 32
 #define WS_MAX_PERSISTENT_COUNT 20
 
+#define SERVICE_TYPE_ALL "02000001"
+#define SERVICE_TYPE_BONJOUR "02000102"
+#define SERVICE_TYPE_UPNP "02000203"
+#define SERVICE_TYPE_VENDOR_SPECIFIC "0200ff04"
+#define CMD_LENGTH 80
+
 /* Config Method bitmap */
 #define WS_CONFIG_METHOD_DISPLAY 0x0008
 #define WS_CONFIG_METHOD_PUSHBUTTON 0x0080
 #define WS_STR_PERSISTENT " persistent"
 #define WS_STR_FREQ_2G " freq=2"
 
+#define WS_CMD_P2P_SERVICE_ADD "P2P_SERVICE_ADD "
+#define WS_CMD_P2P_SERVICE_DEL "P2P_SERVICE_DEL "
+#define WS_CMD_P2P_SERV_DISC_REQ "P2P_SERV_DISC_REQ "
+#define WS_CMD_P2P_SERV_DISC_CANCEL "P2P_SERV_DISC_CANCEL_REQ "
+
 typedef enum {
        WS_IFTYPE_NONE,
        WS_IFTYPE_STATION,
@@ -183,6 +194,8 @@ typedef enum {
        WS_EVENT_GROUP_STARTED,
        WS_EVENT_GROUP_REMOVED,
 
+       WS_EVENT_SERV_DISC_RESP,
+
        WS_EVENT_TERMINATING,
 
        WS_EVENT_LIMIT,
@@ -484,6 +497,11 @@ int ws_get_persistent_groups(wfd_oem_persistent_group_s **groups, int *group_cou
 int ws_remove_persistent_group(char *ssid, unsigned char *bssid);
 int ws_set_persistent_reconnect(unsigned char *bssid, int reconnect);
 
+int ws_service_add(wfd_oem_service_e type,char *data);
+int ws_service_del(wfd_oem_service_e type,char *data);
+int ws_serv_disc_req(unsigned char* MAC, wfd_oem_service_e type,char *data);
+int ws_serv_disc_cancel(int identifier);
+
 
 
 #endif /* __WFD_PLUGIN_WPASUPPLICANT_H__ */
index 4f36586..3068867 100644 (file)
@@ -175,7 +175,14 @@ char *wfd_server_print_cmd(wifi_direct_cmd_e cmd)
                return "WIFI_DIRECT_CMD_SET_DEVICE_NAME";
        case WIFI_DIRECT_CMD_SET_OEM_LOGLEVEL:
                return "WIFI_DIRECT_CMD_SET_OEM_LOGLEVEL";
-
+       case WIFI_DIRECT_CMD_SERVICE_ADD:
+               return "WIFI_DIRECT_CMD_SERVICE_ADD";
+       case WIFI_DIRECT_CMD_SERVICE_DEL:
+               return "WIFI_DIRECT_CMD_SERVICE_DEL";
+       case WIFI_DIRECT_CMD_SERV_DISC_REQ:
+               return "WIFI_DIRECT_CMD_SERV_DISC_REQ";
+       case WIFI_DIRECT_CMD_SERV_DISC_CANCEL:
+               return "WIFI_DIRECT_CMD_SERV_DISC_CANCEL";
        default:
                return "WIFI_DIRECT_CMD_INVALID";
 
@@ -787,6 +794,8 @@ static gboolean wfd_client_process_request(GIOChannel *source,
 
                wfd_destroy_group(manager, GROUP_IFNAME);
                wfd_destroy_session(manager);
+               wfd_manager_init_service(manager->local);
+               wfd_manager_init_query(manager);
                wfd_peer_clear_all(manager);
                WDS_LOGD("peer count[%d], peers[%d]", manager->peer_count, manager->peers);
                wfd_local_reset_data(manager);
@@ -1461,6 +1470,86 @@ static gboolean wfd_client_process_request(GIOChannel *source,
        case WIFI_DIRECT_CMD_GENERATE_WPS_PIN:  // manager
                // TODO: implement in plugin
                break;
+       case WIFI_DIRECT_CMD_SERVICE_ADD:
+               {
+                       char *buff = NULL;
+
+                       buff = (char *)calloc(sizeof(char), req.cmd_data_len);
+                       res = _wfd_read_from_client(sock, buff, req.cmd_data_len);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to get service data");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                               free(buff);
+                               break;
+                       }
+
+                       res = wfd_manager_service_add(manager, req.data.int1, buff);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to add service");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                       }
+
+                       free(buff);
+               }
+               break;
+       case WIFI_DIRECT_CMD_SERVICE_DEL:
+               {
+                       char *buff = NULL;
+
+                       buff = (char *)calloc(sizeof(char),req.cmd_data_len);
+                       res = _wfd_read_from_client(sock, buff, req.cmd_data_len);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to get service data");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                               free(buff);
+                               break;
+                       }
+
+                       res = wfd_manager_service_del(manager, req.data.int1, buff);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to delete service");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                       }
+
+                       free(buff);
+               }
+               break;
+       case WIFI_DIRECT_CMD_SERV_DISC_REQ:
+               {
+                       char *buff = NULL;
+
+                       if(req.cmd_data_len != 0)
+                       {
+                               buff = (char*)calloc(sizeof(char),req.cmd_data_len);
+                               res = _wfd_read_from_client(sock, buff, req.cmd_data_len);
+                               if (res < 0) {
+                                       WDS_LOGE("Failed to get service data");
+                                       rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                                       free(buff);
+                                       break;
+                               }
+                       }
+
+                       res = wfd_manager_serv_disc_req(manager,req.data.mac_addr, req.data.int1, buff);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to requset service discovery");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                       }
+                       rsp.param1 = res;
+
+                       if(buff != NULL)
+                               free(buff);
+               }
+               break;
+       case WIFI_DIRECT_CMD_SERV_DISC_CANCEL:
+               {
+                       res = wfd_manager_serv_disc_cancel(manager, req.data.int1);
+                       if (res < 0) {
+                               WDS_LOGE("Failed to delete service cancel");
+                               rsp.result = WIFI_DIRECT_ERROR_OPERATION_FAILED;
+                       }
+               }
+               break;
        default:
                WDS_LOGE("Unknown command[%d]", req.cmd);
                rsp.result = WIFI_DIRECT_ERROR_NOT_PERMITTED;
index 592dbbd..d0c9c96 100644 (file)
@@ -177,6 +177,201 @@ static int _wfd_event_update_peer(wfd_manager_s *manager, wfd_oem_dev_data_s *da
        return 0;
 }
 
+static int hex2num(const char c)
+{
+       if (c >= '0' && c <= '9')
+               return c - '0';
+       if (c >= 'a' && c <= 'f')
+               return c - 'a' + 10;
+       if (c >= 'A' && c <= 'F')
+               return c - 'A' + 10;
+       return -1;
+}
+
+static int hex2byte(const char *hex)
+{
+       int a, b;
+       a = hex2num(*hex++);
+       if (a < 0)
+               return -1;
+       b = hex2num(*hex++);
+       if (b < 0)
+               return -1;
+       return (a << 4) | b;
+}
+
+int hexstr2bin(const char *hex, int len, char *buf)
+{
+       int i;
+       int a;
+       const char *ipos = hex;
+       char *opos = buf;
+
+       for (i = 0; i < len; i++) {
+               a = hex2byte(ipos);
+               if (a < 0)
+                       return -1;
+               *opos++ = a;
+               ipos += 2;
+       }
+       return 0;
+}
+
+static int _wfd_get_stlv_len(const char* value)
+{
+       int a, b;
+       a = hex2byte(value +2);
+       b = hex2byte(value);
+
+       if( a >= 0 && b >= 0)
+               return ( a << 8) | b;
+       else
+               return -1;
+}
+
+static int _wfd_service_add(wfd_device_s *device, wifi_direct_service_type_e type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_service_s *service = NULL;
+       GList *temp = NULL;
+       int res = 0;
+
+       temp = g_list_first(device->services);
+       while (temp) {
+               service = temp->data;
+
+               if(type == service->service_type &&
+                               !strcmp(data, service->service_string))
+               {
+                       WDS_LOGD("Service found");
+                       break;
+               }
+               temp = g_list_next(temp);
+               service = NULL;
+       }
+
+       if (service) {
+               WDS_LOGE("service already exist");
+               free(data);
+               __WDS_LOG_FUNC_EXIT__;
+               return res;
+       }
+       service = (wfd_service_s*) calloc(1, sizeof(wfd_service_s));
+       service->service_string = data;
+       service->service_str_length = strlen(data);
+       service->service_type = type;
+       device->services = g_list_prepend(device->services, service);
+
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+static int _wfd_update_service(wfd_device_s *peer, char * data, wifi_direct_service_type_e  type, int length)
+{
+       wfd_service_s * service;
+       int res = 0;
+       char *temp = NULL;
+       char *ptr = NULL;
+
+       if (!peer || !data) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+       switch (type)
+       {
+               case WIFI_DIRECT_SERVICE_BONJOUR:
+               {
+                       temp = strndup(data, length*2);
+                       res = _wfd_service_add(peer, type, temp);
+                       break;
+               }
+               case WIFI_DIRECT_SERVICE_UPNP:
+               {
+                       temp = calloc(1, length);
+                       hexstr2bin(data +2, length - 1, temp);
+                       temp[length - 1] = '\0';
+
+                       ptr = strtok(temp, ",");
+
+                       while(ptr != NULL)
+                       {
+                               res = _wfd_service_add(peer, type, strndup(ptr, strlen(ptr)));
+                               ptr = strtok(NULL, ",");
+                       }
+
+                       if(temp)
+                               free(temp);
+                       break;
+               }
+               case WIFI_DIRECT_SERVICE_VENDORSPEC:
+               {
+                       temp = calloc(1, length + 1);
+                       hexstr2bin(data, length, temp);
+                       temp[length] = '\0';
+
+                       res = _wfd_service_add(peer, type, temp);
+                       break;
+               }
+               default:
+               {
+                       res = -1;
+                       break;
+               }
+       }
+       return res;
+}
+
+static int _wfd_event_update_service(wfd_manager_s *manager, wfd_device_s *peer, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       int res = 0;
+       int s_len = 0;
+       char *pos = data;
+       char *end = NULL;
+       wifi_direct_service_type_e  service_tlv_type;
+       int status = 0;
+
+       if (!peer || !data) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+       end = data + strlen(data);
+
+       while(pos <= end -10){// This is raw data that is not passed any exception handling ex> length, value, ...
+
+               s_len = _wfd_get_stlv_len(pos);
+               pos += 4;
+               if (pos + s_len*2 > end || s_len < 3) {
+                       WDS_LOGD("Unexpected Response Data or length: %d", s_len);
+                       break;
+               }
+
+               service_tlv_type = hex2byte(pos);
+               if (service_tlv_type < 0) {
+                       WDS_LOGD("Unexpected Response service type: %d", service_tlv_type);
+                       pos+=(s_len)*2;
+                       continue;
+               }else if (service_tlv_type == 255)
+                       service_tlv_type = WIFI_DIRECT_SERVICE_VENDORSPEC;
+
+               pos += 4;
+               status = hex2byte(pos);
+               pos += 2;
+
+               if (status == 0)
+               {
+                       res = _wfd_update_service(peer, pos, service_tlv_type, s_len -3);
+                       if (res != 0) {
+                               WDS_LOGE("Invalid type");
+                       }
+               } else
+                       WDS_LOGD("Service Reaponse TLV status is not vaild status: %d", status);
+               pos+=(s_len-3)*2;
+       }
+       __WDS_LOG_FUNC_EXIT__;
+       return 0;
+}
+
 int wfd_process_event(void *user_data, void *data)
 {
        __WDS_LOG_FUNC_ENTER__;
@@ -563,6 +758,25 @@ int wfd_process_event(void *user_data, void *data)
                manager->scan_mode = WFD_SCAN_MODE_ACTIVE;
        }
        break;
+       case WFD_OEM_EVENT_SERV_DISC_RESP:
+       {
+               wfd_device_s *peer = NULL;
+               if(event->edata_type != WFD_OEM_EDATA_TYPE_SERVICE)
+               {
+                       WDS_LOGD("There is no service to register");
+                       break;
+               }
+               peer = wfd_peer_find_by_dev_addr(manager, event->dev_addr);
+               if (!peer) {
+                       WDS_LOGD("serv_disc_resp from unknown peer. Discard it");
+                       break;
+               }
+               res = _wfd_event_update_service(manager, peer, (char*) event->edata);
+               if (res < 0) {
+                       WDS_LOGE("Failed to update peer service data");
+               }
+       }
+       break;
        default:
                WDS_LOGE("Unknown event [event ID: %d]", event->event_id);
        break;
index 3c2759c..2031f46 100644 (file)
@@ -197,7 +197,10 @@ int wfd_destroy_group(void *data, char *ifname)
                member = temp->data;
                WDS_LOGD("%dth member[%s] freed", count, member->dev_name);
                if (member)     // Temporary. Sometimes manager crashed
+               {
+                       wfd_manager_init_service(member);
                        free(member);
+               }
                temp = g_list_next(temp);
                count++;
        }
index 008e6af..969ca1a 100644 (file)
@@ -860,6 +860,38 @@ failed:
        return res;
 }
 
+static int _wfd_manager_service_copy(char* dst, GList* services, int dst_length)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_service_s *service = NULL;
+       GList *temp = NULL;
+       char* ptr = dst;
+       int length = dst_length;
+       int res = 0;
+
+       temp = g_list_first(services);
+       while (temp) {
+
+               service = temp->data;
+               if(length < service->service_str_length + 4)
+               {
+                       WDS_LOGD("There is not enough space to reserve service list");
+                       break;
+               }
+
+               memcpy(ptr, service->service_string, service->service_str_length);
+               ptr+=service->service_str_length;
+               strncpy(ptr," ,\n",3);
+               ptr+=3;
+               length = length - service->service_str_length - 3;
+
+               temp = g_list_next(temp);
+       }
+       *ptr='\0';
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
 int wfd_manager_get_peers(wfd_manager_s *manager, wfd_discovery_entry_s **peers_data)
 {
        __WDS_LOG_FUNC_ENTER__;
@@ -907,6 +939,7 @@ int wfd_manager_get_peers(wfd_manager_s *manager, wfd_discovery_entry_s **peers_
                                temp = g_list_next(temp);
                                manager->peers = g_list_remove(manager->peers, peer);
                                manager->peer_count--;
+                               wfd_manager_init_service(peer);
                                free(peer);
                                peer = NULL;
                                continue;
@@ -918,7 +951,6 @@ int wfd_manager_get_peers(wfd_manager_s *manager, wfd_discovery_entry_s **peers_
                memcpy(peers[count].mac_address, peer->dev_addr, MACADDR_LEN);
                memcpy(peers[count].intf_address, peer->intf_addr, MACADDR_LEN);
                peers[count].channel = peer->channel;
-               peers[count].services = 0;
                peers[count].is_group_owner = peer->dev_role == WFD_DEV_ROLE_GO;
                peers[count].is_persistent_go = peer->group_flags & WFD_OEM_GROUP_FLAG_PERSISTENT_GROUP;
                peers[count].is_connected = peer->dev_role == WFD_DEV_ROLE_GC;
@@ -926,6 +958,7 @@ int wfd_manager_get_peers(wfd_manager_s *manager, wfd_discovery_entry_s **peers_
                peers[count].wps_cfg_methods = peer->config_methods;
                peers[count].category = peer->pri_dev_type;
                peers[count].subcategory = peer->sec_dev_type;
+               _wfd_manager_service_copy(peers[count].services, peer->services, 1024);
 
                count++;
                WDS_LOGD("%dth peer [%s]", count, peer->dev_name);
@@ -989,7 +1022,7 @@ int wfd_manager_get_connected_peers(wfd_manager_s *manager, wfd_connected_peer_i
                        peers[count].subcategory = peer->sec_dev_type;
                        peers[count].channel = peer->channel;
                        peers[count].is_p2p = 1;
-                       peers[count].services = 0;
+                       _wfd_manager_service_copy(peers[count].services, peer->services, 1024);
                        WDS_LOGD("%dth member converted[%s]", count, peers[count].device_name);
                        count++;
                }
@@ -1063,6 +1096,275 @@ int wfd_manager_get_goup_ifname(char **ifname)
        return 0;
 }
 
+static wfd_service_s *_wfd_service_find(wfd_device_s *device, wifi_direct_service_type_e type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_service_s *result = NULL;
+       GList *temp = NULL;
+       int cmp_result = 0;
+
+       temp = g_list_first(device->services);
+       while (temp) {
+               result = temp->data;
+
+               if(result->service_type == WIFI_DIRECT_SERVICE_BONJOUR)
+                       cmp_result = strncmp(data, result->service_string, strlen(data));
+               else
+                       cmp_result = strcmp(data, result->service_string);
+
+               if(type == result->service_type && !cmp_result)
+               {
+                       WDS_LOGD("Service found");
+                       break;
+               }
+               temp = g_list_next(temp);
+               result = NULL;
+       }
+       __WDS_LOG_FUNC_EXIT__;
+       return result;
+}
+
+static wfd_query_s *_wfd_query_find(wfd_manager_s *manager, unsigned char* mac_addr, wifi_direct_service_type_e  type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_query_s *query = NULL;
+       GList *temp = NULL;
+       int data_len = 0;
+
+       if(data != NULL)
+               data_len = strlen(data);
+
+       temp = g_list_first(manager->query_handles);
+       while (temp) {
+               query = temp->data;
+
+               if(!memcmp(query->mac_addr, mac_addr, MACADDR_LEN) &&
+                               type == query->service_type)
+               {
+                       if(data_len)
+                       {
+                               if(!strcmp(data, query->query_string))
+                               {
+                                       WDS_LOGD("Query found");
+                                       break;
+                               }
+                       }else{
+                               WDS_LOGD("Query found");
+                               break;
+                       }
+               }
+               temp = g_list_next(temp);
+               query = NULL;
+       }
+       __WDS_LOG_FUNC_EXIT__;
+       return query;
+}
+
+int wfd_manager_service_add(wfd_manager_s *manager, wifi_direct_service_type_e  type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_device_s * device = manager->local;
+       wfd_service_s * service;
+       int res = 0;
+
+       if (!device || !data) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       service = _wfd_service_find(device, type, data);
+       if (service) {
+               WDS_LOGE("service already exist");
+               service->ref_counter++;
+               __WDS_LOG_FUNC_EXIT__;
+               return 0;
+       }
+
+       res = wfd_oem_service_add(manager->oem_ops, type, data);
+       if (res < 0) {
+               WDS_LOGE("Failed to add service");
+               __WDS_LOG_FUNC_EXIT__;
+               return -1;
+       }
+
+       service = (wfd_service_s*) calloc(1, sizeof(wfd_service_s));
+       service->service_string = strndup(data, strlen(data));
+       service->service_str_length = strlen(data);
+       service->service_type = type;
+       service->ref_counter=1;
+       device->services = g_list_prepend(device->services, service);
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int wfd_manager_service_del(wfd_manager_s *manager, wifi_direct_service_type_e  type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_device_s * device = manager->local;
+       wfd_service_s* service;
+       int res = 0;
+
+       if (!device || !data) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+       service = _wfd_service_find(device, type, data);
+       if (!service) {
+               WDS_LOGE("Failed to find service");
+               res = -1;
+
+       }else if(service->ref_counter ==1)
+       {
+               res = wfd_oem_service_del(manager->oem_ops, type, data);
+               if (res < 0) {
+                       WDS_LOGE("Failed to delete service");
+                       __WDS_LOG_FUNC_EXIT__;
+                       return -1;
+               }
+               device->services = g_list_remove(device->services, service);
+               free(service->service_string);
+               free(service);
+
+       }else{
+               service->ref_counter--;
+       }
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int wfd_manager_serv_disc_req(wfd_manager_s *manager, unsigned char* mad_addr, wifi_direct_service_type_e  type, char *data)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_query_s* query;
+       int res = 0;
+
+       if (!manager) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+       query = _wfd_query_find(manager, mad_addr, type, data);
+       if (query) {
+               WDS_LOGE("Query already exist");
+               query->ref_counter++;
+               __WDS_LOG_FUNC_EXIT__;
+               return 0;
+       }
+
+       res = wfd_oem_serv_disc_req(manager->oem_ops, mad_addr, type, data);
+       if (res < 0) {
+               WDS_LOGE("Failed to request service discovery");
+               return res;
+       }
+       query = (wfd_query_s*) calloc(1, sizeof(wfd_query_s));
+       query->handle = res;
+       query->ref_counter=1;
+       memcpy(query->mac_addr, mad_addr, MACADDR_LEN);
+
+       if(data && strlen(data))
+               query->query_string = strndup(data, strlen(data));
+       query->service_type = type;
+       manager->query_handles = g_list_prepend(manager->query_handles, query);
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int wfd_manager_serv_disc_cancel(wfd_manager_s *manager,  int handle)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_query_s *query = NULL;
+       GList *temp = NULL;
+       int res = 0;
+
+       temp = g_list_first(manager->query_handles);
+       while (temp) {
+               query = temp->data;
+
+               //TODO : compare the services
+               if(query->handle == handle)
+               {
+                       WDS_LOGD("Query handle found");
+                       break;
+               }
+               temp = g_list_next(temp);
+               query = NULL;
+       }
+
+       if(query == NULL) {
+               WDS_LOGE("handle does not exist");
+               return -1;
+       }else if(query->ref_counter ==1) {
+
+               res = wfd_oem_serv_disc_cancel(manager->oem_ops, query->handle);
+               if (res < 0) {
+                       WDS_LOGE("Failed to cancel service discovery or already canceled");
+               }
+               manager->query_handles = g_list_remove(manager->query_handles, query);
+               if(query->query_string)
+                       free(query->query_string);
+               free(query);
+       }else
+               query->ref_counter--;
+
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int wfd_manager_init_service(wfd_device_s *device)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_service_s* service = NULL;
+       GList *temp = NULL;
+       int res = 0;
+
+       if (!device) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       if(device->services)
+       {
+               temp = g_list_first(device->services);
+               while (temp) {
+                       service = temp->data;
+                       free(service->service_string);
+                       free(service);
+                       temp = g_list_next(temp);
+               }
+               g_list_free(device->services);
+       }
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
+int wfd_manager_init_query(wfd_manager_s *manager)
+{
+       __WDS_LOG_FUNC_ENTER__;
+       wfd_query_s *query = NULL;
+       GList *temp = NULL;
+       int res = 0;
+
+       if (!manager) {
+               WDS_LOGE("Invalid parameter");
+               return -1;
+       }
+
+       if(manager->query_handles)
+       {
+               temp = g_list_first(manager->query_handles);
+               while (temp) {
+                       query = temp->data;
+
+                       free(query->query_string);
+                       free(query);
+                       temp = g_list_next(temp);
+               }
+               g_list_free(manager->query_handles);
+       }
+
+       __WDS_LOG_FUNC_EXIT__;
+       return res;
+}
+
 static wfd_manager_s *wfd_manager_init()
 {
        __WDS_LOG_FUNC_ENTER__;
index 0cd8554..7d73aa9 100644 (file)
@@ -92,6 +92,7 @@ int wfd_remove_peer(void *data, unsigned char *dev_addr)
        manager->peers = g_list_remove(manager->peers, peer);
        manager->peer_count--;
 
+       wfd_manager_init_service(peer);
        free(peer);
        __WDS_LOG_FUNC_EXIT__;
        return 0;
@@ -179,6 +180,7 @@ int wfd_peer_clear_all(void *data)
        temp = g_list_first(manager->peers);
        while(temp) {
                peer = (wfd_device_s*) temp->data;
+               wfd_manager_init_service(peer);
                free(peer);
                temp = g_list_next(temp);
                manager->peer_count--;