summaryrefslogtreecommitdiffstats
path: root/utils.h
blob: c1b6ebc2bcde40e4ba53fb2a3872745cdcb2105b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#ifndef NCR_UTILS_H
#define  NCR_UTILS_H

#include <linux/kernel.h>
#include <linux/netlink.h>

#define NCR_MAX_ATTR_SIZE 4096

struct nlattr;

struct ncr_out {
	void *buf, *p;
	size_t left;
	void __user *arg;
	size_t output_size_offset, fixed_size;
	u32 orig_output_size;
};

#define __NCR_VERIFY_FIXED_SIZE(fixed)					\
	(BUILD_BUG_ON(sizeof(*(fixed)) != NLA_ALIGN(sizeof(*(fixed)))))
#define __NCR_VERIFY_TB(tb) (BUILD_BUG_ON(ARRAY_SIZE(tb) != NCR_ATTR_MAX + 1))

extern u32 __ncr_u32_type_check;
#define __OUT_SIZE_OFF(fixed)						\
	((void)(&(fixed)->output_size == &__ncr_u32_type_check),	\
	 (char *)&(fixed)->output_size - (char *)(fixed))

/**
 * Load *@fixed and a sequence of netlink-like attributes from @arg.  @fixed
 * contains "input_size", which is an u32 filled with total input size,
 * including the attributes, which are parsed into @tb.
 */
#define NCR_GET_INPUT_ARGS(fixed, tb, arg)			\
	(__NCR_VERIFY_FIXED_SIZE(fixed),			\
	 __NCR_VERIFY_TB(tb),					\
	 __ncr_get_input_args(fixed, tb, sizeof(*(fixed)),	\
			      &(fixed)->input_size, arg))
void *__ncr_get_input_args(void *fixed, struct nlattr *tb[], size_t fixed_size,
			   u32 * input_size_ptr, const void __user * arg);

/**
 * Load *@fixed and a sequence of netlink-like attributes from @arg.  @fixed
 * contains "input_size", which is an u32 filled with total input size,
 * including the attributes, which are parsed into @tb.  In addition, indicate
 * to the user through u32 "output_size" that no output attributes will be
 * returned.
 */
#define NCR_GET_INPUT_ARGS_NO_OUTPUT(fixed, tb, arg)			\
	(__NCR_VERIFY_FIXED_SIZE(fixed),				\
	 __NCR_VERIFY_TB(tb),						\
	 __ncr_get_input_args_no_output(fixed, tb, sizeof(*(fixed)),	\
					&(fixed)->input_size,		\
					__OUT_SIZE_OFF(fixed), arg))
void *__ncr_get_input_args_no_output(void *fixed, struct nlattr *tb[],
				     size_t fixed_size, u32 * input_size_ptr,
				     size_t output_size_offset,
				     void __user * arg);

/**
 * Return a new output attribute context for attributes of *@fixed.  @fixed
 * contains "output_size", an u32 containing total output size, including
 * @fixed.  Store @arg for later ncr_out_finish().
 */
#define NCR_OUT_INIT(out, fixed, arg)				\
	(__NCR_VERIFY_FIXED_SIZE(fixed),			\
	 __ncr_out_init((out), (fixed), sizeof(*(fixed)),	\
			__OUT_SIZE_OFF(fixed), (arg)))
int __ncr_out_init(struct ncr_out *out, const void *fixed, size_t fixed_size,
		   size_t output_size_offset, void __user * arg);

/**
 * Write attributes from @out to user space and update user-space output_size.
 */
int ncr_out_finish(struct ncr_out *out);

void ncr_out_free(struct ncr_out *out);

int ncr_out_put(struct ncr_out *out, int attrtype, int attrlen,
		const void *data);

static inline int ncr_out_put_u32(struct ncr_out *out, int attrtype, u32 value)
{
	return ncr_out_put(out, attrtype, sizeof(value), &value);
}

static inline int ncr_out_put_string(struct ncr_out *out, int attrtype,
				     const char *value)
{
	return ncr_out_put(out, attrtype, strlen(value) + 1, value);
}

struct nlattr *ncr_out_reserve(struct ncr_out *out, int attrtype, int attrlen);

struct nlattr *ncr_out_begin_buffer(struct ncr_out *out, int attrtype);
void ncr_out_commit_buffer(struct ncr_out *out, int attrlen);

#endif