Loading net/netfilter/x_tables.c +142 −57 Original line number Diff line number Diff line Loading @@ -827,130 +827,215 @@ static const struct file_operations xt_table_ops = { .release = seq_release_net, }; static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) /* * Traverse state for ip{,6}_{tables,matches} for helping crossing * the multi-AF mutexes. */ struct nf_mttg_trav { struct list_head *head, *curr; uint8_t class, nfproto; }; enum { MTTG_TRAV_INIT, MTTG_TRAV_NFP_UNSPEC, MTTG_TRAV_NFP_SPEC, MTTG_TRAV_DONE, }; static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos, bool is_target) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; static const uint8_t next_class[] = { [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC, [MTTG_TRAV_NFP_SPEC] = MTTG_TRAV_DONE, }; struct nf_mttg_trav *trav = seq->private; switch (trav->class) { case MTTG_TRAV_INIT: trav->class = MTTG_TRAV_NFP_UNSPEC; mutex_lock(&xt[NFPROTO_UNSPEC].mutex); trav->head = trav->curr = is_target ? &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match; break; case MTTG_TRAV_NFP_UNSPEC: trav->curr = trav->curr->next; if (trav->curr != trav->head) break; mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); mutex_lock(&xt[trav->nfproto].mutex); trav->head = trav->curr = is_target ? &xt[trav->nfproto].target : &xt[trav->nfproto].match; trav->class = next_class[trav->class]; break; case MTTG_TRAV_NFP_SPEC: trav->curr = trav->curr->next; if (trav->curr != trav->head) break; /* fallthru, _stop will unlock */ default: return NULL; } mutex_lock(&xt[af].mutex); return seq_list_start(&xt[af].match, *pos); if (ppos != NULL) ++*ppos; return trav; } static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos, bool is_target) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; struct nf_mttg_trav *trav = seq->private; unsigned int j; return seq_list_next(v, &xt[af].match, pos); trav->class = MTTG_TRAV_INIT; for (j = 0; j < *pos; ++j) if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL) return NULL; return trav; } static void xt_match_seq_stop(struct seq_file *seq, void *v) static void xt_mttg_seq_stop(struct seq_file *seq, void *v) { struct proc_dir_entry *pde = seq->private; u_int16_t af = (unsigned long)pde->data; struct nf_mttg_trav *trav = seq->private; mutex_unlock(&xt[af].mutex); switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); break; case MTTG_TRAV_NFP_SPEC: mutex_unlock(&xt[trav->nfproto].mutex); break; } } static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) { return xt_mttg_seq_start(seq, pos, false); } static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos) { return xt_mttg_seq_next(seq, v, ppos, false); } static int xt_match_seq_show(struct seq_file *seq, void *v) { struct xt_match *match = list_entry(v, struct xt_match, list); const struct nf_mttg_trav *trav = seq->private; const struct xt_match *match; if (strlen(match->name)) return seq_printf(seq, "%s\n", match->name); else switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: case MTTG_TRAV_NFP_SPEC: if (trav->curr == trav->head) return 0; match = list_entry(trav->curr, struct xt_match, list); return (*match->name == '\0') ? 0 : seq_printf(seq, "%s\n", match->name); } return 0; } static const struct seq_operations xt_match_seq_ops = { .start = xt_match_seq_start, .next = xt_match_seq_next, .stop = xt_match_seq_stop, .stop = xt_mttg_seq_stop, .show = xt_match_seq_show, }; static int xt_match_open(struct inode *inode, struct file *file) { struct seq_file *seq; struct nf_mttg_trav *trav; int ret; ret = seq_open(file, &xt_match_seq_ops); if (!ret) { struct seq_file *seq = file->private_data; trav = kmalloc(sizeof(*trav), GFP_KERNEL); if (trav == NULL) return -ENOMEM; seq->private = PDE(inode); } ret = seq_open(file, &xt_match_seq_ops); if (ret < 0) { kfree(trav); return ret; } seq = file->private_data; seq->private = trav; trav->nfproto = (unsigned long)PDE(inode)->data; return 0; } static const struct file_operations xt_match_ops = { .owner = THIS_MODULE, .open = xt_match_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .release = seq_release_private, }; static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; mutex_lock(&xt[af].mutex); return seq_list_start(&xt[af].target, *pos); return xt_mttg_seq_start(seq, pos, true); } static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; return seq_list_next(v, &xt[af].target, pos); } static void xt_target_seq_stop(struct seq_file *seq, void *v) { struct proc_dir_entry *pde = seq->private; u_int16_t af = (unsigned long)pde->data; mutex_unlock(&xt[af].mutex); return xt_mttg_seq_next(seq, v, ppos, true); } static int xt_target_seq_show(struct seq_file *seq, void *v) { struct xt_target *target = list_entry(v, struct xt_target, list); const struct nf_mttg_trav *trav = seq->private; const struct xt_target *target; if (strlen(target->name)) return seq_printf(seq, "%s\n", target->name); else switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: case MTTG_TRAV_NFP_SPEC: if (trav->curr == trav->head) return 0; target = list_entry(trav->curr, struct xt_target, list); return (*target->name == '\0') ? 0 : seq_printf(seq, "%s\n", target->name); } return 0; } static const struct seq_operations xt_target_seq_ops = { .start = xt_target_seq_start, .next = xt_target_seq_next, .stop = xt_target_seq_stop, .stop = xt_mttg_seq_stop, .show = xt_target_seq_show, }; static int xt_target_open(struct inode *inode, struct file *file) { struct seq_file *seq; struct nf_mttg_trav *trav; int ret; ret = seq_open(file, &xt_target_seq_ops); if (!ret) { struct seq_file *seq = file->private_data; trav = kmalloc(sizeof(*trav), GFP_KERNEL); if (trav == NULL) return -ENOMEM; seq->private = PDE(inode); } ret = seq_open(file, &xt_target_seq_ops); if (ret < 0) { kfree(trav); return ret; } seq = file->private_data; seq->private = trav; trav->nfproto = (unsigned long)PDE(inode)->data; return 0; } static const struct file_operations xt_target_ops = { .owner = THIS_MODULE, .open = xt_target_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .release = seq_release_private, }; #define FORMAT_TABLES "_tables_names" Loading Loading
net/netfilter/x_tables.c +142 −57 Original line number Diff line number Diff line Loading @@ -827,130 +827,215 @@ static const struct file_operations xt_table_ops = { .release = seq_release_net, }; static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) /* * Traverse state for ip{,6}_{tables,matches} for helping crossing * the multi-AF mutexes. */ struct nf_mttg_trav { struct list_head *head, *curr; uint8_t class, nfproto; }; enum { MTTG_TRAV_INIT, MTTG_TRAV_NFP_UNSPEC, MTTG_TRAV_NFP_SPEC, MTTG_TRAV_DONE, }; static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos, bool is_target) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; static const uint8_t next_class[] = { [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC, [MTTG_TRAV_NFP_SPEC] = MTTG_TRAV_DONE, }; struct nf_mttg_trav *trav = seq->private; switch (trav->class) { case MTTG_TRAV_INIT: trav->class = MTTG_TRAV_NFP_UNSPEC; mutex_lock(&xt[NFPROTO_UNSPEC].mutex); trav->head = trav->curr = is_target ? &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match; break; case MTTG_TRAV_NFP_UNSPEC: trav->curr = trav->curr->next; if (trav->curr != trav->head) break; mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); mutex_lock(&xt[trav->nfproto].mutex); trav->head = trav->curr = is_target ? &xt[trav->nfproto].target : &xt[trav->nfproto].match; trav->class = next_class[trav->class]; break; case MTTG_TRAV_NFP_SPEC: trav->curr = trav->curr->next; if (trav->curr != trav->head) break; /* fallthru, _stop will unlock */ default: return NULL; } mutex_lock(&xt[af].mutex); return seq_list_start(&xt[af].match, *pos); if (ppos != NULL) ++*ppos; return trav; } static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos, bool is_target) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; struct nf_mttg_trav *trav = seq->private; unsigned int j; return seq_list_next(v, &xt[af].match, pos); trav->class = MTTG_TRAV_INIT; for (j = 0; j < *pos; ++j) if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL) return NULL; return trav; } static void xt_match_seq_stop(struct seq_file *seq, void *v) static void xt_mttg_seq_stop(struct seq_file *seq, void *v) { struct proc_dir_entry *pde = seq->private; u_int16_t af = (unsigned long)pde->data; struct nf_mttg_trav *trav = seq->private; mutex_unlock(&xt[af].mutex); switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: mutex_unlock(&xt[NFPROTO_UNSPEC].mutex); break; case MTTG_TRAV_NFP_SPEC: mutex_unlock(&xt[trav->nfproto].mutex); break; } } static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos) { return xt_mttg_seq_start(seq, pos, false); } static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos) { return xt_mttg_seq_next(seq, v, ppos, false); } static int xt_match_seq_show(struct seq_file *seq, void *v) { struct xt_match *match = list_entry(v, struct xt_match, list); const struct nf_mttg_trav *trav = seq->private; const struct xt_match *match; if (strlen(match->name)) return seq_printf(seq, "%s\n", match->name); else switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: case MTTG_TRAV_NFP_SPEC: if (trav->curr == trav->head) return 0; match = list_entry(trav->curr, struct xt_match, list); return (*match->name == '\0') ? 0 : seq_printf(seq, "%s\n", match->name); } return 0; } static const struct seq_operations xt_match_seq_ops = { .start = xt_match_seq_start, .next = xt_match_seq_next, .stop = xt_match_seq_stop, .stop = xt_mttg_seq_stop, .show = xt_match_seq_show, }; static int xt_match_open(struct inode *inode, struct file *file) { struct seq_file *seq; struct nf_mttg_trav *trav; int ret; ret = seq_open(file, &xt_match_seq_ops); if (!ret) { struct seq_file *seq = file->private_data; trav = kmalloc(sizeof(*trav), GFP_KERNEL); if (trav == NULL) return -ENOMEM; seq->private = PDE(inode); } ret = seq_open(file, &xt_match_seq_ops); if (ret < 0) { kfree(trav); return ret; } seq = file->private_data; seq->private = trav; trav->nfproto = (unsigned long)PDE(inode)->data; return 0; } static const struct file_operations xt_match_ops = { .owner = THIS_MODULE, .open = xt_match_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .release = seq_release_private, }; static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; mutex_lock(&xt[af].mutex); return seq_list_start(&xt[af].target, *pos); return xt_mttg_seq_start(seq, pos, true); } static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos) { struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private; u_int16_t af = (unsigned long)pde->data; return seq_list_next(v, &xt[af].target, pos); } static void xt_target_seq_stop(struct seq_file *seq, void *v) { struct proc_dir_entry *pde = seq->private; u_int16_t af = (unsigned long)pde->data; mutex_unlock(&xt[af].mutex); return xt_mttg_seq_next(seq, v, ppos, true); } static int xt_target_seq_show(struct seq_file *seq, void *v) { struct xt_target *target = list_entry(v, struct xt_target, list); const struct nf_mttg_trav *trav = seq->private; const struct xt_target *target; if (strlen(target->name)) return seq_printf(seq, "%s\n", target->name); else switch (trav->class) { case MTTG_TRAV_NFP_UNSPEC: case MTTG_TRAV_NFP_SPEC: if (trav->curr == trav->head) return 0; target = list_entry(trav->curr, struct xt_target, list); return (*target->name == '\0') ? 0 : seq_printf(seq, "%s\n", target->name); } return 0; } static const struct seq_operations xt_target_seq_ops = { .start = xt_target_seq_start, .next = xt_target_seq_next, .stop = xt_target_seq_stop, .stop = xt_mttg_seq_stop, .show = xt_target_seq_show, }; static int xt_target_open(struct inode *inode, struct file *file) { struct seq_file *seq; struct nf_mttg_trav *trav; int ret; ret = seq_open(file, &xt_target_seq_ops); if (!ret) { struct seq_file *seq = file->private_data; trav = kmalloc(sizeof(*trav), GFP_KERNEL); if (trav == NULL) return -ENOMEM; seq->private = PDE(inode); } ret = seq_open(file, &xt_target_seq_ops); if (ret < 0) { kfree(trav); return ret; } seq = file->private_data; seq->private = trav; trav->nfproto = (unsigned long)PDE(inode)->data; return 0; } static const struct file_operations xt_target_ops = { .owner = THIS_MODULE, .open = xt_target_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, .release = seq_release_private, }; #define FORMAT_TABLES "_tables_names" Loading