diff options
Diffstat (limited to 'drivers/w1/w1_netlink.c')
-rw-r--r-- | drivers/w1/w1_netlink.c | 359 |
1 files changed, 263 insertions, 96 deletions
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 40788c925d1c..5234964fe001 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -45,7 +45,7 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | |||
45 | 45 | ||
46 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); | 46 | memcpy(w, msg, sizeof(struct w1_netlink_msg)); |
47 | 47 | ||
48 | cn_netlink_send(m, 0, GFP_KERNEL); | 48 | cn_netlink_send(m, dev->portid, 0, GFP_KERNEL); |
49 | } | 49 | } |
50 | 50 | ||
51 | static void w1_send_slave(struct w1_master *dev, u64 rn) | 51 | static void w1_send_slave(struct w1_master *dev, u64 rn) |
@@ -54,53 +54,95 @@ static void w1_send_slave(struct w1_master *dev, u64 rn) | |||
54 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); | 54 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); |
55 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); | 55 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); |
56 | int avail; | 56 | int avail; |
57 | 57 | u64 *data; | |
58 | /* update kernel slave list */ | ||
59 | w1_slave_found(dev, rn); | ||
60 | 58 | ||
61 | avail = dev->priv_size - cmd->len; | 59 | avail = dev->priv_size - cmd->len; |
62 | 60 | ||
63 | if (avail > 8) { | 61 | if (avail < 8) { |
64 | u64 *data = (void *)(cmd + 1) + cmd->len; | 62 | msg->ack++; |
63 | cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); | ||
65 | 64 | ||
66 | *data = rn; | 65 | msg->len = sizeof(struct w1_netlink_msg) + |
67 | cmd->len += 8; | 66 | sizeof(struct w1_netlink_cmd); |
68 | hdr->len += 8; | 67 | hdr->len = sizeof(struct w1_netlink_cmd); |
69 | msg->len += 8; | 68 | cmd->len = 0; |
70 | return; | ||
71 | } | 69 | } |
72 | 70 | ||
73 | msg->ack++; | 71 | data = (void *)(cmd + 1) + cmd->len; |
74 | cn_netlink_send(msg, 0, GFP_KERNEL); | ||
75 | 72 | ||
76 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | 73 | *data = rn; |
77 | hdr->len = sizeof(struct w1_netlink_cmd); | 74 | cmd->len += 8; |
78 | cmd->len = 0; | 75 | hdr->len += 8; |
76 | msg->len += 8; | ||
79 | } | 77 | } |
80 | 78 | ||
81 | static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, | 79 | static void w1_found_send_slave(struct w1_master *dev, u64 rn) |
82 | unsigned int avail) | ||
83 | { | 80 | { |
84 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); | 81 | /* update kernel slave list */ |
85 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); | 82 | w1_slave_found(dev, rn); |
86 | int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH; | ||
87 | 83 | ||
88 | dev->priv = msg; | 84 | w1_send_slave(dev, rn); |
89 | dev->priv_size = avail; | 85 | } |
86 | |||
87 | /* Get the current slave list, or search (with or without alarm) */ | ||
88 | static int w1_get_slaves(struct w1_master *dev, | ||
89 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, | ||
90 | struct w1_netlink_cmd *req_cmd) | ||
91 | { | ||
92 | struct cn_msg *msg; | ||
93 | struct w1_netlink_msg *hdr; | ||
94 | struct w1_netlink_cmd *cmd; | ||
95 | struct w1_slave *sl; | ||
96 | |||
97 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
98 | if (!msg) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | msg->id = req_msg->id; | ||
102 | msg->seq = req_msg->seq; | ||
103 | msg->ack = 0; | ||
104 | msg->len = sizeof(struct w1_netlink_msg) + | ||
105 | sizeof(struct w1_netlink_cmd); | ||
106 | |||
107 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
108 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
109 | |||
110 | hdr->type = W1_MASTER_CMD; | ||
111 | hdr->id = req_hdr->id; | ||
112 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
113 | |||
114 | cmd->cmd = req_cmd->cmd; | ||
115 | cmd->len = 0; | ||
90 | 116 | ||
91 | w1_search_process_cb(dev, search_type, w1_send_slave); | 117 | dev->priv = msg; |
118 | dev->priv_size = PAGE_SIZE - msg->len - sizeof(struct cn_msg); | ||
119 | |||
120 | if (req_cmd->cmd == W1_CMD_LIST_SLAVES) { | ||
121 | __u64 rn; | ||
122 | mutex_lock(&dev->list_mutex); | ||
123 | list_for_each_entry(sl, &dev->slist, w1_slave_entry) { | ||
124 | memcpy(&rn, &sl->reg_num, sizeof(rn)); | ||
125 | w1_send_slave(dev, rn); | ||
126 | } | ||
127 | mutex_unlock(&dev->list_mutex); | ||
128 | } else { | ||
129 | w1_search_process_cb(dev, cmd->cmd == W1_CMD_ALARM_SEARCH ? | ||
130 | W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave); | ||
131 | } | ||
92 | 132 | ||
93 | msg->ack = 0; | 133 | msg->ack = 0; |
94 | cn_netlink_send(msg, 0, GFP_KERNEL); | 134 | cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); |
95 | 135 | ||
96 | dev->priv = NULL; | 136 | dev->priv = NULL; |
97 | dev->priv_size = 0; | 137 | dev->priv_size = 0; |
98 | 138 | ||
139 | kfree(msg); | ||
140 | |||
99 | return 0; | 141 | return 0; |
100 | } | 142 | } |
101 | 143 | ||
102 | static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, | 144 | static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, |
103 | struct w1_netlink_cmd *cmd) | 145 | struct w1_netlink_cmd *cmd, u32 portid) |
104 | { | 146 | { |
105 | void *data; | 147 | void *data; |
106 | struct w1_netlink_msg *h; | 148 | struct w1_netlink_msg *h; |
@@ -131,7 +173,7 @@ static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, | |||
131 | 173 | ||
132 | memcpy(c->data, cmd->data, c->len); | 174 | memcpy(c->data, cmd->data, c->len); |
133 | 175 | ||
134 | err = cn_netlink_send(cm, 0, GFP_KERNEL); | 176 | err = cn_netlink_send(cm, portid, 0, GFP_KERNEL); |
135 | 177 | ||
136 | kfree(data); | 178 | kfree(data); |
137 | 179 | ||
@@ -146,11 +188,11 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | |||
146 | switch (cmd->cmd) { | 188 | switch (cmd->cmd) { |
147 | case W1_CMD_TOUCH: | 189 | case W1_CMD_TOUCH: |
148 | w1_touch_block(dev, cmd->data, cmd->len); | 190 | w1_touch_block(dev, cmd->data, cmd->len); |
149 | w1_send_read_reply(msg, hdr, cmd); | 191 | w1_send_read_reply(msg, hdr, cmd, dev->portid); |
150 | break; | 192 | break; |
151 | case W1_CMD_READ: | 193 | case W1_CMD_READ: |
152 | w1_read_block(dev, cmd->data, cmd->len); | 194 | w1_read_block(dev, cmd->data, cmd->len); |
153 | w1_send_read_reply(msg, hdr, cmd); | 195 | w1_send_read_reply(msg, hdr, cmd, dev->portid); |
154 | break; | 196 | break; |
155 | case W1_CMD_WRITE: | 197 | case W1_CMD_WRITE: |
156 | w1_write_block(dev, cmd->data, cmd->len); | 198 | w1_write_block(dev, cmd->data, cmd->len); |
@@ -163,38 +205,57 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | |||
163 | return err; | 205 | return err; |
164 | } | 206 | } |
165 | 207 | ||
166 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, | 208 | static int w1_process_command_addremove(struct w1_master *dev, |
167 | struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) | 209 | struct cn_msg *msg, struct w1_netlink_msg *hdr, |
210 | struct w1_netlink_cmd *cmd) | ||
168 | { | 211 | { |
169 | int err = -EINVAL; | 212 | struct w1_slave *sl; |
170 | struct cn_msg *msg; | 213 | int err = 0; |
171 | struct w1_netlink_msg *hdr; | 214 | struct w1_reg_num *id; |
172 | struct w1_netlink_cmd *cmd; | ||
173 | 215 | ||
174 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | 216 | if (cmd->len != 8) |
175 | if (!msg) | 217 | return -EINVAL; |
176 | return -ENOMEM; | ||
177 | 218 | ||
178 | msg->id = req_msg->id; | 219 | id = (struct w1_reg_num *)cmd->data; |
179 | msg->seq = req_msg->seq; | ||
180 | msg->ack = 0; | ||
181 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
182 | 220 | ||
183 | hdr = (struct w1_netlink_msg *)(msg + 1); | 221 | sl = w1_slave_search_device(dev, id); |
184 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | 222 | switch (cmd->cmd) { |
223 | case W1_CMD_SLAVE_ADD: | ||
224 | if (sl) | ||
225 | err = -EINVAL; | ||
226 | else | ||
227 | err = w1_attach_slave_device(dev, id); | ||
228 | break; | ||
229 | case W1_CMD_SLAVE_REMOVE: | ||
230 | if (sl) | ||
231 | w1_slave_detach(sl); | ||
232 | else | ||
233 | err = -EINVAL; | ||
234 | break; | ||
235 | default: | ||
236 | err = -EINVAL; | ||
237 | break; | ||
238 | } | ||
185 | 239 | ||
186 | hdr->type = W1_MASTER_CMD; | 240 | return err; |
187 | hdr->id = req_hdr->id; | 241 | } |
188 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
189 | 242 | ||
190 | cmd->cmd = req_cmd->cmd; | 243 | static int w1_process_command_master(struct w1_master *dev, |
191 | cmd->len = 0; | 244 | struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, |
245 | struct w1_netlink_cmd *req_cmd) | ||
246 | { | ||
247 | int err = -EINVAL; | ||
192 | 248 | ||
193 | switch (cmd->cmd) { | 249 | /* drop bus_mutex for search (does it's own locking), and add/remove |
250 | * which doesn't use the bus | ||
251 | */ | ||
252 | switch (req_cmd->cmd) { | ||
194 | case W1_CMD_SEARCH: | 253 | case W1_CMD_SEARCH: |
195 | case W1_CMD_ALARM_SEARCH: | 254 | case W1_CMD_ALARM_SEARCH: |
196 | err = w1_process_search_command(dev, msg, | 255 | case W1_CMD_LIST_SLAVES: |
197 | PAGE_SIZE - msg->len - sizeof(struct cn_msg)); | 256 | mutex_unlock(&dev->bus_mutex); |
257 | err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); | ||
258 | mutex_lock(&dev->bus_mutex); | ||
198 | break; | 259 | break; |
199 | case W1_CMD_READ: | 260 | case W1_CMD_READ: |
200 | case W1_CMD_WRITE: | 261 | case W1_CMD_WRITE: |
@@ -204,12 +265,20 @@ static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_m | |||
204 | case W1_CMD_RESET: | 265 | case W1_CMD_RESET: |
205 | err = w1_reset_bus(dev); | 266 | err = w1_reset_bus(dev); |
206 | break; | 267 | break; |
268 | case W1_CMD_SLAVE_ADD: | ||
269 | case W1_CMD_SLAVE_REMOVE: | ||
270 | mutex_unlock(&dev->bus_mutex); | ||
271 | mutex_lock(&dev->mutex); | ||
272 | err = w1_process_command_addremove(dev, req_msg, req_hdr, | ||
273 | req_cmd); | ||
274 | mutex_unlock(&dev->mutex); | ||
275 | mutex_lock(&dev->bus_mutex); | ||
276 | break; | ||
207 | default: | 277 | default: |
208 | err = -EINVAL; | 278 | err = -EINVAL; |
209 | break; | 279 | break; |
210 | } | 280 | } |
211 | 281 | ||
212 | kfree(msg); | ||
213 | return err; | 282 | return err; |
214 | } | 283 | } |
215 | 284 | ||
@@ -223,7 +292,8 @@ static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | |||
223 | return w1_process_command_io(sl->master, msg, hdr, cmd); | 292 | return w1_process_command_io(sl->master, msg, hdr, cmd); |
224 | } | 293 | } |
225 | 294 | ||
226 | static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) | 295 | static int w1_process_command_root(struct cn_msg *msg, |
296 | struct w1_netlink_msg *mcmd, u32 portid) | ||
227 | { | 297 | { |
228 | struct w1_master *m; | 298 | struct w1_master *m; |
229 | struct cn_msg *cn; | 299 | struct cn_msg *cn; |
@@ -256,7 +326,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
256 | mutex_lock(&w1_mlock); | 326 | mutex_lock(&w1_mlock); |
257 | list_for_each_entry(m, &w1_masters, w1_master_entry) { | 327 | list_for_each_entry(m, &w1_masters, w1_master_entry) { |
258 | if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { | 328 | if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { |
259 | cn_netlink_send(cn, 0, GFP_KERNEL); | 329 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); |
260 | cn->ack++; | 330 | cn->ack++; |
261 | cn->len = sizeof(struct w1_netlink_msg); | 331 | cn->len = sizeof(struct w1_netlink_msg); |
262 | w->len = 0; | 332 | w->len = 0; |
@@ -269,7 +339,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
269 | id++; | 339 | id++; |
270 | } | 340 | } |
271 | cn->ack = 0; | 341 | cn->ack = 0; |
272 | cn_netlink_send(cn, 0, GFP_KERNEL); | 342 | cn_netlink_send(cn, portid, 0, GFP_KERNEL); |
273 | mutex_unlock(&w1_mlock); | 343 | mutex_unlock(&w1_mlock); |
274 | 344 | ||
275 | kfree(cn); | 345 | kfree(cn); |
@@ -277,7 +347,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
277 | } | 347 | } |
278 | 348 | ||
279 | static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, | 349 | static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, |
280 | struct w1_netlink_cmd *rcmd, int error) | 350 | struct w1_netlink_cmd *rcmd, int portid, int error) |
281 | { | 351 | { |
282 | struct cn_msg *cmsg; | 352 | struct cn_msg *cmsg; |
283 | struct w1_netlink_msg *msg; | 353 | struct w1_netlink_msg *msg; |
@@ -304,35 +374,147 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm | |||
304 | cmsg->len += sizeof(*cmd); | 374 | cmsg->len += sizeof(*cmd); |
305 | } | 375 | } |
306 | 376 | ||
307 | error = cn_netlink_send(cmsg, 0, GFP_KERNEL); | 377 | error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL); |
308 | kfree(cmsg); | 378 | kfree(cmsg); |
309 | 379 | ||
310 | return error; | 380 | return error; |
311 | } | 381 | } |
312 | 382 | ||
383 | /* Bundle together a reference count, the full message, and broken out | ||
384 | * commands to be executed on each w1 master kthread in one memory allocation. | ||
385 | */ | ||
386 | struct w1_cb_block { | ||
387 | atomic_t refcnt; | ||
388 | u32 portid; /* Sending process port ID */ | ||
389 | struct cn_msg msg; | ||
390 | /* cn_msg data */ | ||
391 | /* one or more variable length struct w1_cb_node */ | ||
392 | }; | ||
393 | struct w1_cb_node { | ||
394 | struct w1_async_cmd async; | ||
395 | /* pointers within w1_cb_block and msg data */ | ||
396 | struct w1_cb_block *block; | ||
397 | struct w1_netlink_msg *m; | ||
398 | struct w1_slave *sl; | ||
399 | struct w1_master *dev; | ||
400 | }; | ||
401 | |||
402 | static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) | ||
403 | { | ||
404 | struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node, | ||
405 | async); | ||
406 | u16 mlen = node->m->len; | ||
407 | u8 *cmd_data = node->m->data; | ||
408 | int err = 0; | ||
409 | struct w1_slave *sl = node->sl; | ||
410 | struct w1_netlink_cmd *cmd = NULL; | ||
411 | |||
412 | mutex_lock(&dev->bus_mutex); | ||
413 | dev->portid = node->block->portid; | ||
414 | if (sl && w1_reset_select_slave(sl)) | ||
415 | err = -ENODEV; | ||
416 | |||
417 | while (mlen && !err) { | ||
418 | cmd = (struct w1_netlink_cmd *)cmd_data; | ||
419 | |||
420 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
421 | err = -E2BIG; | ||
422 | break; | ||
423 | } | ||
424 | |||
425 | if (sl) | ||
426 | err = w1_process_command_slave(sl, &node->block->msg, | ||
427 | node->m, cmd); | ||
428 | else | ||
429 | err = w1_process_command_master(dev, &node->block->msg, | ||
430 | node->m, cmd); | ||
431 | |||
432 | w1_netlink_send_error(&node->block->msg, node->m, cmd, | ||
433 | node->block->portid, err); | ||
434 | err = 0; | ||
435 | |||
436 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
437 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
438 | } | ||
439 | |||
440 | if (!cmd || err) | ||
441 | w1_netlink_send_error(&node->block->msg, node->m, cmd, | ||
442 | node->block->portid, err); | ||
443 | |||
444 | if (sl) | ||
445 | w1_unref_slave(sl); | ||
446 | else | ||
447 | atomic_dec(&dev->refcnt); | ||
448 | dev->portid = 0; | ||
449 | mutex_unlock(&dev->bus_mutex); | ||
450 | |||
451 | mutex_lock(&dev->list_mutex); | ||
452 | list_del(&async_cmd->async_entry); | ||
453 | mutex_unlock(&dev->list_mutex); | ||
454 | |||
455 | if (atomic_sub_return(1, &node->block->refcnt) == 0) | ||
456 | kfree(node->block); | ||
457 | } | ||
458 | |||
313 | static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | 459 | static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) |
314 | { | 460 | { |
315 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); | 461 | struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); |
316 | struct w1_netlink_cmd *cmd; | ||
317 | struct w1_slave *sl; | 462 | struct w1_slave *sl; |
318 | struct w1_master *dev; | 463 | struct w1_master *dev; |
464 | u16 msg_len; | ||
319 | int err = 0; | 465 | int err = 0; |
466 | struct w1_cb_block *block = NULL; | ||
467 | struct w1_cb_node *node = NULL; | ||
468 | int node_count = 0; | ||
469 | |||
470 | /* Count the number of master or slave commands there are to allocate | ||
471 | * space for one cb_node each. | ||
472 | */ | ||
473 | msg_len = msg->len; | ||
474 | while (msg_len && !err) { | ||
475 | if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { | ||
476 | err = -E2BIG; | ||
477 | break; | ||
478 | } | ||
479 | |||
480 | if (m->type == W1_MASTER_CMD || m->type == W1_SLAVE_CMD) | ||
481 | ++node_count; | ||
320 | 482 | ||
321 | while (msg->len && !err) { | 483 | msg_len -= sizeof(struct w1_netlink_msg) + m->len; |
484 | m = (struct w1_netlink_msg *)(((u8 *)m) + | ||
485 | sizeof(struct w1_netlink_msg) + m->len); | ||
486 | } | ||
487 | m = (struct w1_netlink_msg *)(msg + 1); | ||
488 | if (node_count) { | ||
489 | /* msg->len doesn't include itself */ | ||
490 | long size = sizeof(struct w1_cb_block) + msg->len + | ||
491 | node_count*sizeof(struct w1_cb_node); | ||
492 | block = kmalloc(size, GFP_KERNEL); | ||
493 | if (!block) { | ||
494 | w1_netlink_send_error(msg, m, NULL, nsp->portid, | ||
495 | -ENOMEM); | ||
496 | return; | ||
497 | } | ||
498 | atomic_set(&block->refcnt, 1); | ||
499 | block->portid = nsp->portid; | ||
500 | memcpy(&block->msg, msg, sizeof(*msg) + msg->len); | ||
501 | node = (struct w1_cb_node *)((u8 *)block->msg.data + msg->len); | ||
502 | } | ||
503 | |||
504 | msg_len = msg->len; | ||
505 | while (msg_len && !err) { | ||
322 | struct w1_reg_num id; | 506 | struct w1_reg_num id; |
323 | u16 mlen = m->len; | 507 | u16 mlen = m->len; |
324 | u8 *cmd_data = m->data; | ||
325 | 508 | ||
326 | dev = NULL; | 509 | dev = NULL; |
327 | sl = NULL; | 510 | sl = NULL; |
328 | cmd = NULL; | ||
329 | 511 | ||
330 | memcpy(&id, m->id.id, sizeof(id)); | 512 | memcpy(&id, m->id.id, sizeof(id)); |
331 | #if 0 | 513 | #if 0 |
332 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", | 514 | printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", |
333 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); | 515 | __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); |
334 | #endif | 516 | #endif |
335 | if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { | 517 | if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { |
336 | err = -E2BIG; | 518 | err = -E2BIG; |
337 | break; | 519 | break; |
338 | } | 520 | } |
@@ -344,7 +526,7 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
344 | if (sl) | 526 | if (sl) |
345 | dev = sl->master; | 527 | dev = sl->master; |
346 | } else { | 528 | } else { |
347 | err = w1_process_command_root(msg, m); | 529 | err = w1_process_command_root(msg, m, nsp->portid); |
348 | goto out_cont; | 530 | goto out_cont; |
349 | } | 531 | } |
350 | 532 | ||
@@ -357,41 +539,24 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) | |||
357 | if (!mlen) | 539 | if (!mlen) |
358 | goto out_cont; | 540 | goto out_cont; |
359 | 541 | ||
360 | mutex_lock(&dev->mutex); | 542 | atomic_inc(&block->refcnt); |
361 | 543 | node->async.cb = w1_process_cb; | |
362 | if (sl && w1_reset_select_slave(sl)) { | 544 | node->block = block; |
363 | err = -ENODEV; | 545 | node->m = (struct w1_netlink_msg *)((u8 *)&block->msg + |
364 | goto out_up; | 546 | (size_t)((u8 *)m - (u8 *)msg)); |
365 | } | 547 | node->sl = sl; |
548 | node->dev = dev; | ||
366 | 549 | ||
367 | while (mlen) { | 550 | mutex_lock(&dev->list_mutex); |
368 | cmd = (struct w1_netlink_cmd *)cmd_data; | 551 | list_add_tail(&node->async.async_entry, &dev->async_list); |
552 | wake_up_process(dev->thread); | ||
553 | mutex_unlock(&dev->list_mutex); | ||
554 | ++node; | ||
369 | 555 | ||
370 | if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { | ||
371 | err = -E2BIG; | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | if (sl) | ||
376 | err = w1_process_command_slave(sl, msg, m, cmd); | ||
377 | else | ||
378 | err = w1_process_command_master(dev, msg, m, cmd); | ||
379 | |||
380 | w1_netlink_send_error(msg, m, cmd, err); | ||
381 | err = 0; | ||
382 | |||
383 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | ||
384 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | ||
385 | } | ||
386 | out_up: | ||
387 | atomic_dec(&dev->refcnt); | ||
388 | if (sl) | ||
389 | atomic_dec(&sl->refcnt); | ||
390 | mutex_unlock(&dev->mutex); | ||
391 | out_cont: | 556 | out_cont: |
392 | if (!cmd || err) | 557 | if (err) |
393 | w1_netlink_send_error(msg, m, cmd, err); | 558 | w1_netlink_send_error(msg, m, NULL, nsp->portid, err); |
394 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | 559 | msg_len -= sizeof(struct w1_netlink_msg) + m->len; |
395 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | 560 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); |
396 | 561 | ||
397 | /* | 562 | /* |
@@ -400,6 +565,8 @@ out_cont: | |||
400 | if (err == -ENODEV) | 565 | if (err == -ENODEV) |
401 | err = 0; | 566 | err = 0; |
402 | } | 567 | } |
568 | if (block && atomic_sub_return(1, &block->refcnt) == 0) | ||
569 | kfree(block); | ||
403 | } | 570 | } |
404 | 571 | ||
405 | int w1_init_netlink(void) | 572 | int w1_init_netlink(void) |