1 /* 2 * w1_netlink.c 3 * 4 * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net> 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <linux/slab.h> 23 #include <linux/skbuff.h> 24 #include <linux/netlink.h> 25 #include <linux/connector.h> 26 27 #include "w1.h" 28 #include "w1_log.h" 29 #include "w1_netlink.h" 30 31 #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) 32 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) 33 { 34 char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; 35 struct cn_msg *m = (struct cn_msg *)buf; 36 struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); 37 38 memset(buf, 0, sizeof(buf)); 39 40 m->id.idx = CN_W1_IDX; 41 m->id.val = CN_W1_VAL; 42 43 m->seq = dev->seq++; 44 m->len = sizeof(struct w1_netlink_msg); 45 46 memcpy(w, msg, sizeof(struct w1_netlink_msg)); 47 48 cn_netlink_send(m, dev->portid, 0, GFP_KERNEL); 49 } 50 51 static void w1_send_slave(struct w1_master *dev, u64 rn) 52 { 53 struct cn_msg *msg = dev->priv; 54 struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); 55 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); 56 int avail; 57 u64 *data; 58 59 avail = dev->priv_size - cmd->len; 60 61 if (avail < 8) { 62 msg->ack++; 63 cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); 64 65 msg->len = sizeof(struct w1_netlink_msg) + 66 sizeof(struct w1_netlink_cmd); 67 hdr->len = sizeof(struct w1_netlink_cmd); 68 cmd->len = 0; 69 } 70 71 data = (void *)(cmd + 1) + cmd->len; 72 73 *data = rn; 74 cmd->len += 8; 75 hdr->len += 8; 76 msg->len += 8; 77 } 78 79 static void w1_found_send_slave(struct w1_master *dev, u64 rn) 80 { 81 /* update kernel slave list */ 82 w1_slave_found(dev, rn); 83 84 w1_send_slave(dev, rn); 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; 116 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 } 132 133 msg->ack = 0; 134 cn_netlink_send(msg, dev->portid, 0, GFP_KERNEL); 135 136 dev->priv = NULL; 137 dev->priv_size = 0; 138 139 kfree(msg); 140 141 return 0; 142 } 143 144 static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, 145 struct w1_netlink_cmd *cmd, u32 portid) 146 { 147 void *data; 148 struct w1_netlink_msg *h; 149 struct w1_netlink_cmd *c; 150 struct cn_msg *cm; 151 int err; 152 153 data = kzalloc(sizeof(struct cn_msg) + 154 sizeof(struct w1_netlink_msg) + 155 sizeof(struct w1_netlink_cmd) + 156 cmd->len, GFP_KERNEL); 157 if (!data) 158 return -ENOMEM; 159 160 cm = (struct cn_msg *)(data); 161 h = (struct w1_netlink_msg *)(cm + 1); 162 c = (struct w1_netlink_cmd *)(h + 1); 163 164 memcpy(cm, msg, sizeof(struct cn_msg)); 165 memcpy(h, hdr, sizeof(struct w1_netlink_msg)); 166 memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); 167 168 cm->ack = msg->seq+1; 169 cm->len = sizeof(struct w1_netlink_msg) + 170 sizeof(struct w1_netlink_cmd) + cmd->len; 171 172 h->len = sizeof(struct w1_netlink_cmd) + cmd->len; 173 174 memcpy(c->data, cmd->data, c->len); 175 176 err = cn_netlink_send(cm, portid, 0, GFP_KERNEL); 177 178 kfree(data); 179 180 return err; 181 } 182 183 static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, 184 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) 185 { 186 int err = 0; 187 188 switch (cmd->cmd) { 189 case W1_CMD_TOUCH: 190 w1_touch_block(dev, cmd->data, cmd->len); 191 w1_send_read_reply(msg, hdr, cmd, dev->portid); 192 break; 193 case W1_CMD_READ: 194 w1_read_block(dev, cmd->data, cmd->len); 195 w1_send_read_reply(msg, hdr, cmd, dev->portid); 196 break; 197 case W1_CMD_WRITE: 198 w1_write_block(dev, cmd->data, cmd->len); 199 break; 200 default: 201 err = -EINVAL; 202 break; 203 } 204 205 return err; 206 } 207 208 static int w1_process_command_addremove(struct w1_master *dev, 209 struct cn_msg *msg, struct w1_netlink_msg *hdr, 210 struct w1_netlink_cmd *cmd) 211 { 212 struct w1_slave *sl; 213 int err = 0; 214 struct w1_reg_num *id; 215 216 if (cmd->len != 8) 217 return -EINVAL; 218 219 id = (struct w1_reg_num *)cmd->data; 220 221 sl = w1_slave_search_device(dev, id); 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 } 239 240 return err; 241 } 242 243 static int w1_process_command_master(struct w1_master *dev, 244 struct cn_msg *req_msg, struct w1_netlink_msg *req_hdr, 245 struct w1_netlink_cmd *req_cmd) 246 { 247 int err = -EINVAL; 248 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) { 253 case W1_CMD_SEARCH: 254 case W1_CMD_ALARM_SEARCH: 255 case W1_CMD_LIST_SLAVES: 256 mutex_unlock(&dev->bus_mutex); 257 err = w1_get_slaves(dev, req_msg, req_hdr, req_cmd); 258 mutex_lock(&dev->bus_mutex); 259 break; 260 case W1_CMD_READ: 261 case W1_CMD_WRITE: 262 case W1_CMD_TOUCH: 263 err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); 264 break; 265 case W1_CMD_RESET: 266 err = w1_reset_bus(dev); 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; 277 default: 278 err = -EINVAL; 279 break; 280 } 281 282 return err; 283 } 284 285 static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, 286 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) 287 { 288 dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", 289 __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, 290 sl->reg_num.crc, cmd->cmd, cmd->len); 291 292 return w1_process_command_io(sl->master, msg, hdr, cmd); 293 } 294 295 static int w1_process_command_root(struct cn_msg *msg, 296 struct w1_netlink_msg *mcmd, u32 portid) 297 { 298 struct w1_master *m; 299 struct cn_msg *cn; 300 struct w1_netlink_msg *w; 301 u32 *id; 302 303 cn = kmalloc(PAGE_SIZE, GFP_KERNEL); 304 if (!cn) 305 return -ENOMEM; 306 307 cn->id.idx = CN_W1_IDX; 308 cn->id.val = CN_W1_VAL; 309 310 cn->seq = msg->seq; 311 cn->ack = 1; 312 cn->len = sizeof(struct w1_netlink_msg); 313 w = (struct w1_netlink_msg *)(cn + 1); 314 315 w->type = W1_LIST_MASTERS; 316 w->status = 0; 317 w->len = 0; 318 id = (u32 *)(w + 1); 319 320 mutex_lock(&w1_mlock); 321 list_for_each_entry(m, &w1_masters, w1_master_entry) { 322 if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { 323 cn_netlink_send(cn, portid, 0, GFP_KERNEL); 324 cn->ack++; 325 cn->len = sizeof(struct w1_netlink_msg); 326 w->len = 0; 327 id = (u32 *)(w + 1); 328 } 329 330 *id = m->id; 331 w->len += sizeof(*id); 332 cn->len += sizeof(*id); 333 id++; 334 } 335 cn->ack = 0; 336 cn_netlink_send(cn, portid, 0, GFP_KERNEL); 337 mutex_unlock(&w1_mlock); 338 339 kfree(cn); 340 return 0; 341 } 342 343 static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, 344 struct w1_netlink_cmd *rcmd, int portid, int error) 345 { 346 struct cn_msg *cmsg; 347 struct w1_netlink_msg *msg; 348 struct w1_netlink_cmd *cmd; 349 350 cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); 351 if (!cmsg) 352 return -ENOMEM; 353 354 msg = (struct w1_netlink_msg *)(cmsg + 1); 355 cmd = (struct w1_netlink_cmd *)(msg + 1); 356 357 memcpy(cmsg, rcmsg, sizeof(*cmsg)); 358 cmsg->len = sizeof(*msg); 359 360 memcpy(msg, rmsg, sizeof(*msg)); 361 msg->len = 0; 362 msg->status = (short)-error; 363 364 if (rcmd) { 365 memcpy(cmd, rcmd, sizeof(*cmd)); 366 cmd->len = 0; 367 msg->len += sizeof(*cmd); 368 cmsg->len += sizeof(*cmd); 369 } 370 371 error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL); 372 kfree(cmsg); 373 374 return error; 375 } 376 377 /* Bundle together a reference count, the full message, and broken out 378 * commands to be executed on each w1 master kthread in one memory allocation. 379 */ 380 struct w1_cb_block { 381 atomic_t refcnt; 382 u32 portid; /* Sending process port ID */ 383 struct cn_msg msg; 384 /* cn_msg data */ 385 /* one or more variable length struct w1_cb_node */ 386 }; 387 struct w1_cb_node { 388 struct w1_async_cmd async; 389 /* pointers within w1_cb_block and msg data */ 390 struct w1_cb_block *block; 391 struct w1_netlink_msg *m; 392 struct w1_slave *sl; 393 struct w1_master *dev; 394 }; 395 396 static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) 397 { 398 struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node, 399 async); 400 u16 mlen = node->m->len; 401 u8 *cmd_data = node->m->data; 402 int err = 0; 403 struct w1_slave *sl = node->sl; 404 struct w1_netlink_cmd *cmd = NULL; 405 406 mutex_lock(&dev->bus_mutex); 407 dev->portid = node->block->portid; 408 if (sl && w1_reset_select_slave(sl)) 409 err = -ENODEV; 410 411 while (mlen && !err) { 412 cmd = (struct w1_netlink_cmd *)cmd_data; 413 414 if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { 415 err = -E2BIG; 416 break; 417 } 418 419 if (sl) 420 err = w1_process_command_slave(sl, &node->block->msg, 421 node->m, cmd); 422 else 423 err = w1_process_command_master(dev, &node->block->msg, 424 node->m, cmd); 425 426 w1_netlink_send_error(&node->block->msg, node->m, cmd, 427 node->block->portid, err); 428 err = 0; 429 430 cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); 431 mlen -= cmd->len + sizeof(struct w1_netlink_cmd); 432 } 433 434 if (!cmd || err) 435 w1_netlink_send_error(&node->block->msg, node->m, cmd, 436 node->block->portid, err); 437 438 /* ref taken in w1_search_slave or w1_search_master_id when building 439 * the block 440 */ 441 if (sl) 442 w1_unref_slave(sl); 443 else 444 atomic_dec(&dev->refcnt); 445 dev->portid = 0; 446 mutex_unlock(&dev->bus_mutex); 447 448 mutex_lock(&dev->list_mutex); 449 list_del(&async_cmd->async_entry); 450 mutex_unlock(&dev->list_mutex); 451 452 if (atomic_sub_return(1, &node->block->refcnt) == 0) 453 kfree(node->block); 454 } 455 456 static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) 457 { 458 struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); 459 struct w1_slave *sl; 460 struct w1_master *dev; 461 u16 msg_len; 462 int err = 0; 463 struct w1_cb_block *block = NULL; 464 struct w1_cb_node *node = NULL; 465 int node_count = 0; 466 467 /* Count the number of master or slave commands there are to allocate 468 * space for one cb_node each. 469 */ 470 msg_len = msg->len; 471 while (msg_len && !err) { 472 if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { 473 err = -E2BIG; 474 break; 475 } 476 477 if (m->type == W1_MASTER_CMD || m->type == W1_SLAVE_CMD) 478 ++node_count; 479 480 msg_len -= sizeof(struct w1_netlink_msg) + m->len; 481 m = (struct w1_netlink_msg *)(((u8 *)m) + 482 sizeof(struct w1_netlink_msg) + m->len); 483 } 484 m = (struct w1_netlink_msg *)(msg + 1); 485 if (node_count) { 486 /* msg->len doesn't include itself */ 487 long size = sizeof(struct w1_cb_block) + msg->len + 488 node_count*sizeof(struct w1_cb_node); 489 block = kmalloc(size, GFP_KERNEL); 490 if (!block) { 491 w1_netlink_send_error(msg, m, NULL, nsp->portid, 492 -ENOMEM); 493 return; 494 } 495 atomic_set(&block->refcnt, 1); 496 block->portid = nsp->portid; 497 memcpy(&block->msg, msg, sizeof(*msg) + msg->len); 498 node = (struct w1_cb_node *)((u8 *)block->msg.data + msg->len); 499 } 500 501 msg_len = msg->len; 502 while (msg_len && !err) { 503 504 dev = NULL; 505 sl = NULL; 506 507 if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { 508 err = -E2BIG; 509 break; 510 } 511 512 /* execute on this thread, no need to process later */ 513 if (m->type == W1_LIST_MASTERS) { 514 err = w1_process_command_root(msg, m, nsp->portid); 515 goto out_cont; 516 } 517 518 /* All following message types require additional data, 519 * check here before references are taken. 520 */ 521 if (!m->len) { 522 err = -EPROTO; 523 goto out_cont; 524 } 525 526 /* both search calls take reference counts */ 527 if (m->type == W1_MASTER_CMD) { 528 dev = w1_search_master_id(m->id.mst.id); 529 } else if (m->type == W1_SLAVE_CMD) { 530 sl = w1_search_slave((struct w1_reg_num *)m->id.id); 531 if (sl) 532 dev = sl->master; 533 } else { 534 printk(KERN_NOTICE 535 "%s: msg: %x.%x, wrong type: %u, len: %u.\n", 536 __func__, msg->id.idx, msg->id.val, 537 m->type, m->len); 538 err = -EPROTO; 539 goto out_cont; 540 } 541 542 if (!dev) { 543 err = -ENODEV; 544 goto out_cont; 545 } 546 547 err = 0; 548 549 atomic_inc(&block->refcnt); 550 node->async.cb = w1_process_cb; 551 node->block = block; 552 node->m = (struct w1_netlink_msg *)((u8 *)&block->msg + 553 (size_t)((u8 *)m - (u8 *)msg)); 554 node->sl = sl; 555 node->dev = dev; 556 557 mutex_lock(&dev->list_mutex); 558 list_add_tail(&node->async.async_entry, &dev->async_list); 559 wake_up_process(dev->thread); 560 mutex_unlock(&dev->list_mutex); 561 ++node; 562 563 out_cont: 564 if (err) 565 w1_netlink_send_error(msg, m, NULL, nsp->portid, err); 566 msg_len -= sizeof(struct w1_netlink_msg) + m->len; 567 m = (struct w1_netlink_msg *)(((u8 *)m) + 568 sizeof(struct w1_netlink_msg) + m->len); 569 570 /* 571 * Let's allow requests for nonexisting devices. 572 */ 573 if (err == -ENODEV) 574 err = 0; 575 } 576 if (block && atomic_sub_return(1, &block->refcnt) == 0) 577 kfree(block); 578 } 579 580 int w1_init_netlink(void) 581 { 582 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 583 584 return cn_add_callback(&w1_id, "w1", &w1_cn_callback); 585 } 586 587 void w1_fini_netlink(void) 588 { 589 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 590 591 cn_del_callback(&w1_id); 592 } 593 #else 594 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) 595 { 596 } 597 598 int w1_init_netlink(void) 599 { 600 return 0; 601 } 602 603 void w1_fini_netlink(void) 604 { 605 } 606 #endif 607