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 if (mcmd->type != W1_LIST_MASTERS) { 304 printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", 305 __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); 306 return -EPROTO; 307 } 308 309 cn = kmalloc(PAGE_SIZE, GFP_KERNEL); 310 if (!cn) 311 return -ENOMEM; 312 313 cn->id.idx = CN_W1_IDX; 314 cn->id.val = CN_W1_VAL; 315 316 cn->seq = msg->seq; 317 cn->ack = 1; 318 cn->len = sizeof(struct w1_netlink_msg); 319 w = (struct w1_netlink_msg *)(cn + 1); 320 321 w->type = W1_LIST_MASTERS; 322 w->status = 0; 323 w->len = 0; 324 id = (u32 *)(w + 1); 325 326 mutex_lock(&w1_mlock); 327 list_for_each_entry(m, &w1_masters, w1_master_entry) { 328 if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { 329 cn_netlink_send(cn, portid, 0, GFP_KERNEL); 330 cn->ack++; 331 cn->len = sizeof(struct w1_netlink_msg); 332 w->len = 0; 333 id = (u32 *)(w + 1); 334 } 335 336 *id = m->id; 337 w->len += sizeof(*id); 338 cn->len += sizeof(*id); 339 id++; 340 } 341 cn->ack = 0; 342 cn_netlink_send(cn, portid, 0, GFP_KERNEL); 343 mutex_unlock(&w1_mlock); 344 345 kfree(cn); 346 return 0; 347 } 348 349 static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, 350 struct w1_netlink_cmd *rcmd, int portid, int error) 351 { 352 struct cn_msg *cmsg; 353 struct w1_netlink_msg *msg; 354 struct w1_netlink_cmd *cmd; 355 356 cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); 357 if (!cmsg) 358 return -ENOMEM; 359 360 msg = (struct w1_netlink_msg *)(cmsg + 1); 361 cmd = (struct w1_netlink_cmd *)(msg + 1); 362 363 memcpy(cmsg, rcmsg, sizeof(*cmsg)); 364 cmsg->len = sizeof(*msg); 365 366 memcpy(msg, rmsg, sizeof(*msg)); 367 msg->len = 0; 368 msg->status = (short)-error; 369 370 if (rcmd) { 371 memcpy(cmd, rcmd, sizeof(*cmd)); 372 cmd->len = 0; 373 msg->len += sizeof(*cmd); 374 cmsg->len += sizeof(*cmd); 375 } 376 377 error = cn_netlink_send(cmsg, portid, 0, GFP_KERNEL); 378 kfree(cmsg); 379 380 return error; 381 } 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 459 static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) 460 { 461 struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); 462 struct w1_slave *sl; 463 struct w1_master *dev; 464 u16 msg_len; 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; 482 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) { 506 struct w1_reg_num id; 507 u16 mlen = m->len; 508 509 dev = NULL; 510 sl = NULL; 511 512 memcpy(&id, m->id.id, sizeof(id)); 513 #if 0 514 printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", 515 __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); 516 #endif 517 if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { 518 err = -E2BIG; 519 break; 520 } 521 522 if (m->type == W1_MASTER_CMD) { 523 dev = w1_search_master_id(m->id.mst.id); 524 } else if (m->type == W1_SLAVE_CMD) { 525 sl = w1_search_slave(&id); 526 if (sl) 527 dev = sl->master; 528 } else { 529 err = w1_process_command_root(msg, m, nsp->portid); 530 goto out_cont; 531 } 532 533 if (!dev) { 534 err = -ENODEV; 535 goto out_cont; 536 } 537 538 err = 0; 539 if (!mlen) 540 goto out_cont; 541 542 atomic_inc(&block->refcnt); 543 node->async.cb = w1_process_cb; 544 node->block = block; 545 node->m = (struct w1_netlink_msg *)((u8 *)&block->msg + 546 (size_t)((u8 *)m - (u8 *)msg)); 547 node->sl = sl; 548 node->dev = dev; 549 550 mutex_lock(&dev->list_mutex); 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; 555 556 out_cont: 557 if (err) 558 w1_netlink_send_error(msg, m, NULL, nsp->portid, err); 559 msg_len -= sizeof(struct w1_netlink_msg) + m->len; 560 m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); 561 562 /* 563 * Let's allow requests for nonexisting devices. 564 */ 565 if (err == -ENODEV) 566 err = 0; 567 } 568 if (block && atomic_sub_return(1, &block->refcnt) == 0) 569 kfree(block); 570 } 571 572 int w1_init_netlink(void) 573 { 574 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 575 576 return cn_add_callback(&w1_id, "w1", &w1_cn_callback); 577 } 578 579 void w1_fini_netlink(void) 580 { 581 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 582 583 cn_del_callback(&w1_id); 584 } 585 #else 586 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) 587 { 588 } 589 590 int w1_init_netlink(void) 591 { 592 return 0; 593 } 594 595 void w1_fini_netlink(void) 596 { 597 } 598 #endif 599