mako: enable to modify mac address at boot time
- add conn_init and libwfcu packages
- modify mac address of ini and nv (calibration) file through conn_init service
- change ini and nv files location from /system/etc/firmware/wlan/prima
to /system/etc/wifi, because we must read and write mac address from persist.
We use wifi firmware loaded location to /vendor/firmware.
System partition is read-only, so use some fake links like the followings:
- conn_init operation:
1. copy /system/etc/wifi/WCNSS_qcom_cfg.ini and WCNSS_qcom_wlan_nv.bin
to /data/misc/wifi.
2. read mac address from persist and write to ini and nv.
3. WCNSS_qcom.cfg.ini and WCNSS_qcom_wlan.vn.bin must be loaded
in /etc/firmware, /vendor/firmware, or /firmware/image.
4. To operate 3, we use the fake links between
/data/misc/wifi and /vendor/firmware/wlan/prima
5. Now, we can use modified ini and nv files from /vendor/firmware/wlan/prima/
Change-Id: I161385f6883ecf6350bd71ab9f2fc9b2543937c0
diff --git a/conn_init/wfc_util_fctrl.c b/conn_init/wfc_util_fctrl.c
new file mode 100644
index 0000000..13a82f1
--- /dev/null
+++ b/conn_init/wfc_util_fctrl.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright 2012 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "wfc_util_log.h"
+
+/*
+static void wfc_util_printf(char *pSPointer, int length)
+{
+ char *pPrintBuff = NULL;
+
+ if( NULL == pSPointer || 0 >= length ) {
+ wfc_util_log_error("wfc_util_printf : unvalid parameters");
+ return;
+ }
+
+ wfc_util_log_error("wfc_util_printf : lenght is (%d)", length);
+ pPrintBuff = malloc(length+1);
+
+ if( NULL != pPrintBuff ) {
+ memset( pPrintBuff, 0, (length+1) );
+ memcpy(pPrintBuff, pSPointer, length);
+
+ wfc_util_log_error("wfc_util_printf : %s", pPrintBuff);
+
+ free(pPrintBuff);
+ } else {
+ wfc_util_log_error("wfc_util_printf : can not malloc(%d)", (length+1));
+ }
+ return;
+}
+*/
+
+static void wfc_util_finsert_new_string(int fd, char **ppReadedBuff, char *pNewStringValue, char *pEndOfCfg)
+{
+ off_t sz_file;
+ int sz_backupBuff = 0;
+ char *pReadBuff = NULL, *pBackupBuff = NULL;
+ char *pSPointer = NULL, *pETagPointer = NULL;
+
+ if( 0 == fd || NULL == pNewStringValue || 0 == strlen(pNewStringValue) ) {
+ wfc_util_log_error("wfc_util_finsert_new_string : unvalid parameters");
+ return;
+ }
+
+ if( NULL == ppReadedBuff) {
+ // TODO:
+ return;
+ } else {
+ pReadBuff = *ppReadedBuff;
+ }
+
+ /*
+ * find END TAG string
+ */
+ pETagPointer = strstr(pReadBuff, pEndOfCfg);
+ pSPointer = pETagPointer - 1;
+
+ /*
+ * calcurate file size and size of the tail of file
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+ sz_backupBuff = (int)sz_file - (pETagPointer - pReadBuff);
+
+ /*
+ * prefare the buffer to store the tail of file
+ */
+ pBackupBuff = malloc(sz_backupBuff);
+
+ if( NULL != pBackupBuff ) {
+ /*
+ * copy the tail of file.
+ */
+ memset( pBackupBuff, 0, sz_backupBuff );
+ memcpy( pBackupBuff, pETagPointer, sz_backupBuff );
+
+ /*
+ * write new string.
+ */
+ lseek( fd, (int)(pSPointer-pReadBuff), SEEK_SET );
+ write( fd, pNewStringValue, strlen(pNewStringValue));
+
+ /*
+ * update pETagPointer.
+ */
+ pETagPointer = pSPointer + strlen(pNewStringValue);
+
+ /*
+ * write the tail of file.
+ */
+ lseek( fd, (int)(pETagPointer-pReadBuff), SEEK_SET );
+ write( fd, pBackupBuff, sz_backupBuff );
+
+ ftruncate(fd, sz_file + strlen(pNewStringValue) - 1); /* we use "-1" becasue of "pSPointer = pETagPointer - 1"*/
+
+ free(pBackupBuff);
+
+ /*
+ * make new *ppReadedBuff
+ */
+ if( NULL != ppReadedBuff) {
+ // TODO:
+ }
+ } else {
+ wfc_util_log_error("wfc_util_finsert_new_string : can not malloc(%d)", sz_backupBuff);
+ }
+
+ return;
+}
+
+static void wfc_util_fupdate_string(int fd, char **ppReadedBuff,
+ char *pETagPointer, char *pSValuePointer, char *pNewValueString)
+{
+ off_t sz_file;
+ int sz_newReadBuff = 0;
+ char *pReadBuff = NULL, *pNewReadBuff = NULL, *pCurReadBuff = NULL;
+
+ if( 0 == fd ) {
+ wfc_util_log_error("wfc_util_fupdate_string : unvalid parameters");
+ return;
+ }
+
+ if( NULL == ppReadedBuff) {
+ // TODO:
+ return;
+ } else {
+ pReadBuff = *ppReadedBuff;
+ }
+
+ /*
+ * calcurate file size and new file size
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+ sz_newReadBuff = (int)sz_file - (int)(pETagPointer - pSValuePointer) + strlen(pNewValueString);
+
+ /*
+ * prefare the buffer to read file
+ */
+ pNewReadBuff = malloc(sz_newReadBuff);
+
+ if( NULL != pNewReadBuff ) {
+ /*
+ * copy buffer
+ */
+ memset( pNewReadBuff, 0, sz_file );
+ pCurReadBuff = pNewReadBuff;
+ memcpy( pNewReadBuff, pReadBuff, (int)(pSValuePointer-pReadBuff) );
+ pCurReadBuff += (int)(pSValuePointer-pReadBuff);
+
+ /*
+ * copy new value string
+ */
+ memcpy( pCurReadBuff, pNewValueString, strlen(pNewValueString));
+ pCurReadBuff += strlen(pNewValueString);
+
+ /*
+ * copy the remained buffer
+ */
+ memcpy( pCurReadBuff, pETagPointer, ((int)(sz_file) - (int)(pETagPointer - pReadBuff) + 1));
+
+ /*
+ * write file and update the file size
+ */
+ lseek( fd, 0, SEEK_SET );
+ write( fd, pNewReadBuff, sz_newReadBuff);
+ ftruncate(fd, sz_newReadBuff);
+
+ free(pNewReadBuff);
+ } else {
+ wfc_util_log_error("wfc_util_fupdate_string : can not malloc(%d)", (int)sz_newReadBuff);
+ }
+
+ return;
+}
+
+/*
+ * wfc_util_fset_buffer
+ *
+ * return : void
+ */
+void wfc_util_fset_buffer(char *pFileName, int positionStart, unsigned char *pNewValue, int newValueLength)
+{
+ int fd;
+ off_t sz_file;
+ char *pReadBuff = NULL;
+
+ fd = open( pFileName, O_RDWR );
+
+ if( fd >= 0 ) {
+ /*
+ * calcurate file size
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+
+ /*
+ * prefare the buffer to read file
+ */
+ pReadBuff = malloc(sz_file + 1); // null terminated
+
+ if( NULL != pReadBuff ) {
+ /*
+ * read file
+ */
+ memset( pReadBuff, 0, sz_file + 1);
+ lseek( fd, 0, SEEK_SET );
+ read( fd, pReadBuff, sz_file );
+
+ if(sz_file >= (positionStart+newValueLength)) {
+ lseek( fd, positionStart, SEEK_SET );
+ write( fd, pNewValue, newValueLength );
+ } else {
+ /*
+ * insert with new length value buffer
+ */
+ wfc_util_log_error("wfc_util_fset_buffer : file size(%d) is less than to write position(%d)", (int)sz_file, (positionStart+newValueLength));
+ // TODO:
+ }
+
+ free(pReadBuff);
+ } else {
+ wfc_util_log_error("wfc_util_fset_buffer : can not malloc(%d)", (int)sz_file);
+ }
+
+ if ( -1 == fsync( fd ) ) {
+ wfc_util_log_error("wfc_util_fset_buffer : fail to fsync()");
+ }
+
+ close( fd );
+ } else {
+ wfc_util_log_error("wfc_util_fset_buffer : can not open file");
+ }
+
+ return;
+}
+
+/*
+ * wfc_util_fget_buffer
+ *
+ * return : it will return the length of the stored buffer value if procedure is success
+ * or will return 0 if not.
+ */
+int wfc_util_fget_buffer(char *pFileName, int positionStart, int lengthToRead, unsigned char *pValueBuff, int buffLength)
+{
+ int result = 0;
+ int fd;
+ off_t sz_file;
+ char *pReadBuff = NULL;
+ char *pSValuePointer = NULL, *pETagPointer = NULL;
+
+ fd = open( pFileName, O_RDONLY );
+
+ if( fd >= 0 ) {
+ /*
+ * calcurate file size
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+
+ if(sz_file >= (positionStart+lengthToRead)) {
+ /*
+ * prefare the buffer to read file
+ */
+ pReadBuff = malloc(sz_file + 1); // null terminated
+
+ if( NULL != pReadBuff ) {
+ /*
+ * read file
+ */
+ memset( pReadBuff, 0, sz_file + 1 );
+ lseek( fd, 0, SEEK_SET );
+ read( fd, pReadBuff, sz_file );
+
+ /*
+ * calculate the start buffer pointer
+ */
+ pSValuePointer = pReadBuff + positionStart;
+
+ /*
+ * calculate the end buffer pointer
+ */
+ pETagPointer = pSValuePointer + lengthToRead;
+
+ /*
+ * read the string value
+ */
+ if( buffLength >= (int)(pETagPointer-pSValuePointer) ) {
+ memset( pValueBuff, 0, buffLength );
+ memcpy( pValueBuff, pSValuePointer, (int)(pETagPointer-pSValuePointer) );
+ result = (int)(pETagPointer-pSValuePointer);
+ } else {
+ wfc_util_log_error("wfc_util_fget_buffer : not enough string value buffer(%d)", (int)(pETagPointer-pSValuePointer));
+ }
+
+ free(pReadBuff);
+ } else {
+ wfc_util_log_error("wfc_util_fget_buffer : can not malloc(%d)", (int)sz_file);
+ }
+ } else {
+ wfc_util_log_error("wfc_util_fget_buffer : file size(%d) is less than to read position(%d)", (int)sz_file, (positionStart+lengthToRead));
+ }
+ close( fd );
+ } else {
+ wfc_util_log_error("wfc_util_fget_buffer : can not open file");
+ }
+
+ return result;
+}
+
+/*
+ * wfc_util_fset_string
+ *
+ * The following format string will be added or updated to the file pFileName.
+ * [pSTagString][pNewValueString][pETagString]
+ *
+ * pFileName : file name and path
+ * pEndOfCfg : tag string to notify the end of configuration file
+ * pSTagString : tag string to notify purpose of the value
+ * pETagString : tag string to notify the end of the value
+ * pNewValueString : string to set for pSTagString
+ *
+ * return : void
+ */
+void wfc_util_fset_string(char *pFileName, char *pEndOfCfg, char *pSTagString, char *pETagString, char *pNewValueString)
+{
+ int fd;
+ off_t sz_file;
+ int sz_NewValueBuff = 0;
+ char *pReadBuff = NULL, *pNewValueBuff = NULL;
+ char *pSPointer = NULL, *pETagPointer = NULL, *pSValuePointer = NULL;
+
+ fd = open( pFileName, O_RDWR );
+
+ if( fd >= 0 ) {
+ /*
+ * calcurate file size
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+
+ /*
+ * prefare the buffer to read file
+ */
+ if (sz_file > 0)
+ pReadBuff = malloc(sz_file + 1); // null terminated
+
+ if( NULL != pReadBuff ) {
+ /*
+ * read file
+ */
+ memset( pReadBuff, 0x00, sz_file + 1);
+ if(lseek(fd, 0, SEEK_SET) != 0) {
+ wfc_util_log_error("lseek failure");
+ }
+ read( fd, pReadBuff, sz_file );
+
+ /* WBT fix, make sure it is terminated with \0 */
+ pReadBuff[sz_file] = '\0';
+
+ /*
+ * find TAG string
+ */
+ pSPointer = strstr(pReadBuff, pSTagString);
+
+ if(NULL != pSPointer) {
+ /*
+ * find END OF LINE string
+ */
+ pETagPointer = strstr(pSPointer, pETagString);
+
+ if(NULL != pETagPointer) {
+ /*
+ * write the new string value
+ */
+ pSValuePointer = pSPointer+strlen(pSTagString);
+ if(strlen(pNewValueString) == (unsigned int)(pETagPointer-pSValuePointer)) {
+ lseek( fd, (int)(pSValuePointer-pReadBuff), SEEK_SET );
+ write( fd, pNewValueString, strlen(pNewValueString));
+ } else {
+ /*
+ * insert with new length value string
+ */
+ wfc_util_fupdate_string(fd, &pReadBuff, pETagPointer, pSValuePointer, pNewValueString);
+ }
+ } else {
+ wfc_util_log_error("wfc_util_fset_string : can not find End TAG");
+ }
+ } else {
+ /*
+ * "\n""[Start TAG][String Value][End TAG]""\n"
+ */
+ sz_NewValueBuff = strlen(pSTagString) +
+ strlen(pNewValueString) +
+ strlen(pETagString) +
+ 2 + 1;
+ pNewValueBuff = malloc( sz_NewValueBuff);
+
+ if( NULL != pNewValueBuff ) {
+ /*
+ * prefare the new string to insert
+ */
+ memset( pNewValueBuff, 0, sz_NewValueBuff );
+ sprintf( pNewValueBuff, "%c%s%s%s%c", '\n', pSTagString, pNewValueString, pETagString,'\n' );
+
+ /*
+ * insert new string to the file
+ */
+ wfc_util_finsert_new_string(fd, &pReadBuff, pNewValueBuff, pEndOfCfg);
+
+ free( pNewValueBuff );
+ } else {
+ wfc_util_log_error("wfc_util_fset_string : can not malloc(%d)", (int)sz_file);
+ }
+ }
+
+ free(pReadBuff);
+ } else {
+ wfc_util_log_error("wfc_util_fset_string : can not malloc(%d)", (int)sz_file);
+ }
+
+ if ( -1 == fsync( fd ) ) {
+ wfc_util_log_error("wfc_util_fset_string : fail to fsync()");
+ }
+
+ close( fd );
+ } else {
+ wfc_util_log_error("wfc_util_fset_string : can not open file");
+ }
+
+ return;
+}
+
+/*
+ * wfc_util_fget_string
+ *
+ * Read value from the following format string in the file pFileName.
+ * [pSTagString][string value to read][pETagString]
+ *
+ * pFileName : file name and path
+ * pEndOfCfg : tag string to notify the end of configuration file
+ * pSTagString : tag string to notify purpose of the value
+ * pETagString : tag string to notify the end of the value
+ * pValueStringBuff : string buffer to get string value
+ * stringBuffLength : the length of pValueStringBuff
+ *
+ * return : it will return the length of the stored string value if procedure is success
+ * or will return 0 if not.
+ */
+int wfc_util_fget_string(char *pFileName, char *pEndOfCfg, char *pSTagString, char *pETagString, char *pValueStringBuff, int stringBuffLength)
+{
+ int result = 0;
+ int fd;
+ off_t sz_file;
+ char *pReadBuff = NULL;
+ char *pSPointer = NULL, *pETagPointer = NULL, *pSValuePointer = NULL;
+
+ /* unused parameter*/
+ pEndOfCfg = pEndOfCfg;
+
+ fd = open( pFileName, O_RDONLY );
+
+ if( fd >= 0 ) {
+ /*
+ * calcurate file size
+ */
+ sz_file = lseek( fd, 0, SEEK_END );
+
+ /*
+ * prefare the buffer to read file
+ */
+ if (sz_file > 0) // skip when value is 0
+ pReadBuff = malloc(sz_file + 1);
+
+ if( NULL != pReadBuff ) {
+ /*
+ * read file
+ */
+ memset( pReadBuff, 0, sz_file + 1);
+ if(lseek(fd, 0, SEEK_SET) != 0) {
+ wfc_util_log_error("lseek failure");
+ }
+ read( fd, pReadBuff, sz_file );
+
+ /* WBT fix, make sure it is terminated with \0 */
+ pReadBuff[sz_file] = '\0';
+
+ /*
+ * find TAG string
+ */
+ pSPointer = strstr( pReadBuff, pSTagString );
+
+ if( NULL != pSPointer ) {
+ /*
+ * find END OF LINE string
+ */
+ pETagPointer = strstr(pSPointer, pETagString);
+
+ if( NULL != pETagPointer ) {
+ /*
+ * read the string value
+ */
+ pSValuePointer = pSPointer+strlen(pSTagString);
+ if( stringBuffLength >= (int)(pETagPointer-pSValuePointer) ) {
+ memset( pValueStringBuff, 0, stringBuffLength );
+ memcpy( pValueStringBuff, pSValuePointer, (int)(pETagPointer-pSValuePointer) );
+ result = (int)(pETagPointer-pSValuePointer);
+ } else {
+ wfc_util_log_error("wfc_util_fget_string : not enough string value buffer(%d)", (int)(pETagPointer-pSValuePointer));
+ }
+ } else {
+ wfc_util_log_error("wfc_util_fget_string : can not find End TAG");
+ }
+ } else {
+ wfc_util_log_error("wfc_util_fget_string : can not find Start TAG");
+ }
+ free(pReadBuff);
+ } else {
+ wfc_util_log_error("wfc_util_fget_string : can not malloc(%d)", (int)sz_file);
+ }
+ close( fd );
+ } else {
+ wfc_util_log_error("wfc_util_fget_string : can not open file");
+ }
+
+ return result;
+}
+
+/*
+ * wfc_util_ffile_check
+ *
+ * check whether pDestFName file exist or not
+ *
+ * pFileName : file name and path
+ * access_mode : R_OK | W_OK | X_OK | F_OK
+ *
+ * return : it will return 0 if the file exist
+ * or will return -1 if not.
+ */
+int wfc_util_ffile_check(char *pDestFName, int access_mode)
+{
+ struct stat st;
+
+ if (access(pDestFName, access_mode) == 0) {
+ if( stat( pDestFName, &st ) < 0 ) {
+ wfc_util_log_error("Cannot stat the file \"%s\": %s", pDestFName, strerror(errno));
+ return -1;
+ }
+ //check if config file has some data or is it empty due to previous errors
+ if( st.st_size ) {
+ return 0;
+ }
+ } else {
+ wfc_util_log_error("Cannot access \"%s\": %s", pDestFName, strerror(errno));
+ }
+
+ return -1;
+}
+
+/*
+ * wfc_util_ffile_check_copy
+ *
+ * check whether pDestFName file exist if not it will copy from pSourceFName file
+ *
+ * return : it will return 0 if procedure is success
+ * or will return -1 if not.
+ */
+int wfc_util_ffile_check_copy(char *pDestFName, char *pSourceFName, mode_t mode, uid_t uID, gid_t gID)
+{
+#define WFC_BUFFER_SIZE 2048
+ char buf[WFC_BUFFER_SIZE] = {0}; // Null terminated
+ int srcfd, destfd;
+ int nread;
+ struct stat st;
+
+ if (access(pDestFName, R_OK|W_OK) == 0) {
+ if( stat( pDestFName, &st ) < 0 ) {
+ wfc_util_log_error("Cannot stat the file \"%s\": %s", pDestFName, strerror(errno));
+ return -1;
+ }
+ //check if config file has some data or is it empty due to previous errors
+ if( st.st_size ) {
+ return 0;
+ }
+ //else continue to write the config from default template.
+ } else if (errno != ENOENT) {
+ wfc_util_log_error("Cannot access \"%s\": %s", pDestFName, strerror(errno));
+ return -1;
+ }
+
+ srcfd = open(pSourceFName, O_RDONLY);
+ if (srcfd < 0) {
+ wfc_util_log_error("Cannot open \"%s\": %s", pSourceFName, strerror(errno));
+ return -1;
+ }
+
+ destfd = open(pDestFName, O_CREAT|O_WRONLY, mode);
+ if (destfd < 0) {
+ close(srcfd);
+ wfc_util_log_error("Cannot create \"%s\": %s", pDestFName, strerror(errno));
+ return -1;
+ }
+
+ while ((nread = read(srcfd, buf, WFC_BUFFER_SIZE-1)) != 0) {
+ if (nread < 0) {
+ wfc_util_log_error("Error reading \"%s\": %s", pSourceFName, strerror(errno));
+ close(srcfd);
+ close(destfd);
+ unlink(pDestFName);
+ return -1;
+ }
+ // WBT fix, according to manual, the number of bytes read can't be bigger than read_size. I don't know why WBT complains for this.
+ if (nread < WFC_BUFFER_SIZE)
+ buf[nread] = '\0';
+ else {
+ buf[WFC_BUFFER_SIZE-1] = '\0';
+ nread = WFC_BUFFER_SIZE-1;
+ }
+ write(destfd, buf, nread);
+ }
+
+ close(destfd);
+ close(srcfd);
+
+ /* remove this code because of permission problem when it is accessed from "atd" having system permission. */
+ {
+ #ifndef CONFIG_LGE_WLAN_WIFI_PATCH
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+ wfc_util_log_error("Error changing group ownership (%d) of %s to %d: %s", gid, pDestFName, gID, strerror(errno));
+ if (0 == uid) {
+ #endif /* CONFIG_LGE_WLAN_WIFI_PATCH */
+ if (chown(pDestFName, uID, gID) < 0) {
+ wfc_util_log_error("Error changing group ownership of %s to %d: %s", pDestFName, gID, strerror(errno));
+ unlink(pDestFName);
+ return -1;
+ }
+ #ifndef CONFIG_LGE_WLAN_WIFI_PATCH
+ } else {
+ wfc_util_log_error("wfc_util_ffile_check_copy : we can not excute chown[uid = %d, gid = %d]", uid, getgid());
+ }
+ #endif /* CONFIG_LGE_WLAN_WIFI_PATCH */
+ }
+
+ return 0;
+}
+