size_t connection_read_data_msg(struct connection *conn, void *buffer, uint32_t len) { size_t ret = -1; MCDRV_DBG_VERBOSE("reading connection data %u, connection data left %u", len, conn->data_len); /* trying to read more than the left data */ if (len > conn->data_len) { ret = conn->data_len; memcpy(buffer, conn->data_start, conn->data_len); conn->data_len = 0; } else { ret = len; memcpy(buffer, conn->data_start, len); conn->data_len -= len; conn->data_start += len; } if (conn->data_len == 0) { conn->data_start = NULL; kfree_skb(conn->skb); conn->skb = NULL; } MCDRV_DBG_VERBOSE("read %u", ret); return ret; }
int mc_info(uint32_t ext_info_id, uint32_t *state, uint32_t *ext_info) { int ret = 0; union mc_fc_info fc_info; MCDRV_DBG_VERBOSE(mcd, "enter\n"); memset(&fc_info, 0, sizeof(fc_info)); fc_info.as_in.cmd = MC_FC_INFO; fc_info.as_in.ext_info_id = ext_info_id; MCDRV_DBG(mcd, "fc_info <- cmd=0x%08x, ext_info_id=0x%08x\n", fc_info.as_in.cmd, fc_info.as_in.ext_info_id); mc_fastcall(&(fc_info.as_generic)); MCDRV_DBG(mcd, "fc_info -> r=0x%08x ret=0x%08x state=0x%08x ext_info=0x%08x", fc_info.as_out.resp, fc_info.as_out.ret, fc_info.as_out.state, fc_info.as_out.ext_info); ret = convert_fc_ret(fc_info.as_out.ret); *state = fc_info.as_out.state; *ext_info = fc_info.as_out.ext_info; MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; }
size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len, int32_t timeout) { size_t ret = 0; MCDRV_ASSERT(buffer != NULL); MCDRV_ASSERT(conn->socket_descriptor != NULL); MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u", len, conn->sequence_magic); do { /* * Wait until data is available or timeout * msecs_to_jiffies(-1) -> wait forever for the sem */ if (down_timeout(&(conn->data_available_sem), msecs_to_jiffies(timeout))) { MCDRV_DBG_VERBOSE(mc_kapi, "Timeout reading the data sem"); ret = -2; break; } /*################################## #mobicore_security_team_add ##################################*/ /*if (mutex_lock_interruptible(&(conn->data_lock))) { MCDRV_DBG_ERROR(mc_kapi, "interrupted reading the data sem"); ret = -1; break; }*/ mutex_lock(&(conn->data_lock)); /*##################################*/ /* Have data, use it */ if (conn->data_len > 0) ret = connection_read_data_msg(conn, buffer, len); mutex_unlock(&(conn->data_lock)); /* There is still some data left */ if (conn->data_len > 0) up(&conn->data_available_sem); } while (0); return ret; }
size_t connection_write_data(struct connection *conn, void *buffer, uint32_t len) { struct sk_buff *skb = NULL; struct nlmsghdr *nlh; int ret = 0; MCDRV_DBG_VERBOSE("buffer length %u from pid %u\n", len, conn->sequence_magic); do { skb = nlmsg_new(NLMSG_SPACE(len), GFP_KERNEL); if (!skb) { ret = -1; break; } nlh = nlmsg_put(skb, 0, conn->sequence_magic, 2, NLMSG_LENGTH(len), NLM_F_REQUEST); if (!nlh) { ret = -1; break; } memcpy(NLMSG_DATA(nlh), buffer, len); netlink_unicast(conn->socket_descriptor, skb, conn->peer_pid, MSG_DONTWAIT); ret = len; } while (0); if (!ret && skb != NULL) kfree_skb(skb); return ret; }
size_t connection_read_data(struct connection *conn, void *buffer, uint32_t len, int32_t timeout) { size_t ret = 0; MCDRV_ASSERT(buffer != NULL); MCDRV_ASSERT(conn->socket_descriptor != NULL); MCDRV_DBG_VERBOSE(mc_kapi, "read data len = %u for PID = %u", len, conn->sequence_magic); do { if (down_timeout(&(conn->data_available_sem), msecs_to_jiffies(timeout))) { MCDRV_DBG_VERBOSE(mc_kapi, "Timeout reading the data sem"); ret = -2; break; } if (mutex_lock_interruptible(&(conn->data_lock))) { MCDRV_DBG_ERROR(mc_kapi, "interrupted reading the data sem"); ret = -1; break; } if (conn->data_len > 0) ret = connection_read_data_msg(conn, buffer, len); mutex_unlock(&(conn->data_lock)); if (conn->data_len > 0) up(&conn->data_available_sem); } while (0); return ret; }
/* call common notify */ int mc_nsiq(void) { int ret = 0; union fc_generic nsiq; MCDRV_DBG_VERBOSE(mcd, "enter\n"); memset(&nsiq, 0, sizeof(nsiq)); nsiq.as_in.cmd = MC_SMC_N_SIQ; mc_fastcall(&nsiq); ret = convert_fc_ret(nsiq.as_out.ret); return ret; }
/* Call the INIT fastcall to setup MobiCore initialization */ int mc_init(uint32_t base, uint32_t nq_offset, uint32_t nq_length, uint32_t mcp_offset, uint32_t mcp_length) { int ret = 0; union mc_fc_init fc_init; MCDRV_DBG_VERBOSE(mcd, "enter\n"); memset(&fc_init, 0, sizeof(fc_init)); fc_init.as_in.cmd = MC_FC_INIT; /* base address of mci buffer 4KB aligned */ fc_init.as_in.base = base; /* notification buffer start/length [16:16] [start, length] */ fc_init.as_in.nq_info = (nq_offset << 16) | (nq_length & 0xFFFF); /* mcp buffer start/length [16:16] [start, length] */ fc_init.as_in.mcp_info = (mcp_offset << 16) | (mcp_length & 0xFFFF); /* * Set KMOD notification queue to start of MCI * mciInfo was already set up in mmap */ MCDRV_DBG(mcd, "cmd=0x%08x, base=0x%08x,nq_info=0x%08x, mcp_info=0x%08x\n", fc_init.as_in.cmd, fc_init.as_in.base, fc_init.as_in.nq_info, fc_init.as_in.mcp_info); mc_fastcall(&fc_init.as_generic); MCDRV_DBG(mcd, "out cmd=0x%08x, ret=0x%08x\n", fc_init.as_out.resp, fc_init.as_out.ret); ret = convert_fc_ret(fc_init.as_out.ret); MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X\n", ret, ret); return ret; }
/* Yield to MobiCore */ int mc_yield(void) { int ret = 0; union fc_generic yield; MCDRV_DBG_VERBOSE(mcd, "enter\n"); memset(&yield, 0, sizeof(yield)); yield.as_in.cmd = MC_SMC_N_YIELD; mc_fastcall(&yield); ret = convert_fc_ret(yield.as_out.ret); return ret; }