-
Notifications
You must be signed in to change notification settings - Fork 19
/
gnKernel.c
166 lines (141 loc) · 4.48 KB
/
gnKernel.c
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <net/genetlink.h>
#include <linux/module.h>
#include <linux/kernel.h>
/* attributes (variables): the index in this enum is used as a reference for the type,
* userspace application has to indicate the corresponding type
* the policy is used for security considerations
*/
enum {
DOC_EXMPL_A_UNSPEC,
DOC_EXMPL_A_MSG,
__DOC_EXMPL_A_MAX,
};
#define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1)
/* attribute policy: defines which attribute has which type (e.g int, char * etc)
* possible values defined in net/netlink.h
*/
static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = {
[DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING },
};
#define VERSION_NR 1
/* family definition */
static struct genl_family doc_exmpl_gnl_family = {
.id = GENL_ID_GENERATE, //genetlink should generate an id
.hdrsize = 0,
.name = "CONTROL_EXMPL", //the name of this family, used by userspace application
.version = VERSION_NR, //version number
.maxattr = DOC_EXMPL_A_MAX,
};
/* commands: enumeration of all commands (functions),
* used by userspace application to identify command to be ececuted
*/
enum {
DOC_EXMPL_C_UNSPEC,
DOC_EXMPL_C_ECHO,
__DOC_EXMPL_C_MAX,
};
#define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1)
/* an echo command, receives a message, prints it and sends another message back */
int doc_exmpl_echo(struct sk_buff *skb_2, struct genl_info *info)
{
struct nlattr *na;
struct sk_buff *skb;
int rc;
void *msg_head;
char * mydata;
if (info == NULL)
goto out;
/*for each attribute there is an index in info->attrs which points to a nlattr structure
*in this structure the data is given
*/
na = info->attrs[DOC_EXMPL_A_MSG];
if (na) {
mydata = (char *)nla_data(na);
if (mydata == NULL)
printk("error while receiving data\n");
else
printk("received: %s\n", mydata);
}
else
printk("no info->attrs %i\n", DOC_EXMPL_A_MSG);
/* send a message back*/
/* allocate some memory, since the size is not yet known use NLMSG_GOODSIZE*/
skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (skb == NULL)
goto out;
/* create the message headers */
/* arguments of genlmsg_put:
struct sk_buff *,
int (sending) pid,
int sequence number,
struct genl_family *,
int flags,
u8 command index (why do we need this?)
*/
msg_head = genlmsg_put(skb, 0, info->snd_seq+1, &doc_exmpl_gnl_family, 0, DOC_EXMPL_C_ECHO);
if (msg_head == NULL) {
rc = -ENOMEM;
goto out;
}
/* add a DOC_EXMPL_A_MSG attribute (actual value to be sent) */
rc = nla_put_string(skb, DOC_EXMPL_A_MSG, "hello world from kernel space");
if (rc != 0)
goto out;
/* finalize the message */
genlmsg_end(skb, msg_head);
/* send the message back */
rc = genlmsg_unicast(skb,info->snd_pid );
if (rc != 0)
goto out;
return 0;
out:
printk("an error occured in doc_exmpl_echo:\n");
return 0;
}
/* commands: mapping between the command enumeration and the actual function*/
struct genl_ops doc_exmpl_gnl_ops_echo = {
.cmd = DOC_EXMPL_C_ECHO,
.flags = 0,
.policy = doc_exmpl_genl_policy,
.doit = doc_exmpl_echo,
.dumpit = NULL,
};
static int __init gnKernel_init(void)
{
int rc;
printk("INIT GENERIC NETLINK EXEMPLE MODULE\n");
/*register new family*/
rc = genl_register_family(&doc_exmpl_gnl_family);
if (rc != 0)
goto failure;
/*register functions (commands) of the new family*/
rc = genl_register_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo);
if (rc != 0){
printk("register ops: %i\n",rc);
genl_unregister_family(&doc_exmpl_gnl_family);
goto failure;
}
return 0;
failure:
printk("an error occured while inserting the generic netlink example module\n");
return -1;
}
static void __exit gnKernel_exit(void)
{
int ret;
printk("EXIT GENERIC NETLINK EXEMPLE MODULE\n");
/*unregister the functions*/
ret = genl_unregister_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo);
if(ret != 0){
printk("unregister ops: %i\n",ret);
return;
}
/*unregister the family*/
ret = genl_unregister_family(&doc_exmpl_gnl_family);
if(ret !=0){
printk("unregister family %i\n",ret);
}
}
module_init(gnKernel_init);
module_exit(gnKernel_exit);
MODULE_LICENSE("GPL");