0001
0002
0003
0004
0005
0006 #include <linux/slab.h>
0007 #include <linux/skbuff.h>
0008 #include <linux/netlink.h>
0009 #include <linux/connector.h>
0010
0011 #include "w1_internal.h"
0012 #include "w1_netlink.h"
0013
0014 #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
0015
0016
0017
0018
0019 struct w1_cb_block {
0020 atomic_t refcnt;
0021 u32 portid;
0022
0023 u16 maxlen;
0024
0025 struct cn_msg *first_cn;
0026 struct cn_msg *cn;
0027 struct w1_netlink_msg *msg;
0028 struct w1_netlink_cmd *cmd;
0029 struct w1_netlink_msg *cur_msg;
0030
0031 struct cn_msg request_cn;
0032
0033
0034
0035
0036
0037 };
0038 struct w1_cb_node {
0039 struct w1_async_cmd async;
0040
0041 struct w1_cb_block *block;
0042 struct w1_netlink_msg *msg;
0043 struct w1_slave *sl;
0044 struct w1_master *dev;
0045 };
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055 static u16 w1_reply_len(struct w1_cb_block *block)
0056 {
0057 if (!block->cn)
0058 return 0;
0059 return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;
0060 }
0061
0062 static void w1_unref_block(struct w1_cb_block *block)
0063 {
0064 if (atomic_sub_return(1, &block->refcnt) == 0) {
0065 u16 len = w1_reply_len(block);
0066 if (len) {
0067 cn_netlink_send_mult(block->first_cn, len,
0068 block->portid, 0, GFP_KERNEL);
0069 }
0070 kfree(block);
0071 }
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
0083 {
0084 u16 len = w1_reply_len(block);
0085 if (len + space >= block->maxlen) {
0086 cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL);
0087 block->first_cn->len = 0;
0088 block->cn = NULL;
0089 block->msg = NULL;
0090 block->cmd = NULL;
0091 }
0092 }
0093
0094
0095 static void w1_netlink_check_send(struct w1_cb_block *block)
0096 {
0097 if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn)
0098 w1_reply_make_space(block, block->maxlen);
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack)
0111 {
0112 if (block->cn && block->cn->ack == ack) {
0113 block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len);
0114 } else {
0115
0116 if (block->cn)
0117 block->cn = (struct cn_msg *)(block->cn->data +
0118 block->cn->len);
0119 else
0120 block->cn = block->first_cn;
0121
0122 memcpy(block->cn, &block->request_cn, sizeof(*block->cn));
0123 block->cn->len = 0;
0124 block->cn->ack = ack;
0125 block->msg = (struct w1_netlink_msg *)block->cn->data;
0126 }
0127 }
0128
0129
0130
0131
0132
0133 static void w1_netlink_queue_cmd(struct w1_cb_block *block,
0134 struct w1_netlink_cmd *cmd)
0135 {
0136 u32 space;
0137 w1_reply_make_space(block, sizeof(struct cn_msg) +
0138 sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len);
0139
0140
0141
0142
0143
0144 w1_netlink_setup_msg(block, block->request_cn.seq + 1);
0145 memcpy(block->msg, block->cur_msg, sizeof(*block->msg));
0146 block->cn->len += sizeof(*block->msg);
0147 block->msg->len = 0;
0148 block->cmd = (struct w1_netlink_cmd *)(block->msg->data);
0149
0150 space = sizeof(*cmd) + cmd->len;
0151 if (block->cmd != cmd)
0152 memcpy(block->cmd, cmd, space);
0153 block->cn->len += space;
0154 block->msg->len += space;
0155 }
0156
0157
0158
0159
0160 static void w1_netlink_queue_status(struct w1_cb_block *block,
0161 struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd,
0162 int error)
0163 {
0164 u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd);
0165 w1_reply_make_space(block, space);
0166 w1_netlink_setup_msg(block, block->request_cn.ack);
0167
0168 memcpy(block->msg, req_msg, sizeof(*req_msg));
0169 block->cn->len += sizeof(*req_msg);
0170 block->msg->len = 0;
0171 block->msg->status = (u8)-error;
0172 if (req_cmd) {
0173 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data;
0174 memcpy(cmd, req_cmd, sizeof(*cmd));
0175 block->cn->len += sizeof(*cmd);
0176 block->msg->len += sizeof(*cmd);
0177 cmd->len = 0;
0178 }
0179 w1_netlink_check_send(block);
0180 }
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
0193 int portid, int error)
0194 {
0195 struct {
0196 struct cn_msg cn;
0197 struct w1_netlink_msg msg;
0198 } packet;
0199 memcpy(&packet.cn, cn, sizeof(packet.cn));
0200 memcpy(&packet.msg, msg, sizeof(packet.msg));
0201 packet.cn.len = sizeof(packet.msg);
0202 packet.msg.len = 0;
0203 packet.msg.status = (u8)-error;
0204 cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL);
0205 }
0206
0207
0208
0209
0210
0211
0212
0213
0214 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
0215 {
0216 struct {
0217 struct cn_msg cn;
0218 struct w1_netlink_msg msg;
0219 } packet;
0220 memset(&packet, 0, sizeof(packet));
0221
0222 packet.cn.id.idx = CN_W1_IDX;
0223 packet.cn.id.val = CN_W1_VAL;
0224
0225 packet.cn.seq = dev->seq++;
0226 packet.cn.len = sizeof(*msg);
0227
0228 memcpy(&packet.msg, msg, sizeof(*msg));
0229 packet.msg.len = 0;
0230
0231 cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);
0232 }
0233
0234 static void w1_send_slave(struct w1_master *dev, u64 rn)
0235 {
0236 struct w1_cb_block *block = dev->priv;
0237 struct w1_netlink_cmd *cache_cmd = block->cmd;
0238 u64 *data;
0239
0240 w1_reply_make_space(block, sizeof(*data));
0241
0242
0243 if (!block->cmd) {
0244 cache_cmd->len = 0;
0245 w1_netlink_queue_cmd(block, cache_cmd);
0246 }
0247
0248 data = (u64 *)(block->cmd->data + block->cmd->len);
0249
0250 *data = rn;
0251 block->cn->len += sizeof(*data);
0252 block->msg->len += sizeof(*data);
0253 block->cmd->len += sizeof(*data);
0254 }
0255
0256 static void w1_found_send_slave(struct w1_master *dev, u64 rn)
0257 {
0258
0259 w1_slave_found(dev, rn);
0260
0261 w1_send_slave(dev, rn);
0262 }
0263
0264
0265 static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd)
0266 {
0267 struct w1_slave *sl;
0268
0269 req_cmd->len = 0;
0270 w1_netlink_queue_cmd(dev->priv, req_cmd);
0271
0272 if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
0273 u64 rn;
0274 mutex_lock(&dev->list_mutex);
0275 list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
0276 memcpy(&rn, &sl->reg_num, sizeof(rn));
0277 w1_send_slave(dev, rn);
0278 }
0279 mutex_unlock(&dev->list_mutex);
0280 } else {
0281 w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ?
0282 W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
0283 }
0284
0285 return 0;
0286 }
0287
0288 static int w1_process_command_io(struct w1_master *dev,
0289 struct w1_netlink_cmd *cmd)
0290 {
0291 int err = 0;
0292
0293 switch (cmd->cmd) {
0294 case W1_CMD_TOUCH:
0295 w1_touch_block(dev, cmd->data, cmd->len);
0296 w1_netlink_queue_cmd(dev->priv, cmd);
0297 break;
0298 case W1_CMD_READ:
0299 w1_read_block(dev, cmd->data, cmd->len);
0300 w1_netlink_queue_cmd(dev->priv, cmd);
0301 break;
0302 case W1_CMD_WRITE:
0303 w1_write_block(dev, cmd->data, cmd->len);
0304 break;
0305 default:
0306 err = -EINVAL;
0307 break;
0308 }
0309
0310 return err;
0311 }
0312
0313 static int w1_process_command_addremove(struct w1_master *dev,
0314 struct w1_netlink_cmd *cmd)
0315 {
0316 struct w1_slave *sl;
0317 int err = 0;
0318 struct w1_reg_num *id;
0319
0320 if (cmd->len != sizeof(*id))
0321 return -EINVAL;
0322
0323 id = (struct w1_reg_num *)cmd->data;
0324
0325 sl = w1_slave_search_device(dev, id);
0326 switch (cmd->cmd) {
0327 case W1_CMD_SLAVE_ADD:
0328 if (sl)
0329 err = -EINVAL;
0330 else
0331 err = w1_attach_slave_device(dev, id);
0332 break;
0333 case W1_CMD_SLAVE_REMOVE:
0334 if (sl)
0335 w1_slave_detach(sl);
0336 else
0337 err = -EINVAL;
0338 break;
0339 default:
0340 err = -EINVAL;
0341 break;
0342 }
0343
0344 return err;
0345 }
0346
0347 static int w1_process_command_master(struct w1_master *dev,
0348 struct w1_netlink_cmd *req_cmd)
0349 {
0350 int err = -EINVAL;
0351
0352
0353
0354
0355 switch (req_cmd->cmd) {
0356 case W1_CMD_SEARCH:
0357 case W1_CMD_ALARM_SEARCH:
0358 case W1_CMD_LIST_SLAVES:
0359 mutex_unlock(&dev->bus_mutex);
0360 err = w1_get_slaves(dev, req_cmd);
0361 mutex_lock(&dev->bus_mutex);
0362 break;
0363 case W1_CMD_READ:
0364 case W1_CMD_WRITE:
0365 case W1_CMD_TOUCH:
0366 err = w1_process_command_io(dev, req_cmd);
0367 break;
0368 case W1_CMD_RESET:
0369 err = w1_reset_bus(dev);
0370 break;
0371 case W1_CMD_SLAVE_ADD:
0372 case W1_CMD_SLAVE_REMOVE:
0373 mutex_unlock(&dev->bus_mutex);
0374 mutex_lock(&dev->mutex);
0375 err = w1_process_command_addremove(dev, req_cmd);
0376 mutex_unlock(&dev->mutex);
0377 mutex_lock(&dev->bus_mutex);
0378 break;
0379 default:
0380 err = -EINVAL;
0381 break;
0382 }
0383
0384 return err;
0385 }
0386
0387 static int w1_process_command_slave(struct w1_slave *sl,
0388 struct w1_netlink_cmd *cmd)
0389 {
0390 dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
0391 __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id,
0392 sl->reg_num.crc, cmd->cmd, cmd->len);
0393
0394 return w1_process_command_io(sl->master, cmd);
0395 }
0396
0397 static int w1_process_command_root(struct cn_msg *req_cn, u32 portid)
0398 {
0399 struct w1_master *dev;
0400 struct cn_msg *cn;
0401 struct w1_netlink_msg *msg;
0402 u32 *id;
0403
0404 cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
0405 if (!cn)
0406 return -ENOMEM;
0407
0408 cn->id.idx = CN_W1_IDX;
0409 cn->id.val = CN_W1_VAL;
0410
0411 cn->seq = req_cn->seq;
0412 cn->ack = req_cn->seq + 1;
0413 cn->len = sizeof(struct w1_netlink_msg);
0414 msg = (struct w1_netlink_msg *)cn->data;
0415
0416 msg->type = W1_LIST_MASTERS;
0417 msg->status = 0;
0418 msg->len = 0;
0419 id = (u32 *)msg->data;
0420
0421 mutex_lock(&w1_mlock);
0422 list_for_each_entry(dev, &w1_masters, w1_master_entry) {
0423 if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
0424 cn_netlink_send(cn, portid, 0, GFP_KERNEL);
0425 cn->len = sizeof(struct w1_netlink_msg);
0426 msg->len = 0;
0427 id = (u32 *)msg->data;
0428 }
0429
0430 *id = dev->id;
0431 msg->len += sizeof(*id);
0432 cn->len += sizeof(*id);
0433 id++;
0434 }
0435 cn_netlink_send(cn, portid, 0, GFP_KERNEL);
0436 mutex_unlock(&w1_mlock);
0437
0438 kfree(cn);
0439 return 0;
0440 }
0441
0442 static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
0443 {
0444 struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
0445 async);
0446 u16 mlen = node->msg->len;
0447 u16 len;
0448 int err = 0;
0449 struct w1_slave *sl = node->sl;
0450 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data;
0451
0452 mutex_lock(&dev->bus_mutex);
0453 dev->priv = node->block;
0454 if (sl && w1_reset_select_slave(sl))
0455 err = -ENODEV;
0456 node->block->cur_msg = node->msg;
0457
0458 while (mlen && !err) {
0459 if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
0460 err = -E2BIG;
0461 break;
0462 }
0463
0464 if (sl)
0465 err = w1_process_command_slave(sl, cmd);
0466 else
0467 err = w1_process_command_master(dev, cmd);
0468 w1_netlink_check_send(node->block);
0469
0470 w1_netlink_queue_status(node->block, node->msg, cmd, err);
0471 err = 0;
0472
0473 len = sizeof(*cmd) + cmd->len;
0474 cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
0475 mlen -= len;
0476 }
0477
0478 if (!cmd || err)
0479 w1_netlink_queue_status(node->block, node->msg, cmd, err);
0480
0481
0482
0483
0484 if (sl)
0485 w1_unref_slave(sl);
0486 else
0487 atomic_dec(&dev->refcnt);
0488 dev->priv = NULL;
0489 mutex_unlock(&dev->bus_mutex);
0490
0491 mutex_lock(&dev->list_mutex);
0492 list_del(&async_cmd->async_entry);
0493 mutex_unlock(&dev->list_mutex);
0494
0495 w1_unref_block(node->block);
0496 }
0497
0498 static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count,
0499 u16 *slave_len)
0500 {
0501 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data;
0502 u16 mlen = msg->len;
0503 u16 len;
0504 int slave_list = 0;
0505 while (mlen) {
0506 if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen)
0507 break;
0508
0509 switch (cmd->cmd) {
0510 case W1_CMD_SEARCH:
0511 case W1_CMD_ALARM_SEARCH:
0512 case W1_CMD_LIST_SLAVES:
0513 ++slave_list;
0514 }
0515 ++*cmd_count;
0516 len = sizeof(*cmd) + cmd->len;
0517 cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
0518 mlen -= len;
0519 }
0520
0521 if (slave_list) {
0522 struct w1_master *dev = w1_search_master_id(msg->id.mst.id);
0523 if (dev) {
0524
0525
0526
0527 *slave_len += sizeof(struct w1_reg_num) * slave_list *
0528 (dev->slave_count + dev->max_slave_count);
0529
0530 atomic_dec(&dev->refcnt);
0531 }
0532 }
0533 }
0534
0535 static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp)
0536 {
0537 struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1);
0538 struct w1_slave *sl;
0539 struct w1_master *dev;
0540 u16 msg_len;
0541 u16 slave_len = 0;
0542 int err = 0;
0543 struct w1_cb_block *block = NULL;
0544 struct w1_cb_node *node = NULL;
0545 int node_count = 0;
0546 int cmd_count = 0;
0547
0548
0549
0550
0551
0552 if (cn->flags & ~(W1_CN_BUNDLE)) {
0553 w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL);
0554 return;
0555 }
0556
0557
0558
0559
0560 msg_len = cn->len;
0561 while (msg_len && !err) {
0562 if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
0563 err = -E2BIG;
0564 break;
0565 }
0566
0567
0568
0569
0570 if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) {
0571 ++node_count;
0572 w1_list_count_cmds(msg, &cmd_count, &slave_len);
0573 }
0574
0575 msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
0576 msg = (struct w1_netlink_msg *)(((u8 *)msg) +
0577 sizeof(struct w1_netlink_msg) + msg->len);
0578 }
0579 msg = (struct w1_netlink_msg *)(cn + 1);
0580 if (node_count) {
0581 int size;
0582 int reply_size = sizeof(*cn) + cn->len + slave_len;
0583 if (cn->flags & W1_CN_BUNDLE) {
0584
0585 reply_size += 2 * cmd_count * (sizeof(struct cn_msg) +
0586 sizeof(struct w1_netlink_msg) +
0587 sizeof(struct w1_netlink_cmd));
0588 }
0589 reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size);
0590
0591
0592
0593
0594
0595
0596
0597 size =
0598 sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len +
0599
0600 node_count * sizeof(struct w1_cb_node) +
0601
0602 sizeof(struct cn_msg) + reply_size;
0603 block = kzalloc(size, GFP_KERNEL);
0604 if (!block) {
0605
0606
0607
0608
0609 w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM);
0610 return;
0611 }
0612 atomic_set(&block->refcnt, 1);
0613 block->portid = nsp->portid;
0614 memcpy(&block->request_cn, cn, sizeof(*cn) + cn->len);
0615 node = (struct w1_cb_node *)(block->request_cn.data + cn->len);
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626 block->maxlen = reply_size;
0627 block->first_cn = (struct cn_msg *)(node + node_count);
0628 memset(block->first_cn, 0, sizeof(*block->first_cn));
0629 }
0630
0631 msg_len = cn->len;
0632 while (msg_len && !err) {
0633
0634 dev = NULL;
0635 sl = NULL;
0636
0637 if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
0638 err = -E2BIG;
0639 break;
0640 }
0641
0642
0643 if (msg->type == W1_LIST_MASTERS) {
0644 err = w1_process_command_root(cn, nsp->portid);
0645 goto out_cont;
0646 }
0647
0648
0649
0650
0651 if (!msg->len) {
0652 err = -EPROTO;
0653 goto out_cont;
0654 }
0655
0656
0657 if (msg->type == W1_MASTER_CMD) {
0658 dev = w1_search_master_id(msg->id.mst.id);
0659 } else if (msg->type == W1_SLAVE_CMD) {
0660 sl = w1_search_slave((struct w1_reg_num *)msg->id.id);
0661 if (sl)
0662 dev = sl->master;
0663 } else {
0664 pr_notice("%s: cn: %x.%x, wrong type: %u, len: %u.\n",
0665 __func__, cn->id.idx, cn->id.val,
0666 msg->type, msg->len);
0667 err = -EPROTO;
0668 goto out_cont;
0669 }
0670
0671 if (!dev) {
0672 err = -ENODEV;
0673 goto out_cont;
0674 }
0675
0676 err = 0;
0677
0678 atomic_inc(&block->refcnt);
0679 node->async.cb = w1_process_cb;
0680 node->block = block;
0681 node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn +
0682 (size_t)((u8 *)msg - (u8 *)cn));
0683 node->sl = sl;
0684 node->dev = dev;
0685
0686 mutex_lock(&dev->list_mutex);
0687 list_add_tail(&node->async.async_entry, &dev->async_list);
0688 wake_up_process(dev->thread);
0689 mutex_unlock(&dev->list_mutex);
0690 ++node;
0691
0692 out_cont:
0693
0694
0695
0696
0697 if (err)
0698 w1_netlink_send_error(cn, msg, nsp->portid, err);
0699 msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
0700 msg = (struct w1_netlink_msg *)(((u8 *)msg) +
0701 sizeof(struct w1_netlink_msg) + msg->len);
0702
0703
0704
0705
0706 if (err == -ENODEV)
0707 err = 0;
0708 }
0709 if (block)
0710 w1_unref_block(block);
0711 }
0712
0713 int w1_init_netlink(void)
0714 {
0715 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
0716
0717 return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
0718 }
0719
0720 void w1_fini_netlink(void)
0721 {
0722 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
0723
0724 cn_del_callback(&w1_id);
0725 }
0726 #else
0727 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *cn)
0728 {
0729 }
0730
0731 int w1_init_netlink(void)
0732 {
0733 return 0;
0734 }
0735
0736 void w1_fini_netlink(void)
0737 {
0738 }
0739 #endif