static int compat_copy_entries_to_user(unsigned int total_size,
		     struct ipt_table *table, void __user *userptr)
{
	unsigned int off, num;
	struct compat_ipt_entry e;
	struct xt_counters *counters;
	struct xt_table_info *private = table->private;
	void __user *pos;
	unsigned int size;
	int ret = 0;
	void *loc_cpu_entry;

	counters = alloc_counters(table);
	if (IS_ERR(counters))
		return PTR_ERR(counters);

	/* choose the copy that is on our node/cpu, ...
	 * This choice is lazy (because current thread is
	 * allowed to migrate to another cpu)
	 */
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	pos = userptr;
	size = total_size;
	ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
			compat_copy_entry_to_user, &pos, &size);
	if (ret)
		goto free_counters;

	/* ... then go back and fix counters and names */
	for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
		unsigned int i;
		struct ipt_entry_match m;
		struct ipt_entry_target t;

		ret = -EFAULT;
		if (copy_from_user(&e, userptr + off,
					sizeof(struct compat_ipt_entry)))
			goto free_counters;
		if (copy_to_user(userptr + off +
			offsetof(struct compat_ipt_entry, counters),
			 &counters[num], sizeof(counters[num])))
			goto free_counters;

		for (i = sizeof(struct compat_ipt_entry);
				i < e.target_offset; i += m.u.match_size) {
			if (copy_from_user(&m, userptr + off + i,
					sizeof(struct ipt_entry_match)))
				goto free_counters;
			if (copy_to_user(userptr + off + i +
				offsetof(struct ipt_entry_match, u.user.name),
				m.u.kernel.match->name,
				strlen(m.u.kernel.match->name) + 1))
				goto free_counters;
		}

		if (copy_from_user(&t, userptr + off + e.target_offset,
					sizeof(struct ipt_entry_target)))
			goto free_counters;
		if (copy_to_user(userptr + off + e.target_offset +
			offsetof(struct ipt_entry_target, u.user.name),
			t.u.kernel.target->name,
			strlen(t.u.kernel.target->name) + 1))
			goto free_counters;
	}
	ret = 0;
free_counters:
	vfree(counters);
	return ret;
}
static int compat_copy_entries_to_user(unsigned int total_size,
		     struct ipt_table *table, void __user *userptr)
{
	unsigned int off, num;
	struct compat_ipt_entry e;
	struct xt_counters *counters;
	struct xt_table_info *private = table->private;
	void __user *pos;
	unsigned int size;
	int ret = 0;
	void *loc_cpu_entry;

	counters = alloc_counters(table);
	if (IS_ERR(counters))
		return PTR_ERR(counters);

	 
	loc_cpu_entry = private->entries[raw_smp_processor_id()];
	pos = userptr;
	size = total_size;
	ret = IPT_ENTRY_ITERATE(loc_cpu_entry, total_size,
			compat_copy_entry_to_user, &pos, &size);
	if (ret)
		goto free_counters;

	 
	for (off = 0, num = 0; off < size; off += e.next_offset, num++) {
		unsigned int i;
		struct ipt_entry_match m;
		struct ipt_entry_target t;

		ret = -EFAULT;
		if (copy_from_user(&e, userptr + off,
					sizeof(struct compat_ipt_entry)))
			goto free_counters;
		if (copy_to_user(userptr + off +
			offsetof(struct compat_ipt_entry, counters),
			 &counters[num], sizeof(counters[num])))
			goto free_counters;

		for (i = sizeof(struct compat_ipt_entry);
				i < e.target_offset; i += m.u.match_size) {
			if (copy_from_user(&m, userptr + off + i,
					sizeof(struct ipt_entry_match)))
				goto free_counters;
			if (copy_to_user(userptr + off + i +
				offsetof(struct ipt_entry_match, u.user.name),
				m.u.kernel.match->name,
				strlen(m.u.kernel.match->name) + 1))
				goto free_counters;
		}

		if (copy_from_user(&t, userptr + off + e.target_offset,
					sizeof(struct ipt_entry_target)))
			goto free_counters;
		if (copy_to_user(userptr + off + e.target_offset +
			offsetof(struct ipt_entry_target, u.user.name),
			t.u.kernel.target->name,
			strlen(t.u.kernel.target->name) + 1))
			goto free_counters;
	}
	ret = 0;
free_counters:
	vfree(counters);
	return ret;
}