| /** |
| * @file softap_api.c |
| * @brief Implementation of Sanechips |
| * |
| * Copyright (C) 2017 Sanechips Technology Co., Ltd. |
| * @author linxu Gebin |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| * |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <syslog.h> |
| #include <sys/klog.h> |
| #include <sys/msg.h> |
| #include <sys/socket.h> |
| #include <linux/sockios.h> |
| #include <sys/un.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/msg.h> |
| #include <limits.h> |
| #include "softap_api.h" |
| |
| |
| /* ƽ̨»ù´¡Ó¦Ó㬼´: ËùÓÐÐͺŻú¶¼ÐèÒªÆô¶¯µÄÓ¦Óà */ |
| static int basic_apps[] = { |
| MODULE_ID_AT_CTL, // AT |
| MODULE_ID_MAIN_CTRL, // Ö÷¿Ø |
| MODULE_ID_RTC_SERVICE, // rtc |
| MODULE_ID_CODEC // audio ctrl |
| }; |
| |
| static int is_basic_app(int module_id) |
| { |
| int i = 0; |
| |
| for (i = 0; i < sizeof(basic_apps) / sizeof(basic_apps[0]); i++) { |
| if (module_id == basic_apps[i]) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| //»ñÈ¡¶àºË»ù׼ʱ¼ä |
| long long int get_time_us() |
| { |
| int fd; |
| char buf[128] = {0}; |
| |
| fd = open("/proc/persistent_time", O_RDWR); |
| if (fd < 0) { |
| printf("fail to open\n"); |
| return -1; |
| } |
| #if 1 |
| int len = read(fd, buf, sizeof(buf)-1); |
| long long time = 0; |
| |
| if(len < 0 ){ |
| close(fd); |
| return -1; |
| }else{ |
| close(fd); |
| time = atoll(buf); |
| if(time < 0 || time > LLONG_MAX-1) |
| { |
| time = 0; |
| } |
| |
| return time; |
| } |
| #else |
| if (read(fd, buf, 127) > 0) { |
| close(fd); |
| return atoll(buf); |
| } else { |
| close(fd); |
| return -1; |
| } |
| #endif |
| } |
| |
| /************************************************************************** |
| * º¯ÊýÃû³Æ£º soc_send_condition_check |
| * ¹¦ÄÜÃèÊö£º ¼ì²âÊÇ·ñÂú×ãSOCÏûÏ¢·¢ËÍÌõ¼þ£¬Èç¹ûÊÇ´ÓAP·¢Ë͵½CP£¬Ôòsrc_id±ØÐëΪAP²àµÄmoduleid£¬dst_id±ØÐëΪ |
| * moduleid; Èç¹ûÊÇ´ÓCP·¢Ë͵½AP£¬Ôòsrc_id±ØÐëΪCP²àµÄmoduleid£¬dst_id±ØÐëΪAP²àµÄmoduleid. |
| * ²ÎÊý˵Ã÷£ºsrc_id:ÏûÏ¢·¢ËÍÄ£¿éID dest_id:ÏûÏ¢½ÓÊÕÄ£¿éID |
| * ·µ »Ø Öµ£º 1:·ûºÏÌõ¼þ0:²»·ûºÏÌõ¼þ |
| * ÆäËü˵Ã÷£º |
| **************************************************************************/ |
| static int soc_send_condition_check(int src_id, int dst_id) |
| { |
| #if (APP_OS_TYPE == APP_OS_TOS) |
| if ((src_id <= MODULE_ID_CPBASE) || (src_id >= MODULE_ID_MAX)) { //¼ì²âsrc_idÊÇ·ñΪCPºËÄ£¿éºÅ |
| return 0; |
| } else if ((dst_id <= MODULE_ID_APBASE) || (dst_id >= MODULE_ID_CPBASE)) { //¼ì²âdst_idÊÇ·ñΪAPºËÄ£¿éºÅ |
| return 0; |
| } |
| |
| return 1; |
| #endif |
| |
| #if (APP_OS_TYPE == APP_OS_LINUX) |
| if ((src_id <= MODULE_ID_APBASE) || (src_id >= MODULE_ID_CPBASE)) { //¼ì²âsrc_idÊÇ·ñΪAPºËÄ£¿éºÅ |
| return 0; |
| } else if ((dst_id <= MODULE_ID_CPBASE) || (dst_id >= MODULE_ID_MAX)) { //¼ì²âdst_idÊÇ·ñΪCPºËÄ£¿éºÅ |
| return 0; |
| } |
| |
| return 1; |
| |
| #endif |
| } |
| |
| /************************ Ó¦Óü乫¹²º¯ÊýʵÏÖ ************************/ |
| /*·µ»ØÖµ 0 ³É¹¦ ·Ç0ʧ°Ü£¬ |
| Èç¹û·µ»ØÖµµÈÓÚENOENT£¬±íʾ½ÓÊÕ¶ÓÁв»´æÔÚ£¬Ó¦ÓÃ×ÔÐÐÅжϽÓÊÕÄ£¿éÊÇ·ñÒ»¶¨Æô¶¯£¬Èç¹ûÊÇ£¬µ÷ÓÃipc_send_message2·¢ËÍ*/ |
| int ipc_send_message(int src_id, int dst_id, unsigned short Msg_cmd, unsigned short us_DataLen, unsigned char *pData, int msgflag) |
| { |
| MSG_BUF stMsg; |
| int lRet = 0; |
| int lTgtMsgID = 0; |
| LONG msgSize = offsetof(MSG_BUF, aucDataBuf) - sizeof(LONG) + us_DataLen; |
| int errNo = 0; |
| |
| memset(&stMsg, 0, sizeof(MSG_BUF)); |
| |
| lTgtMsgID = msgget(dst_id, 0); |
| if (-1 == lTgtMsgID) { |
| errNo = errno; |
| slog(NET_PRINT, SLOG_ERR, "send_message failed:can not get target msg id, src:0x%x, target:0x%x, cmd:0x%x, errNo:%d! \n", src_id, dst_id, Msg_cmd, errNo); /*lint !e26*/ |
| |
| /* »ù´¡Ó¦ÓñØÐë·¢Ëͳɹ¦£¬Èç¹ûÓ¦Óû¹Ã»Æð¾ÍÖ±½ÓÏÈ´´½¨ÏûÏ¢½ÓÊÕ¶ÓÁУ¬Æô¶¯ºóÔÙ´¦Àí */ |
| if (is_basic_app(dst_id)) { |
| slog(NET_PRINT, SLOG_ERR, "send_message failed, basic app \n"); |
| return ipc_send_message2(src_id, dst_id, Msg_cmd, us_DataLen, pData, msgflag); |
| } |
| return errNo; |
| } |
| |
| if (us_DataLen >= MSG_DATA_MAX_LEN) { |
| slog(NET_PRINT, SLOG_ERR, "send_message failed:us_DataLen %d is too big, src:0x%x, target:0x%x, cmd:0x%x! \n", us_DataLen, src_id, dst_id, Msg_cmd); /*lint !e26*/ |
| softap_assert("send_message failed:us_DataLen %d is too big!", us_DataLen); |
| return EINVAL; |
| } |
| |
| if ((us_DataLen > 0) && (NULL == pData)) { |
| slog(NET_PRINT, SLOG_ERR, "send_message failed:us_DataLen is %d, but pData is NULL! \n", us_DataLen); /*lint !e26*/ |
| softap_assert("send_message failed:us_DataLen is %d, but pData is NULL!", us_DataLen); |
| return EINVAL; |
| } |
| |
| stMsg.ulMagic = MSG_MAGIC_WORD; |
| stMsg.lMsgType = MSG_TYPE_DEFAULT; |
| stMsg.src_id = src_id; |
| stMsg.dst_id = dst_id; |
| stMsg.usMsgCmd = Msg_cmd; |
| stMsg.usDataLen = us_DataLen; |
| |
| if (us_DataLen > 0) { |
| memcpy(stMsg.aucDataBuf, pData, us_DataLen); |
| } |
| |
| AGAIN: |
| lRet = msgsnd(lTgtMsgID, &stMsg, msgSize, msgflag); |
| if (lRet < 0) { |
| if (errno == EINTR) { |
| goto AGAIN; |
| } |
| errNo = errno; |
| slog(NET_PRINT, SLOG_ERR, "send_message failed: msgsnd error code %d!, errNo:%d \n", lRet, errNo); /*lint !e26*/ |
| if (msgflag != IPC_NOWAIT) { |
| softap_assert("send_message failed: msgsnd error code errNo:%d! \n", errNo); |
| } |
| return errNo; |
| } |
| return 0; |
| } |
| |
| int ipc_send_message2(int src_id, int dst_id, unsigned short Msg_cmd, unsigned short us_DataLen, unsigned char *pData, int msgflag) |
| { |
| MSG_BUF stMsg; |
| int lRet = 0; |
| int lTgtMsgID = 0; |
| LONG msgSize = offsetof(MSG_BUF, aucDataBuf) - sizeof(LONG) + us_DataLen; |
| int errNo = 0; |
| |
| memset(&stMsg, 0, sizeof(MSG_BUF)); |
| |
| lTgtMsgID = msgget(dst_id, IPC_CREAT | 0600); |
| if (-1 == lTgtMsgID) { |
| errNo = errno; |
| slog(NET_PRINT, SLOG_ERR, "send_message2 failed:can not get target id, src:0x%x, target:0x%x, cmd:0x%x, errNo:%d!", src_id, dst_id, Msg_cmd, errNo); /*lint !e26*/ |
| softap_assert("send_message2 failed:can not get target msg id 0x%04x!", dst_id); |
| return errNo; |
| } |
| |
| if (us_DataLen >= MSG_DATA_MAX_LEN) { |
| slog(NET_PRINT, SLOG_ERR, "send_message2 failed:us_DataLen %d is too big, src:0x%x, target:0x%x, cmd:0x%x!", us_DataLen, src_id, dst_id, Msg_cmd); /*lint !e26*/ |
| softap_assert("send_message2 failed:us_DataLen %d is too big!", us_DataLen); |
| return EINVAL; |
| } |
| |
| if ((us_DataLen > 0) && (NULL == pData)) { |
| slog(NET_PRINT, SLOG_ERR, "send_message2 failed:us_DataLen is %d, but pData is NULL!", us_DataLen); /*lint !e26*/ |
| softap_assert("send_message2 failed:us_DataLen is %d, but pData is NULL!", us_DataLen); |
| return EINVAL; |
| } |
| |
| stMsg.ulMagic = MSG_MAGIC_WORD; |
| stMsg.lMsgType = MSG_TYPE_DEFAULT; |
| stMsg.src_id = src_id; |
| stMsg.dst_id = dst_id; |
| stMsg.usMsgCmd = Msg_cmd; |
| stMsg.usDataLen = us_DataLen; |
| |
| if (us_DataLen > 0) { |
| memcpy(stMsg.aucDataBuf, pData, us_DataLen); |
| } |
| |
| AGAIN: |
| lRet = msgsnd(lTgtMsgID, &stMsg, msgSize, msgflag); |
| if (lRet < 0) { |
| errNo = errno; |
| if (errNo == EINTR) { |
| goto AGAIN; |
| } |
| if (errNo == EAGAIN) { |
| slog(NET_PRINT, SLOG_ERR, "send_message2 EAGAIN! src=0x%x dst=0x%x msg=0x%x\n",src_id,dst_id,Msg_cmd); |
| goto AGAIN; |
| } |
| slog(NET_PRINT, SLOG_ERR, "send_message failed: msgsnd error code %d, errNo:%d!", lRet, errNo); /*lint !e26*/ |
| if (msgflag != IPC_NOWAIT) { |
| softap_assert("send_message failed: msgsnd error code errNo:%d!", errNo); |
| } |
| return errNo; |
| } |
| return 0; |
| } |
| |
| int send_soc_msg(unsigned short position, int dst_id, unsigned short msg_cmd, unsigned short len, void *msg) |
| { |
| T_Soc_Msg socMsgInfo = {0}; |
| int Msgsize = offsetof(T_Soc_Msg, msg) + len; |
| int ret = -1; |
| |
| if ((len > 0) && (NULL == msg)) { |
| assert(0); |
| return EINVAL; |
| } |
| |
| if (len >= SOC_MSG_MAX_LEN) { |
| assert(0); |
| return EINVAL; |
| } |
| |
| //¿çºË·¢Ë͵½at_ctlµÄÏûÏ¢£¬ÄÚ²¿½øÐÐÈÝ´í |
| switch (dst_id) { |
| case MODULE_ID_AT_CTL: |
| dst_id = MODULE_ID_EXTERNAL_AT_CTL; |
| break; |
| case MODULE_ID_RTC_SERVICE: |
| dst_id = MODULE_ID_EXTERNAL_RTC_SERVICE; |
| break; |
| default: |
| break; |
| } |
| |
| socMsgInfo.position = position; |
| socMsgInfo.targetId = dst_id; |
| socMsgInfo.msg_cmd = msg_cmd; |
| socMsgInfo.len = len; |
| if (len > 0) { |
| memcpy(socMsgInfo.msg, msg, len); |
| } |
| |
| //´Ë´¦½«Ô´Ä£¿éÉèÖÃΪMODULE_ID_AT_CTL£¬socÊÇAT·â×°´¦Àí½Ó¿Ú |
| ret = ipc_send_message(MODULE_ID_AT_CTL, MODULE_ID_AT_CTL, MSG_CMD_SOC_MSG_REQ, Msgsize, &socMsgInfo, 0); |
| if (ret != 0) |
| assert(0); |
| |
| return ret; |
| } |
| |
| /*ƽ̨¼¶ÏûÏ¢·¢Ëͽӿڣ¬ÄÚ²¿Ò»Í³ipc_send_messageºÍsend_soc_msg½Ó¿Ú¡£µ±Ä¿±êÄ£¿éºÍÔ´Ä£¿é²»ÔÚÒ»¸öºËʱ£¬½øÐк˼äÏûÏ¢·¢ËÍ*/ |
| int platform_send_msg(int src_id, int dst_id, unsigned short msg_cmd, unsigned short datalen, unsigned char *pData) |
| { |
| int position; |
| |
| if (datalen >= SOC_MSG_MAX_LEN) { |
| softap_assert("platform_send_msg failed:datalen %d is too big!", datalen); |
| return EINVAL; |
| } |
| |
| if ((datalen > 0) && (NULL == pData)) { |
| softap_assert("platform_send_msg failed:datalen is %d, but pData is NULL!", datalen); |
| return EINVAL; |
| } |
| |
| //䶨ÒåÔ´Ä£¿éID£¬Ôò·Ö±ð¸³¶ÔÓ¦ºËµÄĬÈÏÖµ |
| if (src_id == 0) { |
| #if (APP_OS_TYPE == APP_OS_LINUX) |
| src_id = MODULE_ID_APBASE; |
| #else |
| src_id = MODULE_ID_CPBASE; |
| #endif |
| } |
| |
| if (dst_id == 0) |
| softap_assert("platform_send_msg failed:src_id = %d, dst_id = %d!", src_id, dst_id); |
| |
| //Ô´Ä£¿éIDÓëÄ¿±êÄ£¿éID²»ÔÚÒ»¸öºËÄÚ£¬Ôò×é×°²¢·¢Ëͺ˼äÏûÏ¢ |
| if (((src_id & MODULE_ID_APBASE) != (dst_id & MODULE_ID_APBASE)) && ((src_id & MODULE_ID_CPBASE) != (dst_id & MODULE_ID_CPBASE))) { |
| int msglen = offsetof(T_Soc_Msg, msg) + datalen; |
| int ret = -1; |
| T_Soc_Msg socMsgInfo = {0}; |
| |
| //¼ì²âsrc_id,dst_idÊÇ·ñÂú×ãºË¼äͨѶµÄÌõ¼þ |
| if (0 == soc_send_condition_check(src_id, dst_id)) |
| softap_assert("platform_send_msg failed: confition check failed, src_id = %d, dst_id = %d!", src_id, dst_id); |
| |
| position = (dst_id & MODULE_ID_APBASE) ? FAR_PS : NEAR_PS; |
| |
| socMsgInfo.position = position; |
| socMsgInfo.srcId = src_id; |
| socMsgInfo.targetId = dst_id; |
| socMsgInfo.msg_cmd = msg_cmd; |
| socMsgInfo.len = datalen; |
| if (datalen > 0) { |
| memcpy(socMsgInfo.msg, pData, datalen); |
| } |
| |
| ret = ipc_send_message(src_id, MODULE_ID_AT_CTL, MSG_CMD_SOC_MSG_REQ, msglen, &socMsgInfo, 0); |
| if (ret != 0) //·¢Ë͵½at_ctlµÄÏûÏ¢²»ÔÊÐí·¢ËÍʧ°Ü |
| softap_assert("platform_send_msg failed: ipc_send_message MSG_CMD_SOC_MSG_REQ errNo:%d!", errno); |
| return ret; |
| } else { |
| //ºËÄÚÏûÏ¢´æÔÚÒòÄ¿±êÏûÏ¢¶ÓÁл¹Î´´´½¨µ¼Ö·¢ËÍʧ°ÜµÄÇé¿ö£¬¹Ê¸Ã´¦²»¶ÏÑÔ |
| return ipc_send_message(src_id, dst_id, msg_cmd, datalen, pData, 0); |
| } |
| } |
| |
| int poweroff_request(int src_id) |
| { |
| return platform_send_msg(src_id, MODULE_ID_MAIN_CTRL, MSG_CMD_POWEROFF_REQUEST, 0, NULL); |
| } |
| |
| int restart_request(int src_id) |
| { |
| return platform_send_msg(src_id, MODULE_ID_MAIN_CTRL, MSG_CMD_RESTART_REQUEST, 0, NULL); |
| } |
| |
| int reset_request(int src_id) |
| { |
| return platform_send_msg(src_id, MODULE_ID_MAIN_CTRL, MSG_CMD_RESET_REQUEST, 0, NULL); |
| } |
| |
| typedef struct system_cmd_proc |
| { |
| const char * str; |
| int (* proc)(const char * cmd, const char * str); |
| } |
| system_cmd_proc_t; |
| |
| //awkÌ«¸´ÔÓ£¬¾ßÌåÎÊÌâ¾ßÌå·ÖÎö |
| //·Ö¸ô·û|ºóÃæ¿ÉÒÔ´æÔÚµÄÃüÁ´ýÍêÉÆ |
| const static const char * separator_whitelist[]={ |
| "grep ","sort ","head " |
| }; |
| |
| //·µ»Ø×Ö·û´®¼°ÒÔǰµÄ³¤¶È£¬Ã»ÓÐÕÒµ½·µ»Ø0 |
| static int system_cmd_used_curr(const char * cmd, const char * str) |
| { |
| char *tmp_str = NULL; |
| tmp_str = strstr(cmd, str); |
| if(tmp_str) |
| { |
| int len = tmp_str - cmd + strlen(str); |
| tmp_str = tmp_str + strlen(str); |
| while((*tmp_str)!='\0' && (*tmp_str)==' ') |
| { |
| tmp_str++; |
| } |
| if((*tmp_str) == '\0' || (*(tmp_str+1)) == '\0') |
| {//¹æ±Ü2>&1 |
| return 0; |
| } |
| return len; |
| } |
| else |
| return 0; |
| } |
| |
| //·µ»Ø³ý×Ö·û´®ÒÔǰµÄ³¤¶È£¬Ã»ÓÐÕÒµ½·µ»Ø0 |
| static int system_cmd_used_before(const char * cmd, const char * str) |
| { |
| char *tmp_str = NULL; |
| tmp_str = strstr(cmd, str); |
| if(tmp_str) |
| return tmp_str -cmd; |
| else |
| return 0; |
| } |
| |
| //¶Ô·Ö¸ô·û|µÄÌØÊâ´¦Àí£¬Ã»ÓÐÕÒµ½»òÔÊÐíÖ´Ðзµ»Ø0 |
| static int system_cmd_separator_proc(const char * cmd, const char * str) |
| { |
| char *tmp_str = NULL; |
| tmp_str = strstr(cmd, str); |
| if(tmp_str) |
| { |
| int i = 0; |
| int len = tmp_str -cmd; |
| tmp_str = tmp_str + strlen(str); |
| while((*tmp_str)!='\0' && (*tmp_str)==' ') |
| { |
| tmp_str++; |
| } |
| for(i = 0; i < sizeof(separator_whitelist) / sizeof(const char *); i++) |
| { |
| if(strncmp(tmp_str, separator_whitelist[i], strlen(separator_whitelist[i])) == 0) |
| { |
| return 0; |
| } |
| } |
| return len; |
| } |
| else |
| return 0; |
| } |
| |
| const static system_cmd_proc_t system_chack[]={ |
| {"&",system_cmd_used_curr}, |
| {"|",system_cmd_separator_proc}, |
| {";",system_cmd_used_before}, |
| {"\r",system_cmd_used_before}, |
| {"\n",system_cmd_used_before} |
| }; |
| |
| int soft_system(const char *command) |
| { |
| int i = 0; |
| int flag = 0; |
| int len = strlen(command); |
| |
| for(i = 0; i < sizeof(system_chack) / sizeof(system_cmd_proc_t); i++) |
| { |
| int offset = system_chack[i].proc(command,system_chack[i].str); |
| if(offset != 0 && offset < len) |
| { |
| len = offset; |
| flag = 1; |
| } |
| } |
| if(flag && len > 0 && len < strlen(command)) |
| { |
| char *cmd = (char *)malloc(len+1); |
| int ret = 0; |
| if(cmd == NULL) |
| { |
| slog(NET_PRINT, SLOG_ERR, "@system@ malloc fail!\n"); |
| return -1; |
| } |
| memset(cmd, 0, len+1); |
| strncpy(cmd, command, len); |
| slog(NET_PRINT, SLOG_ERR, "@system@ %s is inject!\n",command); |
| ret = system(cmd); |
| slog(NET_PRINT, SLOG_ERR, "@system@ %s is now,ret=%d!\n",cmd,ret); |
| free(cmd); |
| return ret; |
| } |
| else |
| return system(command); |
| } |
| |
| long get_sys_uptime() |
| { |
| struct sysinfo info; |
| if(sysinfo(&info)) |
| { |
| printf("Failed to get sysinfo failed\n"); |
| return -1; |
| } |
| |
| return info.uptime; |
| } |
| |
| |