Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
7672d0b5 EP |
2 | /* |
3 | * cn_test.c | |
4 | * | |
acb9c1b2 | 5 | * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> |
7672d0b5 | 6 | * All rights reserved. |
7672d0b5 EP |
7 | */ |
8 | ||
37cf2b8d MF |
9 | #define pr_fmt(fmt) "cn_test: " fmt |
10 | ||
7672d0b5 EP |
11 | #include <linux/kernel.h> |
12 | #include <linux/module.h> | |
13 | #include <linux/moduleparam.h> | |
14 | #include <linux/skbuff.h> | |
5a0e3ad6 | 15 | #include <linux/slab.h> |
7672d0b5 EP |
16 | #include <linux/timer.h> |
17 | ||
18a0c236 | 18 | #include <linux/connector.h> |
7672d0b5 | 19 | |
37cf2b8d | 20 | static struct cb_id cn_test_id = { CN_NETLINK_USERS + 3, 0x456 }; |
7672d0b5 EP |
21 | static char cn_test_name[] = "cn_test"; |
22 | static struct sock *nls; | |
23 | static struct timer_list cn_test_timer; | |
24 | ||
7069331d | 25 | static void cn_test_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) |
7672d0b5 | 26 | { |
37cf2b8d MF |
27 | pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", |
28 | __func__, jiffies, msg->id.idx, msg->id.val, | |
29 | msg->seq, msg->ack, msg->len, | |
30 | msg->len ? (char *)msg->data : ""); | |
7672d0b5 EP |
31 | } |
32 | ||
28f06c6f JSR |
33 | /* |
34 | * Do not remove this function even if no one is using it as | |
35 | * this is an example of how to get notifications about new | |
36 | * connector user registration | |
37 | */ | |
38 | #if 0 | |
7672d0b5 EP |
39 | static int cn_test_want_notify(void) |
40 | { | |
41 | struct cn_ctl_msg *ctl; | |
42 | struct cn_notify_req *req; | |
43 | struct cn_msg *msg = NULL; | |
44 | int size, size0; | |
45 | struct sk_buff *skb; | |
46 | struct nlmsghdr *nlh; | |
47 | u32 group = 1; | |
48 | ||
49 | size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req); | |
50 | ||
51 | size = NLMSG_SPACE(size0); | |
52 | ||
53 | skb = alloc_skb(size, GFP_ATOMIC); | |
54 | if (!skb) { | |
37cf2b8d | 55 | pr_err("failed to allocate new skb with size=%u\n", size); |
7672d0b5 EP |
56 | return -ENOMEM; |
57 | } | |
58 | ||
8786395c DM |
59 | nlh = nlmsg_put(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh), 0); |
60 | if (!nlh) { | |
61 | kfree_skb(skb); | |
62 | return -EMSGSIZE; | |
63 | } | |
7672d0b5 | 64 | |
8786395c | 65 | msg = nlmsg_data(nlh); |
7672d0b5 EP |
66 | |
67 | memset(msg, 0, size0); | |
68 | ||
69 | msg->id.idx = -1; | |
70 | msg->id.val = -1; | |
71 | msg->seq = 0x123; | |
72 | msg->ack = 0x345; | |
73 | msg->len = size0 - sizeof(*msg); | |
74 | ||
75 | ctl = (struct cn_ctl_msg *)(msg + 1); | |
76 | ||
77 | ctl->idx_notify_num = 1; | |
78 | ctl->val_notify_num = 2; | |
79 | ctl->group = group; | |
80 | ctl->len = msg->len - sizeof(*ctl); | |
81 | ||
82 | req = (struct cn_notify_req *)(ctl + 1); | |
83 | ||
84 | /* | |
85 | * Idx. | |
86 | */ | |
87 | req->first = cn_test_id.idx; | |
88 | req->range = 10; | |
89 | ||
90 | /* | |
91 | * Val 0. | |
92 | */ | |
93 | req++; | |
94 | req->first = cn_test_id.val; | |
95 | req->range = 10; | |
96 | ||
97 | /* | |
98 | * Val 1. | |
99 | */ | |
100 | req++; | |
101 | req->first = cn_test_id.val + 20; | |
102 | req->range = 10; | |
103 | ||
18a0c236 | 104 | NETLINK_CB(skb).dst_group = ctl->group; |
7672d0b5 EP |
105 | //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC); |
106 | netlink_unicast(nls, skb, 0, 0); | |
107 | ||
37cf2b8d | 108 | pr_info("request was sent: group=0x%x\n", ctl->group); |
7672d0b5 EP |
109 | |
110 | return 0; | |
7672d0b5 | 111 | } |
28f06c6f | 112 | #endif |
7672d0b5 EP |
113 | |
114 | static u32 cn_test_timer_counter; | |
0d694234 | 115 | static void cn_test_timer_func(struct timer_list *unused) |
7672d0b5 EP |
116 | { |
117 | struct cn_msg *m; | |
118 | char data[32]; | |
119 | ||
0d694234 | 120 | pr_debug("%s: timer fired\n", __func__); |
37cf2b8d | 121 | |
dd00cc48 | 122 | m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); |
7672d0b5 | 123 | if (m) { |
7672d0b5 EP |
124 | |
125 | memcpy(&m->id, &cn_test_id, sizeof(m->id)); | |
126 | m->seq = cn_test_timer_counter; | |
127 | m->len = sizeof(data); | |
128 | ||
129 | m->len = | |
130 | scnprintf(data, sizeof(data), "counter = %u", | |
131 | cn_test_timer_counter) + 1; | |
132 | ||
133 | memcpy(m + 1, data, m->len); | |
134 | ||
ac8f7330 | 135 | cn_netlink_send(m, 0, 0, GFP_ATOMIC); |
7672d0b5 EP |
136 | kfree(m); |
137 | } | |
138 | ||
139 | cn_test_timer_counter++; | |
140 | ||
37cf2b8d | 141 | mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); |
7672d0b5 EP |
142 | } |
143 | ||
144 | static int cn_test_init(void) | |
145 | { | |
146 | int err; | |
147 | ||
148 | err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback); | |
149 | if (err) | |
150 | goto err_out; | |
151 | cn_test_id.val++; | |
152 | err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback); | |
153 | if (err) { | |
154 | cn_del_callback(&cn_test_id); | |
155 | goto err_out; | |
156 | } | |
157 | ||
0d694234 | 158 | timer_setup(&cn_test_timer, cn_test_timer_func, 0); |
37cf2b8d MF |
159 | mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); |
160 | ||
161 | pr_info("initialized with id={%u.%u}\n", | |
162 | cn_test_id.idx, cn_test_id.val); | |
7672d0b5 EP |
163 | |
164 | return 0; | |
165 | ||
166 | err_out: | |
167 | if (nls && nls->sk_socket) | |
168 | sock_release(nls->sk_socket); | |
169 | ||
170 | return err; | |
171 | } | |
172 | ||
173 | static void cn_test_fini(void) | |
174 | { | |
175 | del_timer_sync(&cn_test_timer); | |
176 | cn_del_callback(&cn_test_id); | |
177 | cn_test_id.val--; | |
178 | cn_del_callback(&cn_test_id); | |
179 | if (nls && nls->sk_socket) | |
180 | sock_release(nls->sk_socket); | |
181 | } | |
182 | ||
183 | module_init(cn_test_init); | |
184 | module_exit(cn_test_fini); | |
185 | ||
186 | MODULE_LICENSE("GPL"); | |
acb9c1b2 | 187 | MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); |
7672d0b5 | 188 | MODULE_DESCRIPTION("Connector's test module"); |