Blame view
drivers/connector/connector.c
6.64 KB
1a59d1b8e treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
7672d0b54 [NET]: Add netlin... |
2 |
/* |
f3c48ecce drivers: connecto... |
3 |
* connector.c |
1a5645bc9 connector: create... |
4 |
* |
acb9c1b2f connector: mainta... |
5 |
* 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> |
7672d0b54 [NET]: Add netlin... |
6 |
* All rights reserved. |
7672d0b54 [NET]: Add netlin... |
7 |
*/ |
d2af686c2 connector: fix de... |
8 |
#include <linux/compiler.h> |
7672d0b54 [NET]: Add netlin... |
9 10 11 12 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/list.h> #include <linux/skbuff.h> |
9631d79e8 connector: replac... |
13 |
#include <net/netlink.h> |
7672d0b54 [NET]: Add netlin... |
14 15 |
#include <linux/moduleparam.h> #include <linux/connector.h> |
5a0e3ad6a include cleanup: ... |
16 |
#include <linux/slab.h> |
8ed965d61 [PATCH] sem2mutex... |
17 |
#include <linux/mutex.h> |
a0a61a604 CONNECTOR: add a ... |
18 19 |
#include <linux/proc_fs.h> #include <linux/spinlock.h> |
7672d0b54 [NET]: Add netlin... |
20 21 22 23 |
#include <net/sock.h> MODULE_LICENSE("GPL"); |
acb9c1b2f connector: mainta... |
24 |
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); |
7672d0b54 [NET]: Add netlin... |
25 |
MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector."); |
3700c3c29 connector: add mo... |
26 |
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_CONNECTOR); |
7672d0b54 [NET]: Add netlin... |
27 |
|
7672d0b54 [NET]: Add netlin... |
28 |
static struct cn_dev cdev; |
78374676e CONNECTOR: make c... |
29 |
static int cn_already_initialized; |
7672d0b54 [NET]: Add netlin... |
30 31 |
/* |
34470e0bf connector: allow ... |
32 33 |
* Sends mult (multiple) cn_msg at a time. * |
7672d0b54 [NET]: Add netlin... |
34 35 36 37 38 39 40 |
* msg->seq and msg->ack are used to determine message genealogy. * When someone sends message it puts there locally unique sequence * and random acknowledge numbers. Sequence number may be copied into * nlmsghdr->nlmsg_seq too. * * Sequence number is incremented with each message to be sent. * |
ac8f73305 connector: add po... |
41 |
* If we expect a reply to our message then the sequence number in |
7672d0b54 [NET]: Add netlin... |
42 43 44 45 46 47 48 49 50 51 52 |
* received message MUST be the same as in original message, and * acknowledge number MUST be the same + 1. * * If we receive a message and its sequence number is not equal to the * one we are expecting then it is a new message. * * If we receive a message and its sequence number is the same as one * we are expecting but it's acknowledgement number is not equal to * the acknowledgement number in the original message + 1, then it is * a new message. * |
34470e0bf connector: allow ... |
53 54 55 |
* If msg->len != len, then additional cn_msg messages are expected following * the first msg. * |
ac8f73305 connector: add po... |
56 57 |
* The message is sent to, the portid if given, the group if given, both if * both, or if both are zero then the group is looked up and sent there. |
7672d0b54 [NET]: Add netlin... |
58 |
*/ |
34470e0bf connector: allow ... |
59 |
int cn_netlink_send_mult(struct cn_msg *msg, u16 len, u32 portid, u32 __group, |
ac8f73305 connector: add po... |
60 |
gfp_t gfp_mask) |
7672d0b54 [NET]: Add netlin... |
61 62 63 64 65 66 67 68 69 |
{ struct cn_callback_entry *__cbq; unsigned int size; struct sk_buff *skb; struct nlmsghdr *nlh; struct cn_msg *data; struct cn_dev *dev = &cdev; u32 group = 0; int found = 0; |
ac8f73305 connector: add po... |
70 71 72 |
if (portid || __group) { group = __group; } else { |
7672d0b54 [NET]: Add netlin... |
73 74 75 |
spin_lock_bh(&dev->cbdev->queue_lock); list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) { |
acd042bb2 [CONNECTOR]: asyn... |
76 |
if (cn_cb_equal(&__cbq->id.id, &msg->id)) { |
7672d0b54 [NET]: Add netlin... |
77 78 |
found = 1; group = __cbq->group; |
fd00eeccd [CONNECTOR]: add ... |
79 |
break; |
7672d0b54 [NET]: Add netlin... |
80 81 82 83 84 85 |
} } spin_unlock_bh(&dev->cbdev->queue_lock); if (!found) return -ENODEV; |
7672d0b54 [NET]: Add netlin... |
86 |
} |
ac8f73305 connector: add po... |
87 |
if (!portid && !netlink_has_listeners(dev->nls, group)) |
b191ba0d5 [CONNECTOR]: Use ... |
88 |
return -ESRCH; |
34470e0bf connector: allow ... |
89 |
size = sizeof(*msg) + len; |
7672d0b54 [NET]: Add netlin... |
90 |
|
9631d79e8 connector: replac... |
91 |
skb = nlmsg_new(size, gfp_mask); |
7672d0b54 [NET]: Add netlin... |
92 93 |
if (!skb) return -ENOMEM; |
9631d79e8 connector: replac... |
94 |
nlh = nlmsg_put(skb, 0, msg->seq, NLMSG_DONE, size, 0); |
85c931665 connector: use nl... |
95 96 97 98 |
if (!nlh) { kfree_skb(skb); return -EMSGSIZE; } |
7672d0b54 [NET]: Add netlin... |
99 |
|
85c931665 connector: use nl... |
100 |
data = nlmsg_data(nlh); |
7672d0b54 [NET]: Add netlin... |
101 |
|
ac73bf50b connector: use 's... |
102 |
memcpy(data, msg, size); |
7672d0b54 [NET]: Add netlin... |
103 104 |
NETLINK_CB(skb).dst_group = group; |
ac8f73305 connector: add po... |
105 106 107 |
if (group) return netlink_broadcast(dev->nls, skb, portid, group, gfp_mask); |
d0164adc8 mm, page_alloc: d... |
108 109 |
return netlink_unicast(dev->nls, skb, portid, !gfpflags_allow_blocking(gfp_mask)); |
7672d0b54 [NET]: Add netlin... |
110 |
} |
34470e0bf connector: allow ... |
111 112 113 114 115 116 117 118 |
EXPORT_SYMBOL_GPL(cn_netlink_send_mult); /* same as cn_netlink_send_mult except msg->len is used for len */ int cn_netlink_send(struct cn_msg *msg, u32 portid, u32 __group, gfp_t gfp_mask) { return cn_netlink_send_mult(msg, msg->len, portid, __group, gfp_mask); } |
deb0e9b23 [PATCH] connector... |
119 |
EXPORT_SYMBOL_GPL(cn_netlink_send); |
7672d0b54 [NET]: Add netlin... |
120 121 122 123 |
/* * Callback helper - queues work and setup destructor for given data. */ |
f1489cfb1 connector: Remove... |
124 |
static int cn_call_callback(struct sk_buff *skb) |
7672d0b54 [NET]: Add netlin... |
125 |
{ |
a30cfa475 cn: verify msg->l... |
126 |
struct nlmsghdr *nlh; |
04f482faf connector: conver... |
127 |
struct cn_callback_entry *i, *cbq = NULL; |
7672d0b54 [NET]: Add netlin... |
128 |
struct cn_dev *dev = &cdev; |
9631d79e8 connector: replac... |
129 |
struct cn_msg *msg = nlmsg_data(nlmsg_hdr(skb)); |
04f482faf connector: conver... |
130 |
struct netlink_skb_parms *nsp = &NETLINK_CB(skb); |
acd042bb2 [CONNECTOR]: asyn... |
131 |
int err = -ENODEV; |
7672d0b54 [NET]: Add netlin... |
132 |
|
a30cfa475 cn: verify msg->l... |
133 134 135 136 |
/* verify msg->len is within skb */ nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < NLMSG_HDRLEN + sizeof(struct cn_msg) + msg->len) return -EINVAL; |
7672d0b54 [NET]: Add netlin... |
137 |
spin_lock_bh(&dev->cbdev->queue_lock); |
04f482faf connector: conver... |
138 139 |
list_for_each_entry(i, &dev->cbdev->queue_list, callback_entry) { if (cn_cb_equal(&i->id.id, &msg->id)) { |
e65f7ee39 drivers, connecto... |
140 |
refcount_inc(&i->refcnt); |
04f482faf connector: conver... |
141 |
cbq = i; |
7672d0b54 [NET]: Add netlin... |
142 143 144 145 |
break; } } spin_unlock_bh(&dev->cbdev->queue_lock); |
04f482faf connector: conver... |
146 147 148 149 |
if (cbq != NULL) { cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); |
0e0878584 connector: fix sk... |
150 |
err = 0; |
04f482faf connector: conver... |
151 |
} |
acd042bb2 [CONNECTOR]: asyn... |
152 |
return err; |
7672d0b54 [NET]: Add netlin... |
153 154 155 |
} /* |
7672d0b54 [NET]: Add netlin... |
156 157 |
* Main netlink receiving function. * |
00f5e06c0 [CONNECTOR]: clea... |
158 |
* It checks skb, netlink header and msg sizes, and calls callback helper. |
7672d0b54 [NET]: Add netlin... |
159 |
*/ |
55285bf09 connector: bump s... |
160 |
static void cn_rx_skb(struct sk_buff *skb) |
7672d0b54 [NET]: Add netlin... |
161 162 |
{ struct nlmsghdr *nlh; |
162b2bedc connector: use nl... |
163 |
int len, err; |
7672d0b54 [NET]: Add netlin... |
164 |
|
9631d79e8 connector: replac... |
165 |
if (skb->len >= NLMSG_HDRLEN) { |
b529ccf27 [NETLINK]: Introd... |
166 |
nlh = nlmsg_hdr(skb); |
162b2bedc connector: use nl... |
167 |
len = nlmsg_len(nlh); |
7672d0b54 [NET]: Add netlin... |
168 |
|
162b2bedc connector: use nl... |
169 |
if (len < (int)sizeof(struct cn_msg) || |
7672d0b54 [NET]: Add netlin... |
170 |
skb->len < nlh->nlmsg_len || |
55285bf09 connector: bump s... |
171 |
len > CONNECTOR_MAX_MSG_SIZE) |
6cf92e98a [CONNECTOR]: Fix ... |
172 |
return; |
7672d0b54 [NET]: Add netlin... |
173 |
|
55285bf09 connector: bump s... |
174 |
err = cn_call_callback(skb_get(skb)); |
7672d0b54 [NET]: Add netlin... |
175 176 177 |
if (err < 0) kfree_skb(skb); } |
7672d0b54 [NET]: Add netlin... |
178 179 180 |
} /* |
7672d0b54 [NET]: Add netlin... |
181 182 183 184 185 |
* Callback add routing - adds callback with given ID and name. * If there is registered callback with the same ID it will not be added. * * May sleep. */ |
008536e84 connector: Conver... |
186 |
int cn_add_callback(struct cb_id *id, const char *name, |
f3c48ecce drivers: connecto... |
187 188 |
void (*callback)(struct cn_msg *, struct netlink_skb_parms *)) |
7672d0b54 [NET]: Add netlin... |
189 |
{ |
7672d0b54 [NET]: Add netlin... |
190 |
struct cn_dev *dev = &cdev; |
7672d0b54 [NET]: Add netlin... |
191 |
|
d6cc7f1a3 [CONNECTOR]: Init... |
192 193 |
if (!cn_already_initialized) return -EAGAIN; |
fe6bc89ab connector: simpli... |
194 |
return cn_queue_add_callback(dev->cbdev, name, id, callback); |
7672d0b54 [NET]: Add netlin... |
195 |
} |
deb0e9b23 [PATCH] connector... |
196 |
EXPORT_SYMBOL_GPL(cn_add_callback); |
7672d0b54 [NET]: Add netlin... |
197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
/* * Callback remove routing - removes callback * with given ID. * If there is no registered callback with given * ID nothing happens. * * May sleep while waiting for reference counter to become zero. */ void cn_del_callback(struct cb_id *id) { struct cn_dev *dev = &cdev; cn_queue_del_callback(dev->cbdev, id); |
7672d0b54 [NET]: Add netlin... |
211 |
} |
deb0e9b23 [PATCH] connector... |
212 |
EXPORT_SYMBOL_GPL(cn_del_callback); |
7672d0b54 [NET]: Add netlin... |
213 |
|
d2af686c2 connector: fix de... |
214 |
static int __maybe_unused cn_proc_show(struct seq_file *m, void *v) |
a0a61a604 CONNECTOR: add a ... |
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
{ struct cn_queue_dev *dev = cdev.cbdev; struct cn_callback_entry *cbq; seq_printf(m, "Name ID "); spin_lock_bh(&dev->queue_lock); list_for_each_entry(cbq, &dev->queue_list, callback_entry) { seq_printf(m, "%-15s %u:%u ", cbq->id.name, cbq->id.id.idx, cbq->id.id.val); } spin_unlock_bh(&dev->queue_lock); return 0; } |
0fe763c57 Drivers: misc: re... |
236 |
static int cn_init(void) |
7672d0b54 [NET]: Add netlin... |
237 238 |
{ struct cn_dev *dev = &cdev; |
a31f2d17b netlink: add netl... |
239 240 |
struct netlink_kernel_cfg cfg = { .groups = CN_NETLINK_USERS + 0xf, |
903e9d1bf connector: remove... |
241 |
.input = cn_rx_skb, |
a31f2d17b netlink: add netl... |
242 |
}; |
7672d0b54 [NET]: Add netlin... |
243 |
|
9f00d9776 netlink: hide str... |
244 |
dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR, &cfg); |
7672d0b54 [NET]: Add netlin... |
245 246 247 248 249 |
if (!dev->nls) return -EIO; dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls); if (!dev->cbdev) { |
b7c6ba6eb [NETNS]: Consolid... |
250 |
netlink_kernel_release(dev->nls); |
7672d0b54 [NET]: Add netlin... |
251 252 |
return -EINVAL; } |
1a5645bc9 connector: create... |
253 |
|
d6cc7f1a3 [CONNECTOR]: Init... |
254 |
cn_already_initialized = 1; |
7672d0b54 [NET]: Add netlin... |
255 |
|
3f3942aca proc: introduce p... |
256 |
proc_create_single("connector", S_IRUGO, init_net.proc_net, cn_proc_show); |
a0a61a604 CONNECTOR: add a ... |
257 |
|
7672d0b54 [NET]: Add netlin... |
258 259 |
return 0; } |
0fe763c57 Drivers: misc: re... |
260 |
static void cn_fini(void) |
7672d0b54 [NET]: Add netlin... |
261 262 263 264 |
{ struct cn_dev *dev = &cdev; cn_already_initialized = 0; |
ece31ffd5 net: proc: change... |
265 |
remove_proc_entry("connector", init_net.proc_net); |
a0a61a604 CONNECTOR: add a ... |
266 |
|
7672d0b54 [NET]: Add netlin... |
267 |
cn_queue_free_dev(dev->cbdev); |
b7c6ba6eb [NETNS]: Consolid... |
268 |
netlink_kernel_release(dev->nls); |
7672d0b54 [NET]: Add netlin... |
269 |
} |
d6cc7f1a3 [CONNECTOR]: Init... |
270 |
subsys_initcall(cn_init); |
7672d0b54 [NET]: Add netlin... |
271 |
module_exit(cn_fini); |