| /* |
| * Copyright (c) 2014 The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /* |
| * This file was originally distributed by Qualcomm Atheros, Inc. |
| * under proprietary terms before Copyright ownership was assigned |
| * to the Linux Foundation. |
| */ |
| |
| /** |
| * wlan_hdd_mdns_offload.c - WLAN Host Device Driver implementation |
| */ |
| |
| |
| #include "wlan_hdd_main.h" |
| #include "wlan_hdd_assoc.h" |
| #include "wlan_hdd_trace.h" |
| #include "vos_types.h" |
| #include "vos_trace.h" |
| #include "sme_Api.h" |
| #include "wlan_hdd_mdns_offload.h" |
| |
| #ifdef MDNS_OFFLOAD |
| |
| #define MDNS_HEADER_LEN 12 |
| #define MDNS_FQDN_TYPE_GENERAL 0 |
| #define MDNS_FQDN_TYPE_UNIQUE 1 |
| #define MAX_NUM_FIELD_DOMAINNAME 6 |
| #define MAX_LEN_DOMAINNAME_FIELD 64 |
| #define MAX_MDNS_RESP_TYPE 6 |
| #define MDNS_TYPE_A 1 |
| #define MDNS_TYPE_TXT 16 |
| #define MDNS_TYPE_PTR 12 |
| #define MDNS_TYPE_PTR_DNAME 13 |
| #define MDNS_TYPE_SRV 33 |
| #define MDNS_TYPE_SRV_TARGET 34 |
| #define MDNS_CLASS 1 |
| #define MDNS_TTL 5 |
| |
| /* Offload struct */ |
| struct hdd_mdns_resp_info { |
| uint8_t num_entries; |
| uint8_t *data; |
| uint16_t *offset; |
| }; |
| |
| struct hdd_mdns_resp_matched { |
| uint8_t num_matched; |
| uint8_t type; |
| }; |
| |
| /** |
| * wlan_hdd_mdns_process_response_dname() - Process mDNS domain name |
| * @response: Pointer to a struct hdd_mdns_resp_info |
| * @resp_info: Pointer to a struct tSirMDNSResponseInfo |
| * |
| * This function will pack the whole domain name without compression. It will |
| * add the leading len for each field and add zero length octet to terminate |
| * the domain name. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_process_response_dname( |
| struct hdd_mdns_resp_info *response, |
| tpSirMDNSResponseInfo resp_info) |
| { |
| uint8_t num; |
| uint16_t idx; |
| uint8_t len = 0; |
| |
| if ((response == NULL) || (response->data == NULL) || |
| (response->offset == NULL)) { |
| hddLog(LOGE, FL("Either data or offset in response is NULL!")); |
| return FALSE; |
| } |
| |
| if ((resp_info == NULL) || |
| (resp_info->resp_len >= MAX_MDNS_RESP_LEN)) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| |
| for (num = 0; num < response->num_entries; num++) { |
| response->offset[num] = |
| resp_info->resp_len + MDNS_HEADER_LEN; |
| idx = num * MAX_LEN_DOMAINNAME_FIELD; |
| len = strlen((char *)&response->data[idx]); |
| if ((resp_info->resp_len + len + 1) >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), |
| MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| resp_info->resp_data[resp_info->resp_len] = len; |
| resp_info->resp_len++; |
| vos_mem_copy(&resp_info->resp_data[resp_info->resp_len], |
| &response->data[idx], len); |
| resp_info->resp_len += len; |
| } |
| |
| /* The domain name terminates with the zero length octet */ |
| if (num == response->num_entries) { |
| if (resp_info->resp_len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), |
| MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| resp_info->resp_data[resp_info->resp_len] = 0; |
| resp_info->resp_len++; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_format_response_u16() - Form uint16_t response data |
| * @value: The uint16_t value is formed to the struct tSirMDNSResponseInfo |
| * @resp_info: Pointer to a struct tSirMDNSResponseInfo |
| * |
| * Return: None |
| */ |
| static void wlan_hdd_mdns_format_response_u16(uint16_t value, |
| tpSirMDNSResponseInfo resp_info) |
| { |
| uint8_t val_u8; |
| |
| if ((resp_info == NULL) || (resp_info->resp_data == NULL)) |
| return; |
| val_u8 = (value & 0xff00) >> 8; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| val_u8 = value & 0xff; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| } |
| |
| /** |
| * wlan_hdd_mdns_format_response_u32() - Form uint32_t response data |
| * @value: The uint32_t value is formed to the struct tSirMDNSResponseInfo |
| * @resp_info: Pointer to a struct tSirMDNSResponseInfo |
| * |
| * Return: None |
| */ |
| static void wlan_hdd_mdns_format_response_u32(uint32_t value, |
| tpSirMDNSResponseInfo resp_info) |
| { |
| uint8_t val_u8; |
| |
| if ((resp_info == NULL) || (resp_info->resp_data == NULL)) |
| return; |
| val_u8 = (value & 0xff000000) >> 24; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| val_u8 = (value & 0xff0000) >> 16; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| val_u8 = (value & 0xff00) >> 8; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| val_u8 = value & 0xff; |
| resp_info->resp_data[resp_info->resp_len++] = val_u8; |
| } |
| |
| /** |
| * wlan_hdd_mdns_process_response_misc() - Process misc info in mDNS response |
| * @resp_type: Response type for mDNS |
| * @resp_info: Pointer to a struct tSirMDNSResponseInfo |
| * |
| * This function will pack the response type, class and TTL (Time To Live). |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_process_response_misc(uint16_t resp_type, |
| tpSirMDNSResponseInfo resp_info) |
| { |
| uint16_t len; |
| |
| if (resp_info == NULL) { |
| hddLog(LOGE, FL("resp_info is NULL!")); |
| return FALSE; |
| } |
| |
| len = resp_info->resp_len + (3 * sizeof(uint16_t)); |
| if (len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| |
| /* Fill Type, Class, TTL */ |
| wlan_hdd_mdns_format_response_u16(resp_type, resp_info); |
| wlan_hdd_mdns_format_response_u16(MDNS_CLASS, resp_info); |
| wlan_hdd_mdns_format_response_u32(MDNS_TTL, resp_info); |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_compress_data() - Compress the domain name in mDNS response |
| * @resp_info: Pointer to a struct tSirMDNSResponseInfo |
| * @response_dst: The response which domain name is compressed. |
| * @response_src: The response which domain name is matched with response_dst. |
| * Its offset is used for data compression. |
| * @num_matched: The number of matched entries between response_dst and |
| * response_src |
| * |
| * This function will form the different fields of domain name in response_dst |
| * if any. Then use the offset of the matched domain name in response_src to |
| * compress the matched domain name. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_compress_data(tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *response_dst, |
| struct hdd_mdns_resp_info *response_src, |
| uint8_t num_matched) |
| { |
| uint8_t num, num_diff; |
| uint16_t value, idx; |
| uint8_t len = 0; |
| |
| if ((response_src == NULL) || (response_dst == NULL) || |
| (resp_info == NULL)) { |
| hddLog(LOGE, FL("response info is NULL!")); |
| return FALSE; |
| } |
| |
| if (response_dst->num_entries < num_matched) { |
| hddLog(LOGE, FL("num_entries is less than num_matched!")); |
| return FALSE; |
| } |
| |
| if (resp_info->resp_len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| |
| num_diff = response_dst->num_entries - num_matched; |
| if ((num_diff > 0) && (response_dst->data == NULL)) { |
| hddLog(LOGE, FL("response_dst->data is NULL!")); |
| return FALSE; |
| } |
| |
| /* |
| * Handle the unmatched string at the beginning |
| * Store the length of octets and the octets |
| */ |
| for (num = 0; num < num_diff; num++) { |
| response_dst->offset[num] = |
| resp_info->resp_len + MDNS_HEADER_LEN; |
| idx = num * MAX_LEN_DOMAINNAME_FIELD; |
| len = strlen((char *)&response_dst->data[idx]); |
| if ((resp_info->resp_len + len + 1) >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), |
| MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| resp_info->resp_data[resp_info->resp_len] = len; |
| resp_info->resp_len++; |
| vos_mem_copy(&resp_info->resp_data[resp_info->resp_len], |
| &response_dst->data[idx], len); |
| resp_info->resp_len += len; |
| } |
| /* |
| * Handle the matched string from the end |
| * Just keep the offset and mask the leading two bit |
| */ |
| if (response_src->num_entries >= num_matched) { |
| num_diff = response_src->num_entries - num_matched; |
| value = response_src->offset[num_diff]; |
| if (value > 0) { |
| value |= 0xc000; |
| if ((resp_info->resp_len + sizeof(uint16_t)) >= |
| MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), |
| MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| wlan_hdd_mdns_format_response_u16(value, resp_info); |
| return TRUE; |
| } |
| } |
| return FALSE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_reset_response() - Reset the response info |
| * @response: The response which info is reset. |
| * |
| * Return: None |
| */ |
| static void wlan_hdd_mdns_reset_response(struct hdd_mdns_resp_info *response) |
| { |
| if (response == NULL) |
| return; |
| response->num_entries = 0; |
| response->data = NULL; |
| response->offset = NULL; |
| } |
| |
| /** |
| * wlan_hdd_mdns_init_response() - Initialize the response info |
| * @response: The response which info is initiatized. |
| * @resp_dname: The domain name string which might be tokenized. |
| * |
| * This function will allocate the memory for both response->data and |
| * response->offset. Besides, it will also tokenize the domain name to some |
| * entries and fill response->num_entries with the num of entries. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_init_response( |
| struct hdd_mdns_resp_info *response, |
| uint8_t *resp_dname, char separator) |
| { |
| uint16_t size; |
| |
| if ((resp_dname == NULL) || (response == NULL)) { |
| hddLog(LOGE, FL("resp_dname or response is NULL!")); |
| return FALSE; |
| } |
| |
| size = MAX_NUM_FIELD_DOMAINNAME * MAX_LEN_DOMAINNAME_FIELD; |
| response->data = vos_mem_malloc(size); |
| if (response->data) { |
| vos_mem_zero(response->data, size); |
| if (VOS_STATUS_SUCCESS != |
| hdd_string_to_string_array((char *)resp_dname, |
| response->data, |
| separator, |
| &response->num_entries, |
| MAX_NUM_FIELD_DOMAINNAME, |
| MAX_LEN_DOMAINNAME_FIELD)) { |
| hddLog(LOGE, FL("hdd_string_to_string_array fail!")); |
| goto err_init_resp; |
| } |
| |
| if ((response->num_entries > 0) && |
| (strlen((char *)&response->data[0]) > 0)) { |
| size = sizeof(uint16_t) * response->num_entries; |
| response->offset = vos_mem_malloc(size); |
| if (response->offset) { |
| vos_mem_zero(response->offset, size); |
| return TRUE; |
| } |
| } |
| } |
| |
| err_init_resp: |
| if (response->data) |
| vos_mem_free(response->data); |
| wlan_hdd_mdns_reset_response(response); |
| return FALSE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_find_entries_from_end() - Find the matched entries |
| * @response1: The response info is used to be compared. |
| * @response2: The response info is used to be compared. |
| * |
| * This function will find the matched entries from the end. |
| * |
| * Return: Return the number of the matched entries. |
| */ |
| static uint8_t wlan_hdd_mdns_find_entries_from_end( |
| struct hdd_mdns_resp_info *response1, |
| struct hdd_mdns_resp_info *response2) |
| { |
| uint8_t min, len1, i; |
| uint16_t num1, num2; |
| uint8_t num_matched = 0; |
| |
| min = VOS_MIN(response1->num_entries, response2->num_entries); |
| |
| for (i = 1; i <= min; i++) { |
| num1 = (response1->num_entries - i); |
| num1 *= MAX_LEN_DOMAINNAME_FIELD; |
| num2 = (response2->num_entries - i); |
| num2 *= MAX_LEN_DOMAINNAME_FIELD; |
| len1 = strlen((char *)&response1->data[num1]); |
| |
| if ((len1 == 0) || |
| (len1 != strlen((char *)&response2->data[num2]))) |
| break; |
| if (memcmp(&response1->data[num1], |
| &response2->data[num2], len1)) |
| break; |
| else |
| num_matched++; |
| } |
| |
| return num_matched; |
| } |
| |
| /** |
| * wlan_hdd_mdns_find_max() - Find the maximum number of the matched entries |
| * @matchedlist: Pointer to the array of struct hdd_mdns_resp_matched |
| * @numlist: The number of the elements in the array matchedlist. |
| * |
| * Find the max number of the matched entries among the array matchedlist. |
| * |
| * Return: None |
| */ |
| static void wlan_hdd_mdns_find_max(struct hdd_mdns_resp_matched *matchedlist, |
| uint8_t numlist) |
| { |
| int j; |
| struct hdd_mdns_resp_matched tmp; |
| |
| /* At least two values are used for sorting */ |
| if ((numlist < 2) || (matchedlist == NULL)) { |
| hddLog(LOGE, FL("At least two values are used for sorting!")); |
| return; |
| } |
| |
| for (j = 0; j < numlist-1; j++) { |
| if (matchedlist[j].num_matched > |
| matchedlist[j+1].num_matched) { |
| vos_mem_copy(&tmp, &matchedlist[j], |
| sizeof(struct hdd_mdns_resp_matched)); |
| vos_mem_copy(&matchedlist[j], &matchedlist[j+1], |
| sizeof(struct hdd_mdns_resp_matched)); |
| vos_mem_copy(&matchedlist[j+1], &tmp, |
| sizeof(struct hdd_mdns_resp_matched)); |
| } |
| } |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_a() - Pack Type A response |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * Type A response include QName, response type, class, TTL and Ipv4. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_a(hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint16_t value; |
| uint32_t len; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_a == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type A response */ |
| if (strlen((char *)ini_config->mdns_resp_type_a) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_a, |
| ini_config->mdns_resp_type_a, '.')) |
| return TRUE; |
| |
| /* Process response domain name */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_a, resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_A); |
| return FALSE; |
| } |
| |
| /* Process response Type, Class, TTL */ |
| if (!wlan_hdd_mdns_process_response_misc(MDNS_TYPE_A, resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS misc response (%d)!"), |
| MDNS_TYPE_A); |
| return FALSE; |
| } |
| |
| /* Process response RDLength, RData */ |
| len = sizeof(uint16_t) + sizeof(uint32_t); |
| len += resp_info->resp_len; |
| if (len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| value = sizeof(uint32_t); |
| wlan_hdd_mdns_format_response_u16(value, resp_info); |
| wlan_hdd_mdns_format_response_u32(ini_config->mdns_resp_type_a_ipv4, |
| resp_info); |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_txt() - Pack Type Txt response |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_txt: Pointer to the struct hdd_mdns_resp_info of Type txt |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * Type Txt response include QName, response type, class, TTL and text content. |
| * Also, it will find the matched QName from resptype_A and compress the data. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_txt(hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_txt, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint8_t num_matched; |
| uint8_t num; |
| uint16_t idx; |
| uint16_t value = 0; |
| uint32_t len; |
| uint32_t total_len; |
| bool status; |
| struct hdd_mdns_resp_info resptype_content; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_txt == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type Txt response */ |
| if (strlen((char *)ini_config->mdns_resp_type_txt) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_txt, |
| ini_config->mdns_resp_type_txt, '.')) |
| return TRUE; |
| |
| /* |
| * For data compression |
| * Check if any strings are matched with Type A response |
| */ |
| if (resptype_a && (resptype_a->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_txt, |
| resptype_a); |
| if (num_matched > 0) { |
| if (!wlan_hdd_mdns_compress_data(resp_info, |
| resptype_txt, resptype_a, num_matched)) { |
| hddLog(LOGE, FL("Fail to compress mDNS " |
| "response (%d)!"), MDNS_TYPE_TXT); |
| return FALSE; |
| } |
| } else { |
| /* |
| * num_matched is zero. Error! |
| * At least ".local" is needed. |
| */ |
| hddLog(LOGE, FL("No matched string! Fail to pack mDNS " |
| "response (%d)!"), MDNS_TYPE_TXT); |
| return FALSE; |
| } |
| } else { |
| /* no TypeA response, so show the whole data */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_txt, |
| resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_TXT); |
| return FALSE; |
| } |
| } |
| |
| /* Process response Type, Class, TTL */ |
| if (!wlan_hdd_mdns_process_response_misc(MDNS_TYPE_TXT, resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS misc response (%d)!"), |
| MDNS_TYPE_TXT); |
| return FALSE; |
| } |
| |
| /* |
| * Process response RDLength, RData. |
| * TypeTxt RData include len. |
| */ |
| status = wlan_hdd_mdns_init_response(&resptype_content, |
| ini_config->mdns_resp_type_txt_content, |
| '/'); |
| if (status == FALSE) { |
| hddLog(LOGE, FL("wlan_hdd_mdns_init_response FAIL")); |
| return FALSE; |
| } |
| |
| for (num = 0; num < resptype_content.num_entries; num++) { |
| idx = num * MAX_LEN_DOMAINNAME_FIELD; |
| value += strlen((char *)&resptype_content.data[idx]); |
| } |
| |
| /* content len is uint16_t */ |
| total_len = sizeof(uint16_t); |
| total_len += resp_info->resp_len + value + resptype_content.num_entries; |
| |
| if (total_len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| wlan_hdd_mdns_format_response_u16(value + resptype_content.num_entries, |
| resp_info); |
| |
| for (num = 0; num < resptype_content.num_entries; num++) { |
| idx = num * MAX_LEN_DOMAINNAME_FIELD; |
| len = strlen((char *)&resptype_content.data[idx]); |
| resp_info->resp_data[resp_info->resp_len] = len; |
| resp_info->resp_len++; |
| |
| vos_mem_copy(&resp_info->resp_data[resp_info->resp_len], |
| &resptype_content.data[idx], len); |
| |
| resp_info->resp_len += len; |
| hddLog(LOGE, FL("index = %d, len = %d, str = %s"), |
| num, len, &resptype_content.data[idx]); |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_ptr_dname() - Pack Type PTR domain name |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_ptr_dn: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * domain name |
| * @resptype_ptr: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * @resptype_txt: Pointer to the struct hdd_mdns_resp_info of Type Txt |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * The Type Ptr response include Type PTR domain name in its data field. |
| * Also, it will find the matched QName from the existing resptype_ptr, |
| * resptype_txt, resptype_a and then compress the data. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_ptr_dname( |
| hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_ptr_dn, |
| struct hdd_mdns_resp_info *resptype_ptr, |
| struct hdd_mdns_resp_info *resptype_txt, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint8_t num_matched, numlist, size; |
| struct hdd_mdns_resp_matched matchedlist[MAX_MDNS_RESP_TYPE-1]; |
| struct hdd_mdns_resp_info *resp; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_ptr == NULL) || (resptype_ptr_dn == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type Ptr domain name response */ |
| if (strlen((char *)ini_config->mdns_resp_type_ptr_dname) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_ptr_dn, |
| ini_config->mdns_resp_type_ptr_dname, '.')) |
| return TRUE; |
| |
| /* |
| * For data compression |
| * Check if any strings are matched with previous |
| * response. |
| */ |
| numlist = 0; |
| size = (MAX_MDNS_RESP_TYPE-1); |
| size *= sizeof(struct hdd_mdns_resp_matched); |
| vos_mem_zero(matchedlist, size); |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_ptr_dn, |
| resptype_ptr); |
| if (num_matched > 0) { |
| matchedlist[numlist].num_matched = num_matched; |
| matchedlist[numlist].type = MDNS_TYPE_PTR; |
| numlist++; |
| } |
| if (resptype_txt && (resptype_txt->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_ptr_dn, resptype_txt); |
| if (num_matched > 0) { |
| matchedlist[numlist].num_matched = num_matched; |
| matchedlist[numlist].type = MDNS_TYPE_TXT; |
| numlist++; |
| } |
| } |
| if (resptype_a && (resptype_a->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_ptr_dn,resptype_a); |
| if (num_matched > 0) { |
| matchedlist[numlist].num_matched = num_matched; |
| matchedlist[numlist].type = MDNS_TYPE_A; |
| numlist++; |
| } |
| } |
| if (numlist > 0) { |
| if (numlist > 1) |
| wlan_hdd_mdns_find_max(matchedlist, numlist); |
| resp = NULL; |
| switch (matchedlist[numlist-1].type) { |
| case MDNS_TYPE_A: |
| resp = resptype_a; |
| break; |
| case MDNS_TYPE_TXT: |
| resp = resptype_txt; |
| break; |
| case MDNS_TYPE_PTR: |
| resp = resptype_ptr; |
| break; |
| default: |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_PTR_DNAME); |
| return FALSE; |
| } |
| num_matched = matchedlist[numlist-1].num_matched; |
| if (!wlan_hdd_mdns_compress_data(resp_info, resptype_ptr_dn, |
| resp, num_matched)) { |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_PTR_DNAME); |
| return FALSE; |
| } |
| } else { |
| /* num = 0 -> no matched string */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_ptr_dn, |
| resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_PTR_DNAME); |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_ptr() - Pack Type PTR response |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_ptr: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * @resptype_ptr_dn: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * domain name |
| * @resptype_txt: Pointer to the struct hdd_mdns_resp_info of Type Txt |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * The Type Ptr response include QName, response type, class, TTL and |
| * Type PTR domain name. Also, it will find the matched QName from the |
| * existing resptype_txt, resptype_a and then compress the data. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_ptr(hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_ptr, |
| struct hdd_mdns_resp_info *resptype_ptr_dn, |
| struct hdd_mdns_resp_info *resptype_txt, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint8_t num_matched, num_matched1; |
| uint16_t value; |
| uint8_t val_u8; |
| uint32_t offset_data_len, len; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_ptr == NULL) || (resptype_ptr_dn == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type Ptr response */ |
| if (strlen((char *)ini_config->mdns_resp_type_ptr) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_ptr, |
| ini_config->mdns_resp_type_ptr, '.')) |
| return TRUE; |
| |
| /* |
| * For data compression |
| * Check if any strings are matched with Type A response |
| */ |
| num_matched = 0; |
| num_matched1 = 0; |
| if (resptype_a && (resptype_a->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_ptr, |
| resptype_a); |
| } |
| if (resptype_txt && (resptype_txt->num_entries > 0)) { |
| num_matched1 = wlan_hdd_mdns_find_entries_from_end( |
| resptype_ptr, resptype_txt); |
| } |
| if ((num_matched != num_matched1) || |
| ((num_matched > 0) && (num_matched1 > 0))) { |
| if (num_matched >= num_matched1) { |
| if (!wlan_hdd_mdns_compress_data(resp_info, |
| resptype_ptr, resptype_a, num_matched)) { |
| hddLog(LOGE, FL("Fail to compress mDNS " |
| "response (%d)!"), MDNS_TYPE_PTR); |
| return FALSE; |
| } |
| } else { |
| /* num_matched is less than num_matched1 */ |
| if (!wlan_hdd_mdns_compress_data(resp_info, |
| resptype_ptr, resptype_txt, num_matched1)) { |
| hddLog(LOGE, FL("Fail to compress mDNS " |
| "response (%d)!"), MDNS_TYPE_PTR); |
| return FALSE; |
| } |
| } |
| } else { |
| /* |
| * Both num_matched and num_matched1 are zero. |
| * no TypeA & TypeTxt |
| */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_ptr, |
| resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_PTR); |
| return FALSE; |
| } |
| } |
| |
| /* Process response Type, Class, TTL */ |
| if (!wlan_hdd_mdns_process_response_misc(MDNS_TYPE_PTR, resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS misc response (%d)!"), |
| MDNS_TYPE_PTR); |
| return FALSE; |
| } |
| |
| /* |
| * Process response RDLength, RData (Ptr domain name) |
| * Save the offset of RData length |
| */ |
| offset_data_len = resp_info->resp_len; |
| resp_info->resp_len += sizeof(uint16_t); |
| |
| if (!wlan_hdd_mdns_pack_response_type_ptr_dname(ini_config, resp_info, |
| resptype_ptr_dn, resptype_ptr, |
| resptype_txt, resptype_a)) { |
| return FALSE; |
| } |
| /* Set the RData length */ |
| len = offset_data_len + sizeof(uint16_t); |
| if ((resptype_ptr_dn->num_entries > 0) && |
| (resp_info->resp_len > len)) { |
| value = resp_info->resp_len - len; |
| val_u8 = (value & 0xff00) >> 8; |
| resp_info->resp_data[offset_data_len] = val_u8; |
| val_u8 = value & 0xff; |
| resp_info->resp_data[offset_data_len+1] = val_u8; |
| } else { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_PTR); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_srv_target()- Pack Type Service Target |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_srv_tgt: Pointer to the struct hdd_mdns_resp_info of Type Srv |
| * target |
| * @resptype_srv: Pointer to the struct hdd_mdns_resp_info of Type Srv |
| * @resptype_ptr: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * @resptype_ptr_dn: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * domain name |
| * @resptype_txt: Pointer to the struct hdd_mdns_resp_info of Type Txt |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * The Type service target is one of the data field in the Type SRV response. |
| * Also, it will find the matched QName from the existing resptype_srv, |
| * resptype_ptr, resptype_ptr_dn, resptype_txt, resptype_a and then compress |
| * the data. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_srv_target( |
| hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_srv_tgt, |
| struct hdd_mdns_resp_info *resptype_srv, |
| struct hdd_mdns_resp_info *resptype_ptr, |
| struct hdd_mdns_resp_info *resptype_ptr_dn, |
| struct hdd_mdns_resp_info *resptype_txt, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint8_t num_matched, num, size; |
| struct hdd_mdns_resp_matched matchedlist[MAX_MDNS_RESP_TYPE-1]; |
| struct hdd_mdns_resp_info *resp; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_srv == NULL) || (resptype_srv_tgt == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type Srv Target response */ |
| if (strlen((char *)ini_config->mdns_resp_type_srv_target) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_srv_tgt, |
| ini_config->mdns_resp_type_srv_target, '.')) |
| return TRUE; |
| |
| /* |
| * For data compression |
| * Check if any strings are matched with previous response. |
| */ |
| num = 0; |
| size = (MAX_MDNS_RESP_TYPE-1); |
| size *= sizeof(struct hdd_mdns_resp_matched); |
| vos_mem_zero(matchedlist, size); |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_srv_tgt, |
| resptype_srv); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_SRV; |
| num++; |
| } |
| if (resptype_ptr && (resptype_ptr->num_entries > 0)) { |
| if (resptype_ptr_dn && (resptype_ptr_dn->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_srv_tgt, resptype_ptr_dn); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_PTR_DNAME; |
| num++; |
| } |
| } |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_srv_tgt, resptype_ptr); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_PTR; |
| num++; |
| } |
| } |
| if (resptype_txt && (resptype_txt->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_srv_tgt, resptype_txt); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_TXT; |
| num++; |
| } |
| } |
| if (resptype_a && (resptype_a->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_srv_tgt, resptype_a); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_A; |
| num++; |
| } |
| } |
| if (num > 0) { |
| if (num > 1) |
| wlan_hdd_mdns_find_max(matchedlist, num); |
| resp = NULL; |
| switch (matchedlist[num-1].type) { |
| case MDNS_TYPE_A: |
| resp = resptype_a; |
| break; |
| case MDNS_TYPE_TXT: |
| resp = resptype_txt; |
| break; |
| case MDNS_TYPE_PTR: |
| resp = resptype_ptr; |
| break; |
| case MDNS_TYPE_PTR_DNAME: |
| resp = resptype_ptr_dn; |
| break; |
| case MDNS_TYPE_SRV: |
| resp = resptype_srv; |
| break; |
| default: |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_SRV_TARGET); |
| return FALSE; |
| } |
| num_matched = matchedlist[num-1].num_matched; |
| if (!wlan_hdd_mdns_compress_data(resp_info, resptype_srv_tgt, |
| resp, num_matched)) { |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_SRV_TARGET); |
| return FALSE; |
| } |
| } else { |
| /* num = 0 -> no matched string */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_srv_tgt, |
| resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_SRV_TARGET); |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response_type_srv()- Pack Type Service response |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * @resptype_srv: Pointer to the struct hdd_mdns_resp_info of Type Srv |
| * @resptype_srv_tgt: Pointer to the struct hdd_mdns_resp_info of Type Srv |
| * target |
| * @resptype_ptr: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * @resptype_ptr_dn: Pointer to the struct hdd_mdns_resp_info of Type Ptr |
| * domain name |
| * @resptype_txt: Pointer to the struct hdd_mdns_resp_info of Type Txt |
| * @resptype_a: Pointer to the struct hdd_mdns_resp_info of Type A |
| * |
| * The Type SRV (Service) response include QName, response type, class, TTL |
| * and four kinds of data fields. Also, it will find the matched QName from |
| * the existing resptype_ptr, resptype_ptr_dn, resptype_txt, resptype_a and |
| * then compress the data. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response_type_srv(hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info, |
| struct hdd_mdns_resp_info *resptype_srv, |
| struct hdd_mdns_resp_info *resptype_srv_tgt, |
| struct hdd_mdns_resp_info *resptype_ptr, |
| struct hdd_mdns_resp_info *resptype_ptr_dn, |
| struct hdd_mdns_resp_info *resptype_txt, |
| struct hdd_mdns_resp_info *resptype_a) |
| { |
| uint8_t num_matched, num, size; |
| uint16_t value; |
| uint8_t val_u8; |
| uint32_t offset_data_len, len; |
| struct hdd_mdns_resp_info *resp; |
| struct hdd_mdns_resp_matched matchedlist[MAX_MDNS_RESP_TYPE-1]; |
| |
| if ((ini_config == NULL) || (resp_info == NULL) || |
| (resptype_srv == NULL) || (resptype_srv_tgt == NULL)) { |
| hddLog(LOGE, FL("ini_config or response info is NULL!")); |
| return FALSE; |
| } |
| |
| /* No Type Srv response */ |
| if (strlen((char *)ini_config->mdns_resp_type_srv) <= 0) |
| return TRUE; |
| |
| /* Wrong response is assigned, just ignore this response */ |
| if (!wlan_hdd_mdns_init_response(resptype_srv, |
| ini_config->mdns_resp_type_srv, '.')) |
| return TRUE; |
| |
| /* |
| * For data compression |
| * Check if any strings are matched with Type A response |
| */ |
| num = 0; |
| size = (MAX_MDNS_RESP_TYPE-1); |
| size *= sizeof(struct hdd_mdns_resp_matched); |
| vos_mem_zero(matchedlist, size); |
| if (resptype_ptr && (resptype_ptr->num_entries > 0)) { |
| if (resptype_ptr_dn && (resptype_ptr_dn->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end( |
| resptype_srv, |
| resptype_ptr_dn); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_PTR_DNAME; |
| num++; |
| } |
| } |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_srv, |
| resptype_ptr); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_PTR; |
| num++; |
| } |
| } |
| if (resptype_txt && (resptype_txt->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_srv, |
| resptype_txt); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched =num_matched; |
| matchedlist[num].type = MDNS_TYPE_TXT; |
| num++; |
| } |
| } |
| if (resptype_a && (resptype_a->num_entries > 0)) { |
| num_matched = wlan_hdd_mdns_find_entries_from_end(resptype_srv, |
| resptype_a); |
| if (num_matched > 0) { |
| matchedlist[num].num_matched = num_matched; |
| matchedlist[num].type = MDNS_TYPE_A; |
| num++; |
| } |
| } |
| if (num > 0) { |
| if (num > 1) |
| wlan_hdd_mdns_find_max(matchedlist, num); |
| resp = NULL; |
| switch (matchedlist[num-1].type) { |
| case MDNS_TYPE_A: |
| resp = resptype_a; |
| break; |
| case MDNS_TYPE_TXT: |
| resp = resptype_txt; |
| break; |
| case MDNS_TYPE_PTR: |
| resp = resptype_ptr; |
| break; |
| case MDNS_TYPE_PTR_DNAME: |
| resp = resptype_ptr_dn; |
| break; |
| default: |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_SRV); |
| return FALSE; |
| } |
| num_matched = matchedlist[num-1].num_matched; |
| if (!wlan_hdd_mdns_compress_data(resp_info, resptype_srv, |
| resp, num_matched)) { |
| hddLog(LOGE, FL("Fail to compress mDNS response " |
| "(%d)!"), MDNS_TYPE_SRV); |
| return FALSE; |
| } |
| } else { |
| /* num = 0 -> no matched string */ |
| if (!wlan_hdd_mdns_process_response_dname(resptype_srv, |
| resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_SRV); |
| return FALSE; |
| } |
| } |
| |
| /* Process response Type, Class, TTL */ |
| if (!wlan_hdd_mdns_process_response_misc(MDNS_TYPE_SRV, resp_info)) { |
| hddLog(LOGE, FL("Fail to process mDNS misc response (%d)!"), |
| MDNS_TYPE_SRV); |
| return FALSE; |
| } |
| |
| /* |
| * Process response RDLength, RData (Srv target name) |
| * Save the offset of RData length |
| */ |
| offset_data_len = resp_info->resp_len; |
| resp_info->resp_len += sizeof(uint16_t); |
| |
| len = resp_info->resp_len + (3 * sizeof(uint16_t)); |
| if (len >= MAX_MDNS_RESP_LEN) { |
| hddLog(LOGE, FL("resp_len exceeds %d!"), MAX_MDNS_RESP_LEN); |
| return FALSE; |
| } |
| |
| /* set Srv Priority */ |
| value = ini_config->mdns_resp_type_srv_priority; |
| wlan_hdd_mdns_format_response_u16(value, resp_info); |
| /* set Srv Weight */ |
| value = ini_config->mdns_resp_type_srv_weight; |
| wlan_hdd_mdns_format_response_u16(value, resp_info); |
| /* set Srv Port */ |
| value = ini_config->mdns_resp_type_srv_port; |
| wlan_hdd_mdns_format_response_u16(value, resp_info); |
| |
| if (!wlan_hdd_mdns_pack_response_type_srv_target(ini_config, resp_info, |
| resptype_srv_tgt, resptype_srv, |
| resptype_ptr, resptype_ptr_dn, |
| resptype_txt, resptype_a)) { |
| return FALSE; |
| } |
| /* Set the RData length */ |
| len = offset_data_len + sizeof(uint16_t); |
| if ((resptype_srv_tgt->num_entries > 0) && |
| (resp_info->resp_len > len)) { |
| value = resp_info->resp_len - len; |
| val_u8 = (value & 0xff00) >> 8; |
| resp_info->resp_data[offset_data_len] = val_u8; |
| val_u8 = value & 0xff; |
| resp_info->resp_data[offset_data_len+1] = val_u8; |
| } else { |
| hddLog(LOGE, FL("Fail to process mDNS response (%d)!"), |
| MDNS_TYPE_SRV); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| /** |
| * wlan_hdd_mdns_free_mem() - Free the allocated memory |
| * @response: Pointer to the struct hdd_mdns_resp_info |
| * |
| * Return: None |
| */ |
| static void wlan_hdd_mdns_free_mem(struct hdd_mdns_resp_info *response) |
| { |
| if (response && response->data) |
| vos_mem_free(response->data); |
| if (response && response->offset) |
| vos_mem_free(response->offset); |
| } |
| |
| /** |
| * wlan_hdd_mdns_pack_response() - Pack mDNS response |
| * @ini_config: Pointer to the struct hdd_config_t |
| * @resp_info: Pointer to the struct tSirMDNSResponseInfo |
| * |
| * This function will pack four types of responses (Type A, Type Txt, Type Ptr |
| * and Type Service). Each response contains QName, response type, class, TTL |
| * and data fields. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| static bool wlan_hdd_mdns_pack_response(hdd_config_t *ini_config, |
| tpSirMDNSResponseInfo resp_info) |
| { |
| struct hdd_mdns_resp_info resptype_a, resptype_txt; |
| struct hdd_mdns_resp_info resptype_ptr, resptype_ptr_dn; |
| struct hdd_mdns_resp_info resptype_srv, resptype_srv_tgt; |
| uint32_t num_res_records = 0; |
| bool status = FALSE; |
| |
| wlan_hdd_mdns_reset_response(&resptype_a); |
| wlan_hdd_mdns_reset_response(&resptype_txt); |
| wlan_hdd_mdns_reset_response(&resptype_ptr); |
| wlan_hdd_mdns_reset_response(&resptype_ptr_dn); |
| wlan_hdd_mdns_reset_response(&resptype_srv); |
| wlan_hdd_mdns_reset_response(&resptype_srv_tgt); |
| |
| resp_info->resp_len = 0; |
| |
| /* Process Type A response */ |
| if (!wlan_hdd_mdns_pack_response_type_a(ini_config, resp_info, |
| &resptype_a)) |
| goto err_resptype_a; |
| |
| if ((resptype_a.num_entries > 0) && |
| (strlen((char *)&resptype_a.data[0]) > 0)) |
| num_res_records++; |
| |
| /* Process Type TXT response */ |
| if (!wlan_hdd_mdns_pack_response_type_txt(ini_config, resp_info, |
| &resptype_txt, &resptype_a)) |
| goto err_resptype_txt; |
| |
| if ((resptype_txt.num_entries > 0) && |
| (strlen((char *)&resptype_txt.data[0]) > 0)) |
| num_res_records++; |
| |
| /* Process Type PTR response */ |
| if (!wlan_hdd_mdns_pack_response_type_ptr(ini_config, resp_info, |
| &resptype_ptr, &resptype_ptr_dn, |
| &resptype_txt, &resptype_a)) |
| goto err_resptype_ptr; |
| |
| if ((resptype_ptr.num_entries > 0) && |
| (strlen((char *)&resptype_ptr.data[0]) > 0)) |
| num_res_records++; |
| |
| /* Process Type SRV response */ |
| if (!wlan_hdd_mdns_pack_response_type_srv(ini_config, resp_info, |
| &resptype_srv, &resptype_srv_tgt, |
| &resptype_ptr, &resptype_ptr_dn, |
| &resptype_txt, &resptype_a)) |
| goto err_resptype_srv; |
| |
| if ((resptype_srv.num_entries > 0) && |
| (strlen((char *)&resptype_srv.data[0]) > 0)) |
| num_res_records++; |
| |
| resp_info->resourceRecord_count = num_res_records; |
| hddLog(VOS_TRACE_LEVEL_INFO_HIGH, |
| "%s: Pack mDNS response data successfully!", __func__); |
| status = TRUE; |
| |
| err_resptype_srv: |
| wlan_hdd_mdns_free_mem(&resptype_srv); |
| wlan_hdd_mdns_free_mem(&resptype_srv_tgt); |
| |
| err_resptype_ptr: |
| wlan_hdd_mdns_free_mem(&resptype_ptr); |
| wlan_hdd_mdns_free_mem(&resptype_ptr_dn); |
| |
| err_resptype_txt: |
| wlan_hdd_mdns_free_mem(&resptype_txt); |
| |
| err_resptype_a: |
| wlan_hdd_mdns_free_mem(&resptype_a); |
| |
| return status; |
| } |
| |
| /** |
| * wlan_hdd_set_mdns_offload() - Enable mDNS offload |
| * @hostapd_adapter: Pointer to the struct hdd_adapter_t |
| * |
| * This function will set FQDN/unique FQDN (full qualified domain name) |
| * and the mDNS response. Then send them to SME. |
| * |
| * Return: Return boolean. TRUE for success, FALSE for fail. |
| */ |
| bool wlan_hdd_set_mdns_offload(hdd_adapter_t *hostapd_adapter) |
| { |
| hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(hostapd_adapter); |
| tpSirMDNSOffloadInfo mdns_offload_info; |
| tpSirMDNSFqdnInfo mdns_fqdn_info; |
| tpSirMDNSResponseInfo mdns_resp_info; |
| uint32_t fqdn_len, ufqdn_len; |
| |
| if (pHddCtx->cfg_ini->enable_mdns_offload != |
| CFG_MDNS_OFFLOAD_SUPPORT_ENABLE) |
| return FALSE; |
| |
| /* 1. Prepare the MDNS fqdn request to send to SME */ |
| fqdn_len = strlen(pHddCtx->cfg_ini->mdns_fqdn); |
| ufqdn_len = strlen(pHddCtx->cfg_ini->mdns_uniquefqdn); |
| if ((fqdn_len == 0) && (ufqdn_len == 0)) { |
| hddLog(LOGE, FL("No mDNS FQDN or UFQDN is assigned!")); |
| return FALSE; |
| } |
| |
| mdns_fqdn_info = vos_mem_malloc(sizeof(*mdns_fqdn_info)); |
| if (NULL == mdns_fqdn_info) { |
| hddLog(LOGE, FL("could not allocate tSirMDNSFqdnInfo!")); |
| return FALSE; |
| } |
| /* MDNS fqdn request */ |
| if (fqdn_len > 0) { |
| vos_mem_zero(mdns_fqdn_info, sizeof(*mdns_fqdn_info)); |
| mdns_fqdn_info->vdev_id = hostapd_adapter->sessionId; |
| mdns_fqdn_info->fqdn_type = MDNS_FQDN_TYPE_GENERAL; |
| mdns_fqdn_info->fqdn_len = fqdn_len; |
| vos_mem_copy(mdns_fqdn_info->fqdn_data, |
| pHddCtx->cfg_ini->mdns_fqdn, |
| mdns_fqdn_info->fqdn_len); |
| |
| if (eHAL_STATUS_SUCCESS != |
| sme_setMDNSFqdn(pHddCtx->hHal, mdns_fqdn_info)) { |
| hddLog(LOGE, FL("sme_setMDNSFqdn fail!")); |
| vos_mem_free(mdns_fqdn_info); |
| return FALSE; |
| } |
| } |
| /* MDNS unique fqdn request */ |
| if (ufqdn_len > 0) { |
| vos_mem_zero(mdns_fqdn_info, sizeof(*mdns_fqdn_info)); |
| mdns_fqdn_info->vdev_id = hostapd_adapter->sessionId; |
| mdns_fqdn_info->fqdn_type = MDNS_FQDN_TYPE_UNIQUE; |
| mdns_fqdn_info->fqdn_len = ufqdn_len; |
| vos_mem_copy(mdns_fqdn_info->fqdn_data, |
| pHddCtx->cfg_ini->mdns_uniquefqdn, |
| mdns_fqdn_info->fqdn_len); |
| |
| if (eHAL_STATUS_SUCCESS != |
| sme_setMDNSFqdn(pHddCtx->hHal, mdns_fqdn_info)) { |
| hddLog(LOGE, FL("sme_setMDNSFqdn fail!")); |
| vos_mem_free(mdns_fqdn_info); |
| return FALSE; |
| } |
| } |
| vos_mem_free(mdns_fqdn_info); |
| |
| /* 2. Prepare the MDNS response request to send to SME */ |
| mdns_resp_info = vos_mem_malloc(sizeof(*mdns_resp_info)); |
| if (NULL == mdns_resp_info) { |
| hddLog(LOGE, FL("could not allocate tSirMDNSResponseInfo!")); |
| return FALSE; |
| } |
| |
| vos_mem_zero(mdns_resp_info, sizeof(*mdns_resp_info)); |
| mdns_resp_info->vdev_id = hostapd_adapter->sessionId; |
| |
| if (!wlan_hdd_mdns_pack_response(pHddCtx->cfg_ini, mdns_resp_info)) { |
| hddLog(LOGE, FL("wlan_hdd_pack_mdns_response fail!")); |
| vos_mem_free(mdns_resp_info); |
| return FALSE; |
| } |
| |
| if (eHAL_STATUS_SUCCESS != |
| sme_setMDNSResponse(pHddCtx->hHal, mdns_resp_info)) { |
| hddLog(LOGE, FL("sme_setMDNSResponse fail!")); |
| vos_mem_free(mdns_resp_info); |
| return FALSE; |
| } |
| |
| vos_mem_free(mdns_resp_info); |
| |
| /* 3. Prepare the MDNS Enable request to send to SME */ |
| mdns_offload_info = vos_mem_malloc(sizeof(*mdns_offload_info)); |
| if (NULL == mdns_offload_info) { |
| hddLog(LOGE, FL("could not allocate tSirMDNSOffloadInfo!")); |
| return FALSE; |
| } |
| |
| vos_mem_zero(mdns_offload_info, sizeof(*mdns_offload_info)); |
| mdns_offload_info->vdev_id = hostapd_adapter->sessionId; |
| mdns_offload_info->mDNSOffloadEnabled = |
| pHddCtx->cfg_ini->enable_mdns_offload; |
| |
| if (eHAL_STATUS_SUCCESS != |
| sme_setMDNSOffload(pHddCtx->hHal, mdns_offload_info)) { |
| hddLog(LOGE, FL("sme_setMDNSOffload fail!")); |
| vos_mem_free(mdns_offload_info); |
| return FALSE; |
| } |
| |
| vos_mem_free(mdns_offload_info); |
| hddLog(VOS_TRACE_LEVEL_INFO_HIGH, |
| "%s: enable mDNS offload successfully!", __func__); |
| return TRUE; |
| } |
| #endif /* MDNS_OFFLOAD */ |