Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +34 −0 Original line number Diff line number Diff line Loading @@ -1003,6 +1003,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_get_vlan_mode vlan_mode; struct ipa_ioc_wigig_fst_switch fst_switch; struct ipa_nat_in_sram_info nat_in_sram_info; union ipa_ioc_uc_activation_entry uc_act; size_t sz; int pre_entry; int hdl; Loading Loading @@ -3052,6 +3053,39 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_ADD_UC_ACT_ENTRY: if (copy_from_user(&uc_act, (const void __user *)arg, sizeof(union ipa_ioc_uc_activation_entry))) { IPAERR_RL("copy_from_user fails\n"); retval = -EFAULT; break; } /* first field in both structs is cmd id */ if (uc_act.socks.cmd_id == IPA_SOCKSV5_ADD_COM_ID) { retval = ipa3_add_socksv5_conn_usr(&uc_act.socks); } else { retval = ipa3_add_ipv6_nat_uc_activation_entry( &uc_act.ipv6_nat); } if (retval) { retval = -EFAULT; break; } if (copy_to_user((void __user *)arg, &uc_act, sizeof(union ipa_ioc_uc_activation_entry))) { IPAERR_RL("copy_to_user fails\n"); retval = -EFAULT; break; } break; case IPA_IOC_DEL_UC_ACT_ENTRY: if (ipa3_del_uc_act_entry((uint16_t)arg)) { retval = -EFAULT; break; } break; default: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return -ENOTTY; Loading drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +127 −4 Original line number Diff line number Diff line Loading @@ -2646,6 +2646,125 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, return count; } static ssize_t ipa3_read_uc_act_tbl(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { int nbytes; int cnt = 0; int i; struct ipa_ipv6_nat_uc_tmpl *uc_entry_nat; struct ipa_socksv5_uc_tmpl *uc_entry_socks; struct iphdr_rsv *socks_iphdr; struct ipv6hdr *socks_ipv6hdr; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; goto done; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR("uC act tbl wasn't allocated\n"); return -ENOENT; } if (sizeof(dbg_buff) < count + 1) return -EFAULT; dbg_buff[count] = '\0'; mutex_lock(&ipa3_ctx->act_tbl_lock); uc_entry_nat = (struct ipa_ipv6_nat_uc_tmpl *) (ipa3_ctx->uc_act_tbl.base); nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "uc_act_tbl_total %d, uc_act_tbl_ipv6_nat_total %d uc_act_tbl_socksv5_total %d, uc_act_tbl_next_index %d\n" "uC activation entries:" , ipa3_ctx->uc_act_tbl_total, ipa3_ctx->uc_act_tbl_ipv6_nat_total, ipa3_ctx->uc_act_tbl_socksv5_total, ipa3_ctx->uc_act_tbl_next_index); cnt += nbytes; for (i = 0; i < IPA_UC_ACT_TBL_SIZE; i++) { if (uc_entry_nat[i].cmd_id == IPA_IPv6_NAT_COM_ID) { nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "\nentry %d:\n" "cmd_id = IPV6_NAT\n" "private_address_msb 0x%llX\n" "private_address_lsb 0x%llX\n" "private_port %u\n" "public_address_msb 0x%llX\n" "public_address_lsb 0x%llX\n" "public_port %u\n", i, uc_entry_nat[i].private_address_msb, uc_entry_nat[i].private_address_lsb, uc_entry_nat[i].private_port, uc_entry_nat[i].public_address_msb, uc_entry_nat[i].public_address_lsb, uc_entry_nat[i].public_port); cnt += nbytes; } else if (uc_entry_nat[i].cmd_id == IPA_SOCKSV5_ADD_COM_ID) { uc_entry_socks = (struct ipa_socksv5_uc_tmpl *) (uc_entry_nat); nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "\nentry %d:\n" "cmd_id = SOCKSv5\n" "cmd_param: %u\n" "source_port: %u\n" "dest_port: %u\n" "ipa_socksv5_mask: %x\n", i, uc_entry_socks[i].cmd_param, uc_entry_socks[i].src_port, uc_entry_socks[i].dst_port, uc_entry_socks[i].ipa_sockv5_mask); cnt += nbytes; if (uc_entry_socks[i].cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) { socks_iphdr = &uc_entry_socks[i].ip_hdr.ipv4_rsv; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "ipv4_src_addr: 0x%X\n" "ipv4_dst_addr: 0x%X\n", socks_iphdr->ipv4_temp.saddr, socks_iphdr->ipv4_temp.daddr); cnt += nbytes; } else { socks_ipv6hdr = &uc_entry_socks[i].ip_hdr.ipv6_temp; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "ipv6_src_addr[0]: 0x%X\n" "ipv6_src_addr[1]: 0x%X\n" "ipv6_src_addr[2]: 0x%X\n" "ipv6_src_addr[3]: 0x%X\n" "ipv6_dts_addr[0]: 0x%X\n" "ipv6_dts_addr[1]: 0x%X\n" "ipv6_dts_addr[2]: 0x%X\n" "ipv6_dts_addr[3]: 0x%X\n", socks_ipv6hdr->saddr.s6_addr32[0], socks_ipv6hdr->saddr.s6_addr32[1], socks_ipv6hdr->saddr.s6_addr32[2], socks_ipv6hdr->saddr.s6_addr32[3], socks_ipv6hdr->daddr.s6_addr32[0], socks_ipv6hdr->daddr.s6_addr32[1], socks_ipv6hdr->daddr.s6_addr32[2], socks_ipv6hdr->daddr.s6_addr32[3]); cnt += nbytes; } } } mutex_unlock(&ipa3_ctx->act_tbl_lock); done: return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } static const struct ipa3_debugfs_file debugfs_files[] = { { "gen_reg", IPA_READ_ONLY_MODE, NULL, { Loading Loading @@ -2811,7 +2930,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_app_clk_vote, } }, }, { "uc_act_table", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_uc_act_tbl, } } }; void ipa3_debugfs_pre_init(void) Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +11 −0 Original line number Diff line number Diff line Loading @@ -2022,6 +2022,8 @@ struct ipa3_context { bool uc_act_tbl_valid; struct mutex act_tbl_lock; int uc_act_tbl_total; int uc_act_tbl_socksv5_total; int uc_act_tbl_ipv6_nat_total; int uc_act_tbl_next_index; bool manual_fw_load; }; Loading Loading @@ -2419,6 +2421,15 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info); int ipa3_del_socksv5_conn(uint32_t handle); int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl); int ipa3_add_ipv6_nat_uc_activation_entry( struct ipa_ioc_ipv6_nat_uc_act_entry *entry); int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index); int ipa3_del_uc_act_entry(uint16_t index); /* * Header removal / addition */ Loading drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +409 −53 Original line number Diff line number Diff line Loading @@ -9150,6 +9150,213 @@ int ipa3_setup_uc_act_tbl(void) return res; } static inline bool is_free_socksv5(struct ipa_socksv5_uc_tmpl *socksv5_entry) { if ((!socksv5_entry->cmd_id) || (socksv5_entry->cmd_id == IPA_SOCKsv5_ADD_COM_ID && !(socksv5_entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID))) return true; return false; } static int ipa3_get_free_uc_act_entry(void) { struct ipa_socksv5_uc_tmpl *entry; int orig_index = ipa3_ctx->uc_act_tbl_next_index; int free_index = -1; IPADBG("\n"); /* find a free spot*/ do { entry = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); /* check if entry is free */ if (is_free_socksv5(entry)) { free_index = ipa3_ctx->uc_act_tbl_next_index; IPADBG("found free index at %d\n", free_index); break; } ipa3_ctx->uc_act_tbl_next_index++; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); IPADBG("exit free_index %d\n", free_index); return free_index; } int ipa3_add_ipv6_nat_uc_activation_entry( struct ipa_ioc_ipv6_nat_uc_act_entry *entry) { int res = 0; int index; struct ipa_ipv6_nat_uc_tmpl *uc_entry; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR("uC act tbl wasn't allocated\n"); return -ENOENT; } if (!entry) { IPAERR("Null entry\n"); return -EIO; } if (!entry->private_address_lsb || !entry->private_address_msb || !entry->public_address_lsb || !entry->public_address_msb || !entry->private_port || !entry->public_port) { IPAERR("0 param 0x%llX 0x%llX 0x%llX 0x%llX %d %d\n", entry->private_address_lsb, entry->private_address_msb, entry->public_address_lsb, entry->public_address_msb, entry->private_port, entry->public_port); return -EFAULT; } mutex_lock(&ipa3_ctx->act_tbl_lock); /* check the left # of entries */ if (ipa3_ctx->uc_act_tbl_total >= IPA_UC_ACT_TBL_SIZE) { IPAERR("uc act tbl is full!\n"); res = -EFAULT; goto error; } index = ipa3_get_free_uc_act_entry(); uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); uc_entry->private_address_lsb = entry->private_address_lsb; uc_entry->private_address_msb = entry->private_address_msb; uc_entry->public_address_lsb = entry->public_address_lsb; uc_entry->public_address_msb = entry->public_address_msb; uc_entry->private_port = entry->private_port; uc_entry->public_port = entry->public_port; uc_entry->cmd_id = IPA_IPv6_NAT_COM_ID; /* set output index */ entry->index = (uint16_t)index; ipa3_ctx->uc_act_tbl_total++; ipa3_ctx->uc_act_tbl_ipv6_nat_total++; if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { /* * find next free spot, this function shall update * uc_act_tbl_next_index */ index = ipa3_get_free_uc_act_entry(); if (index < 0) { /* set to max tbl size to debug */ IPAERR("can't find available spot!\n"); ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; res = -EFAULT; } } error: mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } int ipa3_del_uc_act_entry(uint16_t index) { struct ipa_ipv6_nat_uc_tmpl *uc_entry; uint16_t cmd_id; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR_RL("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR_RL("uC act tbl haven't allocated\n"); return -ENOENT; } if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { IPAERR_RL("invalid index!\n"); return -EINVAL; } if (!ipa3_ctx->uc_act_tbl_total) { IPAERR_RL( "invalid handle, no uc activation entries in table (total %d)\n" , ipa3_ctx->uc_act_tbl_total); return -EINVAL; } uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); mutex_lock(&ipa3_ctx->act_tbl_lock); cmd_id = uc_entry->cmd_id; mutex_unlock(&ipa3_ctx->act_tbl_lock); if (cmd_id == IPA_IPv6_NAT_COM_ID) return ipa3_del_ipv6_nat_uc_activation_entry(index); else return ipa3_del_socksv5_conn(index); } int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index) { struct ipa_ipv6_nat_uc_tmpl *uc_entry; int res = 0; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR_RL("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR_RL("uC act tbl haven't allocated\n"); return -ENOENT; } if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { IPAERR_RL("invalid index!\n"); return -EINVAL; } if (!ipa3_ctx->uc_act_tbl_ipv6_nat_total) { IPAERR_RL( "invalid handle, no IPv6 NAT entries in table (total %d)\n" , ipa3_ctx->uc_act_tbl_total); return -EINVAL; } uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); mutex_lock(&ipa3_ctx->act_tbl_lock); if (uc_entry->cmd_id != IPA_IPv6_NAT_COM_ID) { IPAERR_RL("entry %d wrong cmd id %d\n", uc_entry->cmd_id); res = -EFAULT; goto error; } uc_entry->cmd_id = 0; ipa3_ctx->uc_act_tbl_total--; ipa3_ctx->uc_act_tbl_ipv6_nat_total--; IPADBG("free entry %d, nat total %d, left total %d\n", index, ipa3_ctx->uc_act_tbl_ipv6_nat_total, ipa3_ctx->uc_act_tbl_total); error: mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) { if (!buff) { Loading @@ -9167,6 +9374,39 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } static int ipa3_get_free_socksv5_entry(void) { struct ipa_socksv5_uc_tmpl *first; struct ipa_socksv5_uc_tmpl *next; int orig_index = ipa3_ctx->uc_act_tbl_next_index; int free_index = -1; IPADBG("\n"); /* find a free spot with two contiguous entries*/ do { first = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); next = ipa3_ctx->uc_act_tbl.base + (ipa3_ctx->uc_act_tbl_next_index + 1) * sizeof(struct ipa_socksv5_uc_tmpl); /* check if first entry and next entry are free */ if (is_free_socksv5(first) && is_free_socksv5(next)) { free_index = ipa3_ctx->uc_act_tbl_next_index; IPADBG("found free index at %d\n", free_index); break; } ipa3_ctx->uc_act_tbl_next_index += 2; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); IPADBG("exit free_index %d\n", free_index); return free_index; } /** * ipa3_add_socksv5_conn() - IPA add socksv5_conn * Loading @@ -9176,8 +9416,8 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) */ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) { int res = 0; void *rp_va, *wp_va; int res = 0, index; void *wp_va; struct ipa_socksv5_msg *socksv5_msg; struct ipa_msg_meta msg_meta; Loading @@ -9198,18 +9438,24 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) } mutex_lock(&ipa3_ctx->act_tbl_lock); /* check the left # of entries */ /* check the left # of entries (need at least 2)*/ if (ipa3_ctx->uc_act_tbl_total >= IPA_UC_ACT_TBL_SIZE) { >= IPA_UC_ACT_TBL_SIZE - 1) { IPAERR("uc act tbl is full!\n"); res = -EFAULT; goto error; } index = ipa3_get_free_socksv5_entry(); if (index < 0) { IPAERR("couldn't find free socksv5 entry\n"); res = -EFAULT; goto error; } /* Copied the act-info to tbl */ wp_va = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); index * sizeof(struct ipa_socksv5_uc_tmpl); /* check entry valid */ if ((info->ul_out.cmd_id != IPA_SOCKsv5_ADD_COM_ID) Loading Loading @@ -9246,9 +9492,10 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) &(info->dl_out), sizeof(info->dl_out)); /* set output handle */ info->handle = (uint16_t) ipa3_ctx->uc_act_tbl_next_index; info->handle = (uint16_t) index; ipa3_ctx->uc_act_tbl_total += 2; ipa3_ctx->uc_act_tbl_socksv5_total += 2; /* send msg to ipacm */ socksv5_msg = kzalloc(sizeof(*socksv5_msg), GFP_KERNEL); Loading @@ -9261,9 +9508,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) memcpy(&(socksv5_msg->dl_in), &(info->dl_in), sizeof(info->dl_in)); socksv5_msg->handle = info->handle; socksv5_msg->ul_in.index = (uint16_t) ipa3_ctx->uc_act_tbl_next_index; (uint16_t) index; socksv5_msg->dl_in.index = (uint16_t) ipa3_ctx->uc_act_tbl_next_index + 1; (uint16_t) index + 1; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = IPA_SOCKV5_ADD; Loading @@ -9276,27 +9523,14 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) goto error; } if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { /* find next free spot */ do { ipa3_ctx->uc_act_tbl_next_index += 2; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; rp_va = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { IPADBG("next available entry %d, total %d\n", ipa3_ctx->uc_act_tbl_next_index, ipa3_ctx->uc_act_tbl_total); break; } } while (rp_va != wp_va); if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE - 1) { /* * find next free spot, this function shall update * uc_act_tbl_next_index */ index = ipa3_get_free_socksv5_entry(); if (rp_va == wp_va) { if (index < 0) { /* set to max tbl size to debug */ IPAERR("can't find available spot!\n"); ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; Loading @@ -9308,6 +9542,127 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } /* * ipa3_add_socksv5_conn_usr() - IPA copy and add socksv5 conn * * Returns: 0 on success, negative on failure * * Note : Should not be called from atomic context */ int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl) { struct ipa_socksv5_info info; int retval = 0; memset(&info, 0, sizeof(struct ipa_socksv5_info)); if (tmpl->direction == 0) { /* DL */ info.dl_out.cmd_id = tmpl->cmd_id; info.dl_out.cmd_param = tmpl->cmd_param; info.dl_out.ip_hdr.ipv6_temp.version = 6; info.dl_out.ip_hdr.ipv6_temp.nexthdr = 6; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = tmpl->ipv6_src_addr[0]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = tmpl->ipv6_src_addr[1]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = tmpl->ipv6_src_addr[2]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = tmpl->ipv6_src_addr[3]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = tmpl->ipv6_dst_addr[0]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = tmpl->ipv6_dst_addr[1]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = tmpl->ipv6_dst_addr[2]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = tmpl->ipv6_dst_addr[3]; info.dl_out.src_port = tmpl->src_port; info.dl_out.dst_port = tmpl->dst_port; info.dl_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; info.dl_out.out_irs = tmpl->out_irs; info.dl_out.out_iss = tmpl->out_iss; info.dl_out.in_irs = tmpl->in_irs; info.dl_out.in_iss = tmpl->in_iss; info.dl_out.out_ircv_tsval = tmpl->out_ircv_tsval; info.dl_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; info.dl_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; info.dl_out.in_ircv_tsval = tmpl->in_ircv_tsval; info.dl_out.in_isnd_wscale = tmpl->in_isnd_wscale; info.dl_out.out_isnd_wscale = tmpl->out_isnd_wscale; info.dl_out.in_ircv_wscale = tmpl->in_ircv_wscale; info.dl_out.out_ircv_wscale = tmpl->out_ircv_wscale; /* for UL set default values to pass pair validity check */ info.ul_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; info.ul_out.cmd_param = IPA_SOCKsv5_ADD_V6_V4_COM_PM; } else if (tmpl->direction == 1) { /* UL */ info.ul_out.cmd_id = tmpl->cmd_id; info.ul_out.cmd_param = tmpl->cmd_param; if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) { info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.version = 4; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.ihl = 5; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.saddr = tmpl->ip_src_addr; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.daddr = tmpl->ip_dst_addr; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.protocol = 6; } if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V6_COM_PM) { info.ul_out.ip_hdr.ipv6_temp.version = 6; info.ul_out.ip_hdr.ipv6_temp.nexthdr = 6; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = tmpl->ipv6_src_addr[0]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = tmpl->ipv6_src_addr[1]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = tmpl->ipv6_src_addr[2]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = tmpl->ipv6_src_addr[3]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = tmpl->ipv6_dst_addr[0]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = tmpl->ipv6_dst_addr[1]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = tmpl->ipv6_dst_addr[2]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = tmpl->ipv6_dst_addr[3]; } info.ul_out.src_port = tmpl->src_port; info.ul_out.dst_port = tmpl->dst_port; info.ul_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; info.ul_out.out_irs = tmpl->out_irs; info.ul_out.out_iss = tmpl->out_iss; info.ul_out.in_irs = tmpl->in_irs; info.ul_out.in_iss = tmpl->in_iss; info.ul_out.out_ircv_tsval = tmpl->out_ircv_tsval; info.ul_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; info.ul_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; info.ul_out.in_ircv_tsval = tmpl->in_ircv_tsval; info.ul_out.in_isnd_wscale = tmpl->in_isnd_wscale; info.ul_out.out_isnd_wscale = tmpl->out_isnd_wscale; info.ul_out.in_ircv_wscale = tmpl->in_ircv_wscale; info.ul_out.out_ircv_wscale = tmpl->out_ircv_wscale; /* for DL set default values to pass pair validity check */ info.dl_out.cmd_param = IPA_SOCKsv5_ADD_V4_V6_COM_PM; info.dl_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; } else { IPAERR("invalid socksv5 direction: %d\n", tmpl->direction); return -EINVAL; } retval = ipa3_add_socksv5_conn(&info); if (retval) { IPAERR("ipa3_add_socksv5_conn failed retval: %d\n", retval); return retval; } /* save uc handle */ tmpl->handle = info.handle; return retval; } /** * ipa3_del_socksv5_conn() - IPA add socksv5_conn Loading @@ -9319,9 +9674,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) int ipa3_del_socksv5_conn(uint32_t handle) { int res = 0; void *rp_va; uint32_t *socksv5_handle; struct ipa_msg_meta msg_meta; struct ipa_socksv5_uc_tmpl *entry, *next; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { Loading @@ -9339,43 +9694,44 @@ int ipa3_del_socksv5_conn(uint32_t handle) return -EINVAL; } if ((handle % 2) != 0) { IPAERR("invalid handle!\n"); if (ipa3_ctx->uc_act_tbl_socksv5_total < 2) { IPAERR("invalid handle, tbl doesn't have socksv5 entries!\n"); return -EINVAL; } if (ipa3_ctx->uc_act_tbl_total < 2) { IPAERR("invalid handle, all tbl is empty!\n"); return -EINVAL; } rp_va = ipa3_ctx->uc_act_tbl.base + handle * sizeof(struct ipa_socksv5_uc_tmpl); entry = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + handle * sizeof(struct ipa_socksv5_uc_tmpl)); next = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + (handle + 1) * sizeof(struct ipa_socksv5_uc_tmpl)); /* check entry is valid or not */ mutex_lock(&ipa3_ctx->act_tbl_lock); if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { IPADBG(" entry %d already free\n", handle); if (entry->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { IPAERR(" entry %d not socksv5\n", handle); res = -EINVAL; goto error; } if (next->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { IPAERR(" entry %d not socksv5\n", handle + 1); res = -EINVAL; goto error; } if (!(entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) IPADBG(" entry %d already free\n", handle); if (!((((struct ipa_socksv5_uc_tmpl *) (rp_va + sizeof(struct ipa_socksv5_uc_tmpl)))-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { if (!(next->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) IPADBG(" entry %d already free\n", handle); } ((struct ipa_socksv5_uc_tmpl *) rp_va)->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; ((struct ipa_socksv5_uc_tmpl *) (rp_va + sizeof(struct ipa_socksv5_uc_tmpl)))->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; entry->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; next->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; ipa3_ctx->uc_act_tbl_total -= 2; ipa3_ctx->uc_act_tbl_socksv5_total -= 2; IPADBG("free entry %d and %d, left total %d\n", IPADBG("free entry %d and %d, left total %d, socksv5 total %d\n", handle, handle + 1, ipa3_ctx->uc_act_tbl_total); ipa3_ctx->uc_act_tbl_total, ipa3_ctx->uc_act_tbl_socksv5_total); /* send msg to ipacm */ socksv5_handle = kzalloc(sizeof(*socksv5_handle), GFP_KERNEL); Loading include/linux/ipa.h +27 −1 Original line number Diff line number Diff line Loading @@ -1423,9 +1423,35 @@ struct ipa_socksv5_info { struct ipacm_socksv5_info dl_in; /* output: handle (index) */ uint32_t handle; uint16_t handle; }; struct ipa_ipv6_nat_uc_tmpl { uint16_t cmd_id; uint16_t rsv; uint32_t cmd_param; uint16_t pkt_count; uint16_t rsv2; uint32_t byte_count; uint64_t private_address_lsb; uint64_t private_address_msb; uint64_t public_address_lsb; uint64_t public_address_msb; uint16_t private_port; uint16_t public_port; uint32_t rsv3; uint64_t rsv4; uint64_t rsv5; uint64_t rsv6; uint64_t rsv7; uint64_t rsv8; uint64_t rsv9; uint64_t rsv10; uint64_t rsv11; uint64_t rsv12; } __packed; #if defined CONFIG_IPA || defined CONFIG_IPA3 Loading Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +34 −0 Original line number Diff line number Diff line Loading @@ -1003,6 +1003,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_get_vlan_mode vlan_mode; struct ipa_ioc_wigig_fst_switch fst_switch; struct ipa_nat_in_sram_info nat_in_sram_info; union ipa_ioc_uc_activation_entry uc_act; size_t sz; int pre_entry; int hdl; Loading Loading @@ -3052,6 +3053,39 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_ADD_UC_ACT_ENTRY: if (copy_from_user(&uc_act, (const void __user *)arg, sizeof(union ipa_ioc_uc_activation_entry))) { IPAERR_RL("copy_from_user fails\n"); retval = -EFAULT; break; } /* first field in both structs is cmd id */ if (uc_act.socks.cmd_id == IPA_SOCKSV5_ADD_COM_ID) { retval = ipa3_add_socksv5_conn_usr(&uc_act.socks); } else { retval = ipa3_add_ipv6_nat_uc_activation_entry( &uc_act.ipv6_nat); } if (retval) { retval = -EFAULT; break; } if (copy_to_user((void __user *)arg, &uc_act, sizeof(union ipa_ioc_uc_activation_entry))) { IPAERR_RL("copy_to_user fails\n"); retval = -EFAULT; break; } break; case IPA_IOC_DEL_UC_ACT_ENTRY: if (ipa3_del_uc_act_entry((uint16_t)arg)) { retval = -EFAULT; break; } break; default: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return -ENOTTY; Loading
drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +127 −4 Original line number Diff line number Diff line Loading @@ -2646,6 +2646,125 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, return count; } static ssize_t ipa3_read_uc_act_tbl(struct file *file, char __user *ubuf, size_t count, loff_t *ppos) { int nbytes; int cnt = 0; int i; struct ipa_ipv6_nat_uc_tmpl *uc_entry_nat; struct ipa_socksv5_uc_tmpl *uc_entry_socks; struct iphdr_rsv *socks_iphdr; struct ipv6hdr *socks_ipv6hdr; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "This feature only support on IPA4.5+\n"); cnt += nbytes; goto done; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR("uC act tbl wasn't allocated\n"); return -ENOENT; } if (sizeof(dbg_buff) < count + 1) return -EFAULT; dbg_buff[count] = '\0'; mutex_lock(&ipa3_ctx->act_tbl_lock); uc_entry_nat = (struct ipa_ipv6_nat_uc_tmpl *) (ipa3_ctx->uc_act_tbl.base); nbytes = scnprintf(dbg_buff, IPA_MAX_MSG_LEN, "uc_act_tbl_total %d, uc_act_tbl_ipv6_nat_total %d uc_act_tbl_socksv5_total %d, uc_act_tbl_next_index %d\n" "uC activation entries:" , ipa3_ctx->uc_act_tbl_total, ipa3_ctx->uc_act_tbl_ipv6_nat_total, ipa3_ctx->uc_act_tbl_socksv5_total, ipa3_ctx->uc_act_tbl_next_index); cnt += nbytes; for (i = 0; i < IPA_UC_ACT_TBL_SIZE; i++) { if (uc_entry_nat[i].cmd_id == IPA_IPv6_NAT_COM_ID) { nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "\nentry %d:\n" "cmd_id = IPV6_NAT\n" "private_address_msb 0x%llX\n" "private_address_lsb 0x%llX\n" "private_port %u\n" "public_address_msb 0x%llX\n" "public_address_lsb 0x%llX\n" "public_port %u\n", i, uc_entry_nat[i].private_address_msb, uc_entry_nat[i].private_address_lsb, uc_entry_nat[i].private_port, uc_entry_nat[i].public_address_msb, uc_entry_nat[i].public_address_lsb, uc_entry_nat[i].public_port); cnt += nbytes; } else if (uc_entry_nat[i].cmd_id == IPA_SOCKSV5_ADD_COM_ID) { uc_entry_socks = (struct ipa_socksv5_uc_tmpl *) (uc_entry_nat); nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "\nentry %d:\n" "cmd_id = SOCKSv5\n" "cmd_param: %u\n" "source_port: %u\n" "dest_port: %u\n" "ipa_socksv5_mask: %x\n", i, uc_entry_socks[i].cmd_param, uc_entry_socks[i].src_port, uc_entry_socks[i].dst_port, uc_entry_socks[i].ipa_sockv5_mask); cnt += nbytes; if (uc_entry_socks[i].cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) { socks_iphdr = &uc_entry_socks[i].ip_hdr.ipv4_rsv; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "ipv4_src_addr: 0x%X\n" "ipv4_dst_addr: 0x%X\n", socks_iphdr->ipv4_temp.saddr, socks_iphdr->ipv4_temp.daddr); cnt += nbytes; } else { socks_ipv6hdr = &uc_entry_socks[i].ip_hdr.ipv6_temp; nbytes = scnprintf(dbg_buff + cnt, IPA_MAX_MSG_LEN, "ipv6_src_addr[0]: 0x%X\n" "ipv6_src_addr[1]: 0x%X\n" "ipv6_src_addr[2]: 0x%X\n" "ipv6_src_addr[3]: 0x%X\n" "ipv6_dts_addr[0]: 0x%X\n" "ipv6_dts_addr[1]: 0x%X\n" "ipv6_dts_addr[2]: 0x%X\n" "ipv6_dts_addr[3]: 0x%X\n", socks_ipv6hdr->saddr.s6_addr32[0], socks_ipv6hdr->saddr.s6_addr32[1], socks_ipv6hdr->saddr.s6_addr32[2], socks_ipv6hdr->saddr.s6_addr32[3], socks_ipv6hdr->daddr.s6_addr32[0], socks_ipv6hdr->daddr.s6_addr32[1], socks_ipv6hdr->daddr.s6_addr32[2], socks_ipv6hdr->daddr.s6_addr32[3]); cnt += nbytes; } } } mutex_unlock(&ipa3_ctx->act_tbl_lock); done: return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, cnt); } static const struct ipa3_debugfs_file debugfs_files[] = { { "gen_reg", IPA_READ_ONLY_MODE, NULL, { Loading Loading @@ -2811,7 +2930,11 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "app_clk_vote_cnt", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_app_clk_vote, } }, }, { "uc_act_table", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_read_uc_act_tbl, } } }; void ipa3_debugfs_pre_init(void) Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +11 −0 Original line number Diff line number Diff line Loading @@ -2022,6 +2022,8 @@ struct ipa3_context { bool uc_act_tbl_valid; struct mutex act_tbl_lock; int uc_act_tbl_total; int uc_act_tbl_socksv5_total; int uc_act_tbl_ipv6_nat_total; int uc_act_tbl_next_index; bool manual_fw_load; }; Loading Loading @@ -2419,6 +2421,15 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info); int ipa3_del_socksv5_conn(uint32_t handle); int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl); int ipa3_add_ipv6_nat_uc_activation_entry( struct ipa_ioc_ipv6_nat_uc_act_entry *entry); int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index); int ipa3_del_uc_act_entry(uint16_t index); /* * Header removal / addition */ Loading
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +409 −53 Original line number Diff line number Diff line Loading @@ -9150,6 +9150,213 @@ int ipa3_setup_uc_act_tbl(void) return res; } static inline bool is_free_socksv5(struct ipa_socksv5_uc_tmpl *socksv5_entry) { if ((!socksv5_entry->cmd_id) || (socksv5_entry->cmd_id == IPA_SOCKsv5_ADD_COM_ID && !(socksv5_entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID))) return true; return false; } static int ipa3_get_free_uc_act_entry(void) { struct ipa_socksv5_uc_tmpl *entry; int orig_index = ipa3_ctx->uc_act_tbl_next_index; int free_index = -1; IPADBG("\n"); /* find a free spot*/ do { entry = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); /* check if entry is free */ if (is_free_socksv5(entry)) { free_index = ipa3_ctx->uc_act_tbl_next_index; IPADBG("found free index at %d\n", free_index); break; } ipa3_ctx->uc_act_tbl_next_index++; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); IPADBG("exit free_index %d\n", free_index); return free_index; } int ipa3_add_ipv6_nat_uc_activation_entry( struct ipa_ioc_ipv6_nat_uc_act_entry *entry) { int res = 0; int index; struct ipa_ipv6_nat_uc_tmpl *uc_entry; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR("uC act tbl wasn't allocated\n"); return -ENOENT; } if (!entry) { IPAERR("Null entry\n"); return -EIO; } if (!entry->private_address_lsb || !entry->private_address_msb || !entry->public_address_lsb || !entry->public_address_msb || !entry->private_port || !entry->public_port) { IPAERR("0 param 0x%llX 0x%llX 0x%llX 0x%llX %d %d\n", entry->private_address_lsb, entry->private_address_msb, entry->public_address_lsb, entry->public_address_msb, entry->private_port, entry->public_port); return -EFAULT; } mutex_lock(&ipa3_ctx->act_tbl_lock); /* check the left # of entries */ if (ipa3_ctx->uc_act_tbl_total >= IPA_UC_ACT_TBL_SIZE) { IPAERR("uc act tbl is full!\n"); res = -EFAULT; goto error; } index = ipa3_get_free_uc_act_entry(); uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); uc_entry->private_address_lsb = entry->private_address_lsb; uc_entry->private_address_msb = entry->private_address_msb; uc_entry->public_address_lsb = entry->public_address_lsb; uc_entry->public_address_msb = entry->public_address_msb; uc_entry->private_port = entry->private_port; uc_entry->public_port = entry->public_port; uc_entry->cmd_id = IPA_IPv6_NAT_COM_ID; /* set output index */ entry->index = (uint16_t)index; ipa3_ctx->uc_act_tbl_total++; ipa3_ctx->uc_act_tbl_ipv6_nat_total++; if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { /* * find next free spot, this function shall update * uc_act_tbl_next_index */ index = ipa3_get_free_uc_act_entry(); if (index < 0) { /* set to max tbl size to debug */ IPAERR("can't find available spot!\n"); ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; res = -EFAULT; } } error: mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } int ipa3_del_uc_act_entry(uint16_t index) { struct ipa_ipv6_nat_uc_tmpl *uc_entry; uint16_t cmd_id; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR_RL("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR_RL("uC act tbl haven't allocated\n"); return -ENOENT; } if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { IPAERR_RL("invalid index!\n"); return -EINVAL; } if (!ipa3_ctx->uc_act_tbl_total) { IPAERR_RL( "invalid handle, no uc activation entries in table (total %d)\n" , ipa3_ctx->uc_act_tbl_total); return -EINVAL; } uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); mutex_lock(&ipa3_ctx->act_tbl_lock); cmd_id = uc_entry->cmd_id; mutex_unlock(&ipa3_ctx->act_tbl_lock); if (cmd_id == IPA_IPv6_NAT_COM_ID) return ipa3_del_ipv6_nat_uc_activation_entry(index); else return ipa3_del_socksv5_conn(index); } int ipa3_del_ipv6_nat_uc_activation_entry(uint16_t index) { struct ipa_ipv6_nat_uc_tmpl *uc_entry; int res = 0; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { IPAERR_RL("Not support !\n"); return -EPERM; } if (!ipa3_ctx->uc_act_tbl_valid) { IPAERR_RL("uC act tbl haven't allocated\n"); return -ENOENT; } if (index > IPA_UC_ACT_TBL_SIZE || index < 0) { IPAERR_RL("invalid index!\n"); return -EINVAL; } if (!ipa3_ctx->uc_act_tbl_ipv6_nat_total) { IPAERR_RL( "invalid handle, no IPv6 NAT entries in table (total %d)\n" , ipa3_ctx->uc_act_tbl_total); return -EINVAL; } uc_entry = (struct ipa_ipv6_nat_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + index * sizeof(struct ipa_ipv6_nat_uc_tmpl)); mutex_lock(&ipa3_ctx->act_tbl_lock); if (uc_entry->cmd_id != IPA_IPv6_NAT_COM_ID) { IPAERR_RL("entry %d wrong cmd id %d\n", uc_entry->cmd_id); res = -EFAULT; goto error; } uc_entry->cmd_id = 0; ipa3_ctx->uc_act_tbl_total--; ipa3_ctx->uc_act_tbl_ipv6_nat_total--; IPADBG("free entry %d, nat total %d, left total %d\n", index, ipa3_ctx->uc_act_tbl_ipv6_nat_total, ipa3_ctx->uc_act_tbl_total); error: mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) { if (!buff) { Loading @@ -9167,6 +9374,39 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } static int ipa3_get_free_socksv5_entry(void) { struct ipa_socksv5_uc_tmpl *first; struct ipa_socksv5_uc_tmpl *next; int orig_index = ipa3_ctx->uc_act_tbl_next_index; int free_index = -1; IPADBG("\n"); /* find a free spot with two contiguous entries*/ do { first = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); next = ipa3_ctx->uc_act_tbl.base + (ipa3_ctx->uc_act_tbl_next_index + 1) * sizeof(struct ipa_socksv5_uc_tmpl); /* check if first entry and next entry are free */ if (is_free_socksv5(first) && is_free_socksv5(next)) { free_index = ipa3_ctx->uc_act_tbl_next_index; IPADBG("found free index at %d\n", free_index); break; } ipa3_ctx->uc_act_tbl_next_index += 2; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; } while (orig_index != ipa3_ctx->uc_act_tbl_next_index); IPADBG("exit free_index %d\n", free_index); return free_index; } /** * ipa3_add_socksv5_conn() - IPA add socksv5_conn * Loading @@ -9176,8 +9416,8 @@ static void ipa3_socksv5_msg_free_cb(void *buff, u32 len, u32 type) */ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) { int res = 0; void *rp_va, *wp_va; int res = 0, index; void *wp_va; struct ipa_socksv5_msg *socksv5_msg; struct ipa_msg_meta msg_meta; Loading @@ -9198,18 +9438,24 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) } mutex_lock(&ipa3_ctx->act_tbl_lock); /* check the left # of entries */ /* check the left # of entries (need at least 2)*/ if (ipa3_ctx->uc_act_tbl_total >= IPA_UC_ACT_TBL_SIZE) { >= IPA_UC_ACT_TBL_SIZE - 1) { IPAERR("uc act tbl is full!\n"); res = -EFAULT; goto error; } index = ipa3_get_free_socksv5_entry(); if (index < 0) { IPAERR("couldn't find free socksv5 entry\n"); res = -EFAULT; goto error; } /* Copied the act-info to tbl */ wp_va = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); index * sizeof(struct ipa_socksv5_uc_tmpl); /* check entry valid */ if ((info->ul_out.cmd_id != IPA_SOCKsv5_ADD_COM_ID) Loading Loading @@ -9246,9 +9492,10 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) &(info->dl_out), sizeof(info->dl_out)); /* set output handle */ info->handle = (uint16_t) ipa3_ctx->uc_act_tbl_next_index; info->handle = (uint16_t) index; ipa3_ctx->uc_act_tbl_total += 2; ipa3_ctx->uc_act_tbl_socksv5_total += 2; /* send msg to ipacm */ socksv5_msg = kzalloc(sizeof(*socksv5_msg), GFP_KERNEL); Loading @@ -9261,9 +9508,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) memcpy(&(socksv5_msg->dl_in), &(info->dl_in), sizeof(info->dl_in)); socksv5_msg->handle = info->handle; socksv5_msg->ul_in.index = (uint16_t) ipa3_ctx->uc_act_tbl_next_index; (uint16_t) index; socksv5_msg->dl_in.index = (uint16_t) ipa3_ctx->uc_act_tbl_next_index + 1; (uint16_t) index + 1; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); msg_meta.msg_type = IPA_SOCKV5_ADD; Loading @@ -9276,27 +9523,14 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) goto error; } if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE) { /* find next free spot */ do { ipa3_ctx->uc_act_tbl_next_index += 2; ipa3_ctx->uc_act_tbl_next_index %= IPA_UC_ACT_TBL_SIZE; rp_va = ipa3_ctx->uc_act_tbl.base + ipa3_ctx->uc_act_tbl_next_index * sizeof(struct ipa_socksv5_uc_tmpl); if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { IPADBG("next available entry %d, total %d\n", ipa3_ctx->uc_act_tbl_next_index, ipa3_ctx->uc_act_tbl_total); break; } } while (rp_va != wp_va); if (ipa3_ctx->uc_act_tbl_total < IPA_UC_ACT_TBL_SIZE - 1) { /* * find next free spot, this function shall update * uc_act_tbl_next_index */ index = ipa3_get_free_socksv5_entry(); if (rp_va == wp_va) { if (index < 0) { /* set to max tbl size to debug */ IPAERR("can't find available spot!\n"); ipa3_ctx->uc_act_tbl_total = IPA_UC_ACT_TBL_SIZE; Loading @@ -9308,6 +9542,127 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) mutex_unlock(&ipa3_ctx->act_tbl_lock); return res; } /* * ipa3_add_socksv5_conn_usr() - IPA copy and add socksv5 conn * * Returns: 0 on success, negative on failure * * Note : Should not be called from atomic context */ int ipa3_add_socksv5_conn_usr(struct ipa_kernel_tests_socksv5_uc_tmpl *tmpl) { struct ipa_socksv5_info info; int retval = 0; memset(&info, 0, sizeof(struct ipa_socksv5_info)); if (tmpl->direction == 0) { /* DL */ info.dl_out.cmd_id = tmpl->cmd_id; info.dl_out.cmd_param = tmpl->cmd_param; info.dl_out.ip_hdr.ipv6_temp.version = 6; info.dl_out.ip_hdr.ipv6_temp.nexthdr = 6; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = tmpl->ipv6_src_addr[0]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = tmpl->ipv6_src_addr[1]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = tmpl->ipv6_src_addr[2]; info.dl_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = tmpl->ipv6_src_addr[3]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = tmpl->ipv6_dst_addr[0]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = tmpl->ipv6_dst_addr[1]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = tmpl->ipv6_dst_addr[2]; info.dl_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = tmpl->ipv6_dst_addr[3]; info.dl_out.src_port = tmpl->src_port; info.dl_out.dst_port = tmpl->dst_port; info.dl_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; info.dl_out.out_irs = tmpl->out_irs; info.dl_out.out_iss = tmpl->out_iss; info.dl_out.in_irs = tmpl->in_irs; info.dl_out.in_iss = tmpl->in_iss; info.dl_out.out_ircv_tsval = tmpl->out_ircv_tsval; info.dl_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; info.dl_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; info.dl_out.in_ircv_tsval = tmpl->in_ircv_tsval; info.dl_out.in_isnd_wscale = tmpl->in_isnd_wscale; info.dl_out.out_isnd_wscale = tmpl->out_isnd_wscale; info.dl_out.in_ircv_wscale = tmpl->in_ircv_wscale; info.dl_out.out_ircv_wscale = tmpl->out_ircv_wscale; /* for UL set default values to pass pair validity check */ info.ul_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; info.ul_out.cmd_param = IPA_SOCKsv5_ADD_V6_V4_COM_PM; } else if (tmpl->direction == 1) { /* UL */ info.ul_out.cmd_id = tmpl->cmd_id; info.ul_out.cmd_param = tmpl->cmd_param; if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V4_COM_PM) { info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.version = 4; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.ihl = 5; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.saddr = tmpl->ip_src_addr; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.daddr = tmpl->ip_dst_addr; info.ul_out.ip_hdr.ipv4_rsv.ipv4_temp.protocol = 6; } if (info.ul_out.cmd_param == IPA_SOCKsv5_ADD_V6_V6_COM_PM) { info.ul_out.ip_hdr.ipv6_temp.version = 6; info.ul_out.ip_hdr.ipv6_temp.nexthdr = 6; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[0] = tmpl->ipv6_src_addr[0]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[1] = tmpl->ipv6_src_addr[1]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[2] = tmpl->ipv6_src_addr[2]; info.ul_out.ip_hdr.ipv6_temp.saddr.s6_addr32[3] = tmpl->ipv6_src_addr[3]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[0] = tmpl->ipv6_dst_addr[0]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[1] = tmpl->ipv6_dst_addr[1]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[2] = tmpl->ipv6_dst_addr[2]; info.ul_out.ip_hdr.ipv6_temp.daddr.s6_addr32[3] = tmpl->ipv6_dst_addr[3]; } info.ul_out.src_port = tmpl->src_port; info.ul_out.dst_port = tmpl->dst_port; info.ul_out.ipa_sockv5_mask = tmpl->ipa_sockv5_mask; info.ul_out.out_irs = tmpl->out_irs; info.ul_out.out_iss = tmpl->out_iss; info.ul_out.in_irs = tmpl->in_irs; info.ul_out.in_iss = tmpl->in_iss; info.ul_out.out_ircv_tsval = tmpl->out_ircv_tsval; info.ul_out.in_ircv_tsecr = tmpl->in_ircv_tsecr; info.ul_out.out_ircv_tsecr = tmpl->out_ircv_tsecr; info.ul_out.in_ircv_tsval = tmpl->in_ircv_tsval; info.ul_out.in_isnd_wscale = tmpl->in_isnd_wscale; info.ul_out.out_isnd_wscale = tmpl->out_isnd_wscale; info.ul_out.in_ircv_wscale = tmpl->in_ircv_wscale; info.ul_out.out_ircv_wscale = tmpl->out_ircv_wscale; /* for DL set default values to pass pair validity check */ info.dl_out.cmd_param = IPA_SOCKsv5_ADD_V4_V6_COM_PM; info.dl_out.cmd_id = IPA_SOCKsv5_ADD_COM_ID; } else { IPAERR("invalid socksv5 direction: %d\n", tmpl->direction); return -EINVAL; } retval = ipa3_add_socksv5_conn(&info); if (retval) { IPAERR("ipa3_add_socksv5_conn failed retval: %d\n", retval); return retval; } /* save uc handle */ tmpl->handle = info.handle; return retval; } /** * ipa3_del_socksv5_conn() - IPA add socksv5_conn Loading @@ -9319,9 +9674,9 @@ int ipa3_add_socksv5_conn(struct ipa_socksv5_info *info) int ipa3_del_socksv5_conn(uint32_t handle) { int res = 0; void *rp_va; uint32_t *socksv5_handle; struct ipa_msg_meta msg_meta; struct ipa_socksv5_uc_tmpl *entry, *next; /* IPA version check */ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_5) { Loading @@ -9339,43 +9694,44 @@ int ipa3_del_socksv5_conn(uint32_t handle) return -EINVAL; } if ((handle % 2) != 0) { IPAERR("invalid handle!\n"); if (ipa3_ctx->uc_act_tbl_socksv5_total < 2) { IPAERR("invalid handle, tbl doesn't have socksv5 entries!\n"); return -EINVAL; } if (ipa3_ctx->uc_act_tbl_total < 2) { IPAERR("invalid handle, all tbl is empty!\n"); return -EINVAL; } rp_va = ipa3_ctx->uc_act_tbl.base + handle * sizeof(struct ipa_socksv5_uc_tmpl); entry = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + handle * sizeof(struct ipa_socksv5_uc_tmpl)); next = (struct ipa_socksv5_uc_tmpl *)(ipa3_ctx->uc_act_tbl.base + (handle + 1) * sizeof(struct ipa_socksv5_uc_tmpl)); /* check entry is valid or not */ mutex_lock(&ipa3_ctx->act_tbl_lock); if (!((((struct ipa_socksv5_uc_tmpl *) rp_va)-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { IPADBG(" entry %d already free\n", handle); if (entry->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { IPAERR(" entry %d not socksv5\n", handle); res = -EINVAL; goto error; } if (next->cmd_id != IPA_SOCKsv5_ADD_COM_ID) { IPAERR(" entry %d not socksv5\n", handle + 1); res = -EINVAL; goto error; } if (!(entry->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) IPADBG(" entry %d already free\n", handle); if (!((((struct ipa_socksv5_uc_tmpl *) (rp_va + sizeof(struct ipa_socksv5_uc_tmpl)))-> ipa_sockv5_mask) & IPA_SOCKSv5_ENTRY_VALID)) { if (!(next->ipa_sockv5_mask & IPA_SOCKSv5_ENTRY_VALID)) IPADBG(" entry %d already free\n", handle); } ((struct ipa_socksv5_uc_tmpl *) rp_va)->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; ((struct ipa_socksv5_uc_tmpl *) (rp_va + sizeof(struct ipa_socksv5_uc_tmpl)))->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; entry->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; next->ipa_sockv5_mask &= ~IPA_SOCKSv5_ENTRY_VALID; ipa3_ctx->uc_act_tbl_total -= 2; ipa3_ctx->uc_act_tbl_socksv5_total -= 2; IPADBG("free entry %d and %d, left total %d\n", IPADBG("free entry %d and %d, left total %d, socksv5 total %d\n", handle, handle + 1, ipa3_ctx->uc_act_tbl_total); ipa3_ctx->uc_act_tbl_total, ipa3_ctx->uc_act_tbl_socksv5_total); /* send msg to ipacm */ socksv5_handle = kzalloc(sizeof(*socksv5_handle), GFP_KERNEL); Loading
include/linux/ipa.h +27 −1 Original line number Diff line number Diff line Loading @@ -1423,9 +1423,35 @@ struct ipa_socksv5_info { struct ipacm_socksv5_info dl_in; /* output: handle (index) */ uint32_t handle; uint16_t handle; }; struct ipa_ipv6_nat_uc_tmpl { uint16_t cmd_id; uint16_t rsv; uint32_t cmd_param; uint16_t pkt_count; uint16_t rsv2; uint32_t byte_count; uint64_t private_address_lsb; uint64_t private_address_msb; uint64_t public_address_lsb; uint64_t public_address_msb; uint16_t private_port; uint16_t public_port; uint32_t rsv3; uint64_t rsv4; uint64_t rsv5; uint64_t rsv6; uint64_t rsv7; uint64_t rsv8; uint64_t rsv9; uint64_t rsv10; uint64_t rsv11; uint64_t rsv12; } __packed; #if defined CONFIG_IPA || defined CONFIG_IPA3 Loading