Loading drivers/platform/msm/ipa/ipa_v3/ipa.c +62 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } break; case IPA_IOC_ADD_RT_RULE_AFTER: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_add_rt_rule_after))) { retval = -EFAULT; break; } pyld_sz = sizeof(struct ipa_ioc_add_rt_rule_after) + ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules * sizeof(struct ipa_rt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; break; } if (copy_from_user(param, (u8 *)arg, pyld_sz)) { retval = -EFAULT; break; } if (ipa3_add_rt_rule_after( (struct ipa_ioc_add_rt_rule_after *)param)) { retval = -EFAULT; break; } if (copy_to_user((u8 *)arg, param, pyld_sz)) { retval = -EFAULT; break; } break; case IPA_IOC_MDFY_RT_RULE: if (copy_from_user(header, (u8 *)arg, Loading Loading @@ -586,6 +617,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_ADD_FLT_RULE_AFTER: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_add_flt_rule_after))) { retval = -EFAULT; break; } pyld_sz = sizeof(struct ipa_ioc_add_flt_rule_after) + ((struct ipa_ioc_add_flt_rule_after *)header)->num_rules * sizeof(struct ipa_flt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; break; } if (copy_from_user(param, (u8 *)arg, pyld_sz)) { retval = -EFAULT; break; } if (ipa3_add_flt_rule_after( (struct ipa_ioc_add_flt_rule_after *)param)) { retval = -EFAULT; break; } if (copy_to_user((u8 *)arg, param, pyld_sz)) { retval = -EFAULT; break; } break; case IPA_IOC_DEL_FLT_RULE: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_del_flt_rule))) { Loading drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +219 −39 Original line number Diff line number Diff line Loading @@ -1038,14 +1038,9 @@ fail_gen: return rc; } static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule, struct ipa3_rt_tbl **rt_tbl, enum ipa_ip_type ip) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; int id; if (rule->action != IPA_PASS_TO_EXCEPTION) { if (!rule->eq_attrib_type) { if (!rule->rt_tbl_hdl) { Loading @@ -1053,13 +1048,13 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, goto error; } rt_tbl = ipa3_id_find(rule->rt_tbl_hdl); if (rt_tbl == NULL) { *rt_tbl = ipa3_id_find(rule->rt_tbl_hdl); if (*rt_tbl == NULL) { IPAERR("RT tbl not found\n"); goto error; } if (rt_tbl->cookie != IPA_COOKIE) { if ((*rt_tbl)->cookie != IPA_COOKIE) { IPAERR("RT table cookie is invalid\n"); goto error; } Loading @@ -1073,32 +1068,49 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, } } entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL); if (!entry) { return 0; error: return -EPERM; } static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, const struct ipa_flt_rule *rule, struct ipa3_rt_tbl *rt_tbl, struct ipa3_flt_tbl *tbl) { int id; *entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL); if (!*entry) { IPAERR("failed to alloc FLT rule object\n"); goto error; } INIT_LIST_HEAD(&entry->link); entry->rule = *rule; entry->cookie = IPA_COOKIE; entry->rt_tbl = rt_tbl; entry->tbl = tbl; INIT_LIST_HEAD(&((*entry)->link)); (*entry)->rule = *rule; (*entry)->cookie = IPA_COOKIE; (*entry)->rt_tbl = rt_tbl; (*entry)->tbl = tbl; id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { IPAERR("failed to allocate rule id\n"); WARN_ON(1); goto rule_id_fail; } entry->rule_id = id; if (add_rear) { if (tbl->sticky_rear) list_add_tail(&entry->link, tbl->head_flt_rule_list.prev); else list_add_tail(&entry->link, &tbl->head_flt_rule_list); } else { list_add(&entry->link, &tbl->head_flt_rule_list); (*entry)->rule_id = id; return 0; rule_id_fail: kmem_cache_free(ipa3_ctx->flt_rule_cache, *entry); error: return -EPERM; } static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl, struct ipa3_flt_entry *entry, u32 *rule_hdl) { int id; tbl->rule_cnt++; if (entry->rt_tbl) entry->rt_tbl->ref_cnt++; Loading @@ -1111,14 +1123,80 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, entry->id = id; IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt); return 0; } static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) goto error; if (add_rear) { if (tbl->sticky_rear) list_add_tail(&entry->link, tbl->head_flt_rule_list.prev); else list_add_tail(&entry->link, &tbl->head_flt_rule_list); } else { list_add(&entry->link, &tbl->head_flt_rule_list); } __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); return 0; rule_id_fail: kmem_cache_free(ipa3_ctx->flt_rule_cache, entry); error: return -EPERM; } static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, const struct ipa_flt_rule *rule, u32 *rule_hdl, enum ipa_ip_type ip, struct ipa3_flt_entry **add_after_entry) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; if (!*add_after_entry) goto error; if (rule == NULL || rule_hdl == NULL) { IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl); goto error; } if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); /* * prepare for next insertion */ *add_after_entry = entry; return 0; error: *add_after_entry = NULL; return -EPERM; } static int __ipa_del_flt_rule(u32 rule_hdl) { struct ipa3_flt_entry *entry; Loading Loading @@ -1212,6 +1290,24 @@ error: return -EPERM; } static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx) { *ipa_ep_idx = ipa3_get_ep_mapping(ep); if (*ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) { IPAERR("ep not valid ep=%d\n", ep); return -EINVAL; } if (ipa3_ctx->ep[*ipa_ep_idx].valid == 0) IPADBG("ep not connected ep_idx=%d\n", *ipa_ep_idx); if (!ipa_is_ep_support_flt(*ipa_ep_idx)) { IPAERR("ep do not support filtering ep=%d\n", ep); return -EINVAL; } return 0; } static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) Loading @@ -1225,18 +1321,9 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, return -EINVAL; } ipa_ep_idx = ipa3_get_ep_mapping(ep); if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) { IPAERR("ep not valid ep=%d\n", ep); return -EINVAL; } if (ipa3_ctx->ep[ipa_ep_idx].valid == 0) IPADBG("ep not connected ep_idx=%d\n", ipa_ep_idx); if (!ipa_is_ep_support_flt(ipa_ep_idx)) { IPAERR("ep do not support filtering ep=%d\n", ep); if (__ipa_add_flt_get_ep_idx(ep, &ipa_ep_idx)) return -EINVAL; } tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][ip]; IPADBG("add ep flt rule ip=%d ep=%d\n", ip, ep); Loading Loading @@ -1300,6 +1387,99 @@ bail: return result; } /** * ipa3_add_flt_rule_after() - Add the specified filtering rules to SW after * the rule which its handle is given and optionally commit to IPA HW * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) { int i; int result; struct ipa3_flt_tbl *tbl; int ipa_ep_idx; struct ipa3_flt_entry *entry; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { IPAERR("bad parm\n"); return -EINVAL; } if (rules->ep >= IPA_CLIENT_MAX) { IPAERR("bad parms ep=%d\n", rules->ep); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); if (__ipa_add_flt_get_ep_idx(rules->ep, &ipa_ep_idx)) { result = -EINVAL; goto bail; } tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][rules->ip]; entry = ipa3_id_find(rules->add_after_hdl); if (entry == NULL) { IPAERR("lookup failed\n"); result = -EINVAL; goto bail; } if (entry->tbl != tbl) { IPAERR("given entry does not match the table\n"); result = -EINVAL; goto bail; } if (tbl->sticky_rear) if (&entry->link == tbl->head_flt_rule_list.prev) { IPAERR("cannot add rule at end of a sticky table"); result = -EINVAL; goto bail; } IPADBG("add ep flt rule ip=%d ep=%d after hdl %d\n", rules->ip, rules->ep, rules->add_after_hdl); /* * we add all rules one after the other, if one insertion fails, it cuts * the chain (all following will receive fail status) following calls to * __ipa_add_flt_rule_after will fail (entry == NULL) */ for (i = 0; i < rules->num_rules; i++) { result = __ipa_add_flt_rule_after(tbl, &rules->rules[i].rule, &rules->rules[i].flt_rule_hdl, rules->ip, &entry); if (result) { IPAERR("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; } } if (rules->commit) if (ipa3_ctx->ctrl->ipa3_commit_flt(rules->ip)) { IPAERR("failed to commit flt rules\n"); result = -EPERM; goto bail; } result = 0; bail: mutex_unlock(&ipa3_ctx->lock); return result; } /** * ipa3_del_flt_rule() - Remove the specified filtering rules from SW and * optionally commit to IPA HW Loading drivers/platform/msm/ipa/ipa_v3/ipa_i.h +4 −0 Original line number Diff line number Diff line Loading @@ -1565,6 +1565,8 @@ int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); */ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules); int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules); int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls); int ipa3_commit_rt(enum ipa_ip_type ip); Loading @@ -1584,6 +1586,8 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules); */ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules); int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules); int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls); int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules); Loading drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +218 −44 Original line number Diff line number Diff line Loading @@ -989,73 +989,73 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) return 0; } static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl) static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, struct ipa3_hdr_entry **hdr, struct ipa3_hdr_proc_ctx_entry **proc_ctx) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; int id; if (rule->hdr_hdl && rule->hdr_proc_ctx_hdl) { IPAERR("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n"); goto error; return -EPERM; } if (rule->hdr_hdl) { hdr = ipa3_id_find(rule->hdr_hdl); if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) { *hdr = ipa3_id_find(rule->hdr_hdl); if ((*hdr == NULL) || ((*hdr)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid hdr\n"); goto error; return -EPERM; } } else if (rule->hdr_proc_ctx_hdl) { proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl); if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) { *proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl); if ((*proc_ctx == NULL) || ((*proc_ctx)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid proc ctx\n"); goto error; return -EPERM; } } tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed adding rt tbl name=%s\n", name ? name : ""); goto error; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (tbl->rule_cnt > 0) && (at_rear != 0)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n", tbl->rule_cnt, at_rear); goto error; return 0; } entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL); if (!entry) { static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, const struct ipa_rt_rule *rule, struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr, struct ipa3_hdr_proc_ctx_entry *proc_ctx) { int id; *entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL); if (!*entry) { IPAERR("failed to alloc RT rule object\n"); goto error; } INIT_LIST_HEAD(&entry->link); entry->cookie = IPA_COOKIE; entry->rule = *rule; entry->tbl = tbl; entry->hdr = hdr; entry->proc_ctx = proc_ctx; INIT_LIST_HEAD(&(*entry)->link); (*(entry))->cookie = IPA_COOKIE; (*(entry))->rule = *rule; (*(entry))->tbl = tbl; (*(entry))->hdr = hdr; (*(entry))->proc_ctx = proc_ctx; id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { IPAERR("failed to allocate rule id\n"); WARN_ON(1); goto alloc_rule_id_fail; } entry->rule_id = id; if (at_rear) list_add_tail(&entry->link, &tbl->head_rt_rule_list); else list_add(&entry->link, &tbl->head_rt_rule_list); (*(entry))->rule_id = id; return 0; alloc_rule_id_fail: kmem_cache_free(ipa3_ctx->rt_rule_cache, *entry); error: return -EPERM; } static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl, struct ipa3_rt_tbl *tbl) { int id; tbl->rule_cnt++; if (entry->hdr) entry->hdr->ref_cnt++; Loading @@ -1077,9 +1077,87 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, ipa_insert_failed: idr_remove(&tbl->rule_ids, entry->rule_id); list_del(&entry->link); alloc_rule_id_fail: kmem_cache_free(ipa3_ctx->rt_rule_cache, entry); return -EPERM; } static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed adding rt tbl name = %s\n", name ? name : ""); goto error; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (tbl->rule_cnt > 0) && (at_rear != 0)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n", tbl->rule_cnt, at_rear); goto error; } if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx)) goto error; if (at_rear) list_add_tail(&entry->link, &tbl->head_rt_rule_list); else list_add(&entry->link, &tbl->head_rt_rule_list); if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl)) goto error; return 0; error: return -EPERM; } static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl, const struct ipa_rt_rule *rule, u32 *rule_hdl, struct ipa3_rt_entry **add_after_entry) { struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; if (!*add_after_entry) goto error; if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl)) goto error; /* * prepare for next insertion */ *add_after_entry = entry; return 0; error: *add_after_entry = NULL; return -EPERM; } Loading Loading @@ -1127,6 +1205,102 @@ bail: return ret; } /** * ipa3_add_rt_rule_after() - Add the given routing rules after the * specified rule to SW and optionally commit to IPA HW * @rules: [inout] set of routing rules to add + handle where to add * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) { int i; int ret = 0; struct ipa3_rt_tbl *tbl = NULL; struct ipa3_rt_entry *entry = NULL; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed finding rt tbl name = %s\n", rules->rt_tbl_name ? rules->rt_tbl_name : ""); ret = -EINVAL; goto bail; } if (tbl->rule_cnt <= 0) { IPAERR("tbl->rule_cnt <= 0"); ret = -EINVAL; goto bail; } entry = ipa3_id_find(rules->add_after_hdl); if (!entry) { IPAERR("failed finding rule %d in rt tbls\n", rules->add_after_hdl); ret = -EINVAL; goto bail; } if (entry->tbl != tbl) { IPAERR("given rt rule does not match the table\n"); ret = -EINVAL; goto bail; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (&entry->link == tbl->head_rt_rule_list.prev)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d\n", tbl->rule_cnt); ret = -EINVAL; goto bail; } /* * we add all rules one after the other, if one insertion fails, it cuts * the chain (all following will receive fail status) following calls to * __ipa_add_rt_rule_after will fail (entry == NULL) */ for (i = 0; i < rules->num_rules; i++) { if (__ipa_add_rt_rule_after(tbl, &rules->rules[i].rule, &rules->rules[i].rt_rule_hdl, &entry)) { IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; } } if (rules->commit) if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) { IPAERR("failed to commit\n"); ret = -EPERM; goto bail; } ret = 0; goto bail; bail: mutex_unlock(&ipa3_ctx->lock); return ret; } int __ipa3_del_rt_rule(u32 rule_hdl) { struct ipa3_rt_entry *entry; Loading include/uapi/linux/msm_ipa.h +52 −1 Original line number Diff line number Diff line Loading @@ -65,7 +65,9 @@ #define IPA_IOCTL_ADD_HDR_PROC_CTX 40 #define IPA_IOCTL_DEL_HDR_PROC_CTX 41 #define IPA_IOCTL_MDFY_RT_RULE 42 #define IPA_IOCTL_MAX 43 #define IPA_IOCTL_ADD_RT_RULE_AFTER 43 #define IPA_IOCTL_ADD_FLT_RULE_AFTER 44 #define IPA_IOCTL_MAX 45 /** * max size of the header to be inserted Loading Loading @@ -867,6 +869,28 @@ struct ipa_ioc_add_rt_rule { struct ipa_rt_rule_add rules[0]; }; /** * struct ipa_ioc_add_rt_rule_after - routing rule addition after a specific * rule parameters(supports multiple rules and commit); * * all rules MUST be added to same table * @commit: should rules be written to IPA HW also? * @ip: IP family of rule * @rt_tbl_name: name of routing table resource * @num_rules: number of routing rules that follow * @add_after_hdl: the rules will be added after this specific rule * @ipa_rt_rule_add rules: all rules need to go back to back here, no pointers * at_rear field will be ignored when using this IOCTL */ struct ipa_ioc_add_rt_rule_after { uint8_t commit; enum ipa_ip_type ip; char rt_tbl_name[IPA_RESOURCE_NAME_MAX]; uint8_t num_rules; uint32_t add_after_hdl; struct ipa_rt_rule_add rules[0]; }; /** * struct ipa_rt_rule_mdfy - routing rule descriptor includes * in and out parameters Loading Loading @@ -978,6 +1002,27 @@ struct ipa_ioc_add_flt_rule { struct ipa_flt_rule_add rules[0]; }; /** * struct ipa_ioc_add_flt_rule_after - filtering rule addition after specific * rule parameters (supports multiple rules and commit) * all rules MUST be added to same table * @commit: should rules be written to IPA HW also? * @ip: IP family of rule * @ep: which "clients" pipe does this rule apply to? * @num_rules: number of filtering rules that follow * @add_after_hdl: rules will be added after the rule with this handle * @rules: all rules need to go back to back here, no pointers. at rear field * is ignored when using this IOCTL */ struct ipa_ioc_add_flt_rule_after { uint8_t commit; enum ipa_ip_type ip; enum ipa_client_type ep; uint8_t num_rules; uint32_t add_after_hdl; struct ipa_flt_rule_add rules[0]; }; /** * struct ipa_flt_rule_mdfy - filtering rule descriptor includes * in and out parameters Loading Loading @@ -1382,12 +1427,18 @@ enum ipacm_client_enum { #define IPA_IOC_ADD_RT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_RT_RULE, \ struct ipa_ioc_add_rt_rule *) #define IPA_IOC_ADD_RT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_RT_RULE_AFTER, \ struct ipa_ioc_add_rt_rule_after *) #define IPA_IOC_DEL_RT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_RT_RULE, \ struct ipa_ioc_del_rt_rule *) #define IPA_IOC_ADD_FLT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_FLT_RULE, \ struct ipa_ioc_add_flt_rule *) #define IPA_IOC_ADD_FLT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_FLT_RULE_AFTER, \ struct ipa_ioc_add_flt_rule_after *) #define IPA_IOC_DEL_FLT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_FLT_RULE, \ struct ipa_ioc_del_flt_rule *) Loading Loading
drivers/platform/msm/ipa/ipa_v3/ipa.c +62 −0 Original line number Diff line number Diff line Loading @@ -498,6 +498,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } break; case IPA_IOC_ADD_RT_RULE_AFTER: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_add_rt_rule_after))) { retval = -EFAULT; break; } pyld_sz = sizeof(struct ipa_ioc_add_rt_rule_after) + ((struct ipa_ioc_add_rt_rule_after *)header)->num_rules * sizeof(struct ipa_rt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; break; } if (copy_from_user(param, (u8 *)arg, pyld_sz)) { retval = -EFAULT; break; } if (ipa3_add_rt_rule_after( (struct ipa_ioc_add_rt_rule_after *)param)) { retval = -EFAULT; break; } if (copy_to_user((u8 *)arg, param, pyld_sz)) { retval = -EFAULT; break; } break; case IPA_IOC_MDFY_RT_RULE: if (copy_from_user(header, (u8 *)arg, Loading Loading @@ -586,6 +617,37 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; case IPA_IOC_ADD_FLT_RULE_AFTER: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_add_flt_rule_after))) { retval = -EFAULT; break; } pyld_sz = sizeof(struct ipa_ioc_add_flt_rule_after) + ((struct ipa_ioc_add_flt_rule_after *)header)->num_rules * sizeof(struct ipa_flt_rule_add); param = kzalloc(pyld_sz, GFP_KERNEL); if (!param) { retval = -ENOMEM; break; } if (copy_from_user(param, (u8 *)arg, pyld_sz)) { retval = -EFAULT; break; } if (ipa3_add_flt_rule_after( (struct ipa_ioc_add_flt_rule_after *)param)) { retval = -EFAULT; break; } if (copy_to_user((u8 *)arg, param, pyld_sz)) { retval = -EFAULT; break; } break; case IPA_IOC_DEL_FLT_RULE: if (copy_from_user(header, (u8 *)arg, sizeof(struct ipa_ioc_del_flt_rule))) { Loading
drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +219 −39 Original line number Diff line number Diff line Loading @@ -1038,14 +1038,9 @@ fail_gen: return rc; } static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) static int __ipa_validate_flt_rule(const struct ipa_flt_rule *rule, struct ipa3_rt_tbl **rt_tbl, enum ipa_ip_type ip) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; int id; if (rule->action != IPA_PASS_TO_EXCEPTION) { if (!rule->eq_attrib_type) { if (!rule->rt_tbl_hdl) { Loading @@ -1053,13 +1048,13 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, goto error; } rt_tbl = ipa3_id_find(rule->rt_tbl_hdl); if (rt_tbl == NULL) { *rt_tbl = ipa3_id_find(rule->rt_tbl_hdl); if (*rt_tbl == NULL) { IPAERR("RT tbl not found\n"); goto error; } if (rt_tbl->cookie != IPA_COOKIE) { if ((*rt_tbl)->cookie != IPA_COOKIE) { IPAERR("RT table cookie is invalid\n"); goto error; } Loading @@ -1073,32 +1068,49 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, } } entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL); if (!entry) { return 0; error: return -EPERM; } static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, const struct ipa_flt_rule *rule, struct ipa3_rt_tbl *rt_tbl, struct ipa3_flt_tbl *tbl) { int id; *entry = kmem_cache_zalloc(ipa3_ctx->flt_rule_cache, GFP_KERNEL); if (!*entry) { IPAERR("failed to alloc FLT rule object\n"); goto error; } INIT_LIST_HEAD(&entry->link); entry->rule = *rule; entry->cookie = IPA_COOKIE; entry->rt_tbl = rt_tbl; entry->tbl = tbl; INIT_LIST_HEAD(&((*entry)->link)); (*entry)->rule = *rule; (*entry)->cookie = IPA_COOKIE; (*entry)->rt_tbl = rt_tbl; (*entry)->tbl = tbl; id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { IPAERR("failed to allocate rule id\n"); WARN_ON(1); goto rule_id_fail; } entry->rule_id = id; if (add_rear) { if (tbl->sticky_rear) list_add_tail(&entry->link, tbl->head_flt_rule_list.prev); else list_add_tail(&entry->link, &tbl->head_flt_rule_list); } else { list_add(&entry->link, &tbl->head_flt_rule_list); (*entry)->rule_id = id; return 0; rule_id_fail: kmem_cache_free(ipa3_ctx->flt_rule_cache, *entry); error: return -EPERM; } static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl, struct ipa3_flt_entry *entry, u32 *rule_hdl) { int id; tbl->rule_cnt++; if (entry->rt_tbl) entry->rt_tbl->ref_cnt++; Loading @@ -1111,14 +1123,80 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, entry->id = id; IPADBG("add flt rule rule_cnt=%d\n", tbl->rule_cnt); return 0; } static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) goto error; if (add_rear) { if (tbl->sticky_rear) list_add_tail(&entry->link, tbl->head_flt_rule_list.prev); else list_add_tail(&entry->link, &tbl->head_flt_rule_list); } else { list_add(&entry->link, &tbl->head_flt_rule_list); } __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); return 0; rule_id_fail: kmem_cache_free(ipa3_ctx->flt_rule_cache, entry); error: return -EPERM; } static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, const struct ipa_flt_rule *rule, u32 *rule_hdl, enum ipa_ip_type ip, struct ipa3_flt_entry **add_after_entry) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; if (!*add_after_entry) goto error; if (rule == NULL || rule_hdl == NULL) { IPAERR("bad parms rule=%p rule_hdl=%p\n", rule, rule_hdl); goto error; } if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); __ipa_finish_flt_rule_add(tbl, entry, rule_hdl); /* * prepare for next insertion */ *add_after_entry = entry; return 0; error: *add_after_entry = NULL; return -EPERM; } static int __ipa_del_flt_rule(u32 rule_hdl) { struct ipa3_flt_entry *entry; Loading Loading @@ -1212,6 +1290,24 @@ error: return -EPERM; } static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx) { *ipa_ep_idx = ipa3_get_ep_mapping(ep); if (*ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) { IPAERR("ep not valid ep=%d\n", ep); return -EINVAL; } if (ipa3_ctx->ep[*ipa_ep_idx].valid == 0) IPADBG("ep not connected ep_idx=%d\n", *ipa_ep_idx); if (!ipa_is_ep_support_flt(*ipa_ep_idx)) { IPAERR("ep do not support filtering ep=%d\n", ep); return -EINVAL; } return 0; } static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, const struct ipa_flt_rule *rule, u8 add_rear, u32 *rule_hdl) Loading @@ -1225,18 +1321,9 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, return -EINVAL; } ipa_ep_idx = ipa3_get_ep_mapping(ep); if (ipa_ep_idx == IPA_FLT_TABLE_INDEX_NOT_FOUND) { IPAERR("ep not valid ep=%d\n", ep); return -EINVAL; } if (ipa3_ctx->ep[ipa_ep_idx].valid == 0) IPADBG("ep not connected ep_idx=%d\n", ipa_ep_idx); if (!ipa_is_ep_support_flt(ipa_ep_idx)) { IPAERR("ep do not support filtering ep=%d\n", ep); if (__ipa_add_flt_get_ep_idx(ep, &ipa_ep_idx)) return -EINVAL; } tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][ip]; IPADBG("add ep flt rule ip=%d ep=%d\n", ip, ep); Loading Loading @@ -1300,6 +1387,99 @@ bail: return result; } /** * ipa3_add_flt_rule_after() - Add the specified filtering rules to SW after * the rule which its handle is given and optionally commit to IPA HW * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules) { int i; int result; struct ipa3_flt_tbl *tbl; int ipa_ep_idx; struct ipa3_flt_entry *entry; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { IPAERR("bad parm\n"); return -EINVAL; } if (rules->ep >= IPA_CLIENT_MAX) { IPAERR("bad parms ep=%d\n", rules->ep); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); if (__ipa_add_flt_get_ep_idx(rules->ep, &ipa_ep_idx)) { result = -EINVAL; goto bail; } tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][rules->ip]; entry = ipa3_id_find(rules->add_after_hdl); if (entry == NULL) { IPAERR("lookup failed\n"); result = -EINVAL; goto bail; } if (entry->tbl != tbl) { IPAERR("given entry does not match the table\n"); result = -EINVAL; goto bail; } if (tbl->sticky_rear) if (&entry->link == tbl->head_flt_rule_list.prev) { IPAERR("cannot add rule at end of a sticky table"); result = -EINVAL; goto bail; } IPADBG("add ep flt rule ip=%d ep=%d after hdl %d\n", rules->ip, rules->ep, rules->add_after_hdl); /* * we add all rules one after the other, if one insertion fails, it cuts * the chain (all following will receive fail status) following calls to * __ipa_add_flt_rule_after will fail (entry == NULL) */ for (i = 0; i < rules->num_rules; i++) { result = __ipa_add_flt_rule_after(tbl, &rules->rules[i].rule, &rules->rules[i].flt_rule_hdl, rules->ip, &entry); if (result) { IPAERR("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; } } if (rules->commit) if (ipa3_ctx->ctrl->ipa3_commit_flt(rules->ip)) { IPAERR("failed to commit flt rules\n"); result = -EPERM; goto bail; } result = 0; bail: mutex_unlock(&ipa3_ctx->lock); return result; } /** * ipa3_del_flt_rule() - Remove the specified filtering rules from SW and * optionally commit to IPA HW Loading
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +4 −0 Original line number Diff line number Diff line Loading @@ -1565,6 +1565,8 @@ int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); */ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules); int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules); int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls); int ipa3_commit_rt(enum ipa_ip_type ip); Loading @@ -1584,6 +1586,8 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules); */ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules); int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules); int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls); int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +218 −44 Original line number Diff line number Diff line Loading @@ -989,73 +989,73 @@ static int __ipa_del_rt_tbl(struct ipa3_rt_tbl *entry) return 0; } static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl) static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule, struct ipa3_hdr_entry **hdr, struct ipa3_hdr_proc_ctx_entry **proc_ctx) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; int id; if (rule->hdr_hdl && rule->hdr_proc_ctx_hdl) { IPAERR("rule contains both hdr_hdl and hdr_proc_ctx_hdl\n"); goto error; return -EPERM; } if (rule->hdr_hdl) { hdr = ipa3_id_find(rule->hdr_hdl); if ((hdr == NULL) || (hdr->cookie != IPA_COOKIE)) { *hdr = ipa3_id_find(rule->hdr_hdl); if ((*hdr == NULL) || ((*hdr)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid hdr\n"); goto error; return -EPERM; } } else if (rule->hdr_proc_ctx_hdl) { proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl); if ((proc_ctx == NULL) || (proc_ctx->cookie != IPA_COOKIE)) { *proc_ctx = ipa3_id_find(rule->hdr_proc_ctx_hdl); if ((*proc_ctx == NULL) || ((*proc_ctx)->cookie != IPA_COOKIE)) { IPAERR("rt rule does not point to valid proc ctx\n"); goto error; return -EPERM; } } tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed adding rt tbl name=%s\n", name ? name : ""); goto error; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (tbl->rule_cnt > 0) && (at_rear != 0)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n", tbl->rule_cnt, at_rear); goto error; return 0; } entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL); if (!entry) { static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, const struct ipa_rt_rule *rule, struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr, struct ipa3_hdr_proc_ctx_entry *proc_ctx) { int id; *entry = kmem_cache_zalloc(ipa3_ctx->rt_rule_cache, GFP_KERNEL); if (!*entry) { IPAERR("failed to alloc RT rule object\n"); goto error; } INIT_LIST_HEAD(&entry->link); entry->cookie = IPA_COOKIE; entry->rule = *rule; entry->tbl = tbl; entry->hdr = hdr; entry->proc_ctx = proc_ctx; INIT_LIST_HEAD(&(*entry)->link); (*(entry))->cookie = IPA_COOKIE; (*(entry))->rule = *rule; (*(entry))->tbl = tbl; (*(entry))->hdr = hdr; (*(entry))->proc_ctx = proc_ctx; id = ipa3_alloc_rule_id(&tbl->rule_ids); if (id < 0) { IPAERR("failed to allocate rule id\n"); WARN_ON(1); goto alloc_rule_id_fail; } entry->rule_id = id; if (at_rear) list_add_tail(&entry->link, &tbl->head_rt_rule_list); else list_add(&entry->link, &tbl->head_rt_rule_list); (*(entry))->rule_id = id; return 0; alloc_rule_id_fail: kmem_cache_free(ipa3_ctx->rt_rule_cache, *entry); error: return -EPERM; } static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl, struct ipa3_rt_tbl *tbl) { int id; tbl->rule_cnt++; if (entry->hdr) entry->hdr->ref_cnt++; Loading @@ -1077,9 +1077,87 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, ipa_insert_failed: idr_remove(&tbl->rule_ids, entry->rule_id); list_del(&entry->link); alloc_rule_id_fail: kmem_cache_free(ipa3_ctx->rt_rule_cache, entry); return -EPERM; } static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; tbl = __ipa_add_rt_tbl(ip, name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed adding rt tbl name = %s\n", name ? name : ""); goto error; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (tbl->rule_cnt > 0) && (at_rear != 0)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d at_rear=%d\n", tbl->rule_cnt, at_rear); goto error; } if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx)) goto error; if (at_rear) list_add_tail(&entry->link, &tbl->head_rt_rule_list); else list_add(&entry->link, &tbl->head_rt_rule_list); if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl)) goto error; return 0; error: return -EPERM; } static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl, const struct ipa_rt_rule *rule, u32 *rule_hdl, struct ipa3_rt_entry **add_after_entry) { struct ipa3_rt_entry *entry; struct ipa3_hdr_entry *hdr = NULL; struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; if (!*add_after_entry) goto error; if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); if (__ipa_finish_rt_rule_add(entry, rule_hdl, tbl)) goto error; /* * prepare for next insertion */ *add_after_entry = entry; return 0; error: *add_after_entry = NULL; return -EPERM; } Loading Loading @@ -1127,6 +1205,102 @@ bail: return ret; } /** * ipa3_add_rt_rule_after() - Add the given routing rules after the * specified rule to SW and optionally commit to IPA HW * @rules: [inout] set of routing rules to add + handle where to add * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules) { int i; int ret = 0; struct ipa3_rt_tbl *tbl = NULL; struct ipa3_rt_entry *entry = NULL; if (rules == NULL || rules->num_rules == 0 || rules->ip >= IPA_IP_MAX) { IPAERR("bad parm\n"); return -EINVAL; } mutex_lock(&ipa3_ctx->lock); tbl = __ipa3_find_rt_tbl(rules->ip, rules->rt_tbl_name); if (tbl == NULL || (tbl->cookie != IPA_COOKIE)) { IPAERR("failed finding rt tbl name = %s\n", rules->rt_tbl_name ? rules->rt_tbl_name : ""); ret = -EINVAL; goto bail; } if (tbl->rule_cnt <= 0) { IPAERR("tbl->rule_cnt <= 0"); ret = -EINVAL; goto bail; } entry = ipa3_id_find(rules->add_after_hdl); if (!entry) { IPAERR("failed finding rule %d in rt tbls\n", rules->add_after_hdl); ret = -EINVAL; goto bail; } if (entry->tbl != tbl) { IPAERR("given rt rule does not match the table\n"); ret = -EINVAL; goto bail; } /* * do not allow any rules to be added at end of the "default" routing * tables */ if (!strcmp(tbl->name, IPA_DFLT_RT_TBL_NAME) && (&entry->link == tbl->head_rt_rule_list.prev)) { IPAERR("cannot add rule at end of tbl rule_cnt=%d\n", tbl->rule_cnt); ret = -EINVAL; goto bail; } /* * we add all rules one after the other, if one insertion fails, it cuts * the chain (all following will receive fail status) following calls to * __ipa_add_rt_rule_after will fail (entry == NULL) */ for (i = 0; i < rules->num_rules; i++) { if (__ipa_add_rt_rule_after(tbl, &rules->rules[i].rule, &rules->rules[i].rt_rule_hdl, &entry)) { IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { rules->rules[i].status = 0; } } if (rules->commit) if (ipa3_ctx->ctrl->ipa3_commit_rt(rules->ip)) { IPAERR("failed to commit\n"); ret = -EPERM; goto bail; } ret = 0; goto bail; bail: mutex_unlock(&ipa3_ctx->lock); return ret; } int __ipa3_del_rt_rule(u32 rule_hdl) { struct ipa3_rt_entry *entry; Loading
include/uapi/linux/msm_ipa.h +52 −1 Original line number Diff line number Diff line Loading @@ -65,7 +65,9 @@ #define IPA_IOCTL_ADD_HDR_PROC_CTX 40 #define IPA_IOCTL_DEL_HDR_PROC_CTX 41 #define IPA_IOCTL_MDFY_RT_RULE 42 #define IPA_IOCTL_MAX 43 #define IPA_IOCTL_ADD_RT_RULE_AFTER 43 #define IPA_IOCTL_ADD_FLT_RULE_AFTER 44 #define IPA_IOCTL_MAX 45 /** * max size of the header to be inserted Loading Loading @@ -867,6 +869,28 @@ struct ipa_ioc_add_rt_rule { struct ipa_rt_rule_add rules[0]; }; /** * struct ipa_ioc_add_rt_rule_after - routing rule addition after a specific * rule parameters(supports multiple rules and commit); * * all rules MUST be added to same table * @commit: should rules be written to IPA HW also? * @ip: IP family of rule * @rt_tbl_name: name of routing table resource * @num_rules: number of routing rules that follow * @add_after_hdl: the rules will be added after this specific rule * @ipa_rt_rule_add rules: all rules need to go back to back here, no pointers * at_rear field will be ignored when using this IOCTL */ struct ipa_ioc_add_rt_rule_after { uint8_t commit; enum ipa_ip_type ip; char rt_tbl_name[IPA_RESOURCE_NAME_MAX]; uint8_t num_rules; uint32_t add_after_hdl; struct ipa_rt_rule_add rules[0]; }; /** * struct ipa_rt_rule_mdfy - routing rule descriptor includes * in and out parameters Loading Loading @@ -978,6 +1002,27 @@ struct ipa_ioc_add_flt_rule { struct ipa_flt_rule_add rules[0]; }; /** * struct ipa_ioc_add_flt_rule_after - filtering rule addition after specific * rule parameters (supports multiple rules and commit) * all rules MUST be added to same table * @commit: should rules be written to IPA HW also? * @ip: IP family of rule * @ep: which "clients" pipe does this rule apply to? * @num_rules: number of filtering rules that follow * @add_after_hdl: rules will be added after the rule with this handle * @rules: all rules need to go back to back here, no pointers. at rear field * is ignored when using this IOCTL */ struct ipa_ioc_add_flt_rule_after { uint8_t commit; enum ipa_ip_type ip; enum ipa_client_type ep; uint8_t num_rules; uint32_t add_after_hdl; struct ipa_flt_rule_add rules[0]; }; /** * struct ipa_flt_rule_mdfy - filtering rule descriptor includes * in and out parameters Loading Loading @@ -1382,12 +1427,18 @@ enum ipacm_client_enum { #define IPA_IOC_ADD_RT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_RT_RULE, \ struct ipa_ioc_add_rt_rule *) #define IPA_IOC_ADD_RT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_RT_RULE_AFTER, \ struct ipa_ioc_add_rt_rule_after *) #define IPA_IOC_DEL_RT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_RT_RULE, \ struct ipa_ioc_del_rt_rule *) #define IPA_IOC_ADD_FLT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_FLT_RULE, \ struct ipa_ioc_add_flt_rule *) #define IPA_IOC_ADD_FLT_RULE_AFTER _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_ADD_FLT_RULE_AFTER, \ struct ipa_ioc_add_flt_rule_after *) #define IPA_IOC_DEL_FLT_RULE _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_FLT_RULE, \ struct ipa_ioc_del_flt_rule *) Loading