xref: /openbmc/linux/drivers/w1/w1_netlink.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3a8018766SEvgeniy Polyakov  * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
65a0e3ad6STejun Heo #include <linux/slab.h>
71da177e4SLinus Torvalds #include <linux/skbuff.h>
81da177e4SLinus Torvalds #include <linux/netlink.h>
912003375SEvgeniy Polyakov #include <linux/connector.h>
101da177e4SLinus Torvalds 
11de0d6dbdSAndrew F. Davis #include "w1_internal.h"
121da177e4SLinus Torvalds #include "w1_netlink.h"
131da177e4SLinus Torvalds 
1446e07f6eSEvgeniy Polyakov #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
158a0427d1SDavid Fries 
168a0427d1SDavid Fries /* Bundle together everything required to process a request in one memory
178a0427d1SDavid Fries  * allocation.
188a0427d1SDavid Fries  */
198a0427d1SDavid Fries struct w1_cb_block {
208a0427d1SDavid Fries 	atomic_t refcnt;
218a0427d1SDavid Fries 	u32 portid; /* Sending process port ID */
228a0427d1SDavid Fries 	/* maximum value for first_cn->len */
238a0427d1SDavid Fries 	u16 maxlen;
248a0427d1SDavid Fries 	/* pointers to building up the reply message */
258a0427d1SDavid Fries 	struct cn_msg *first_cn; /* fixed once the structure is populated */
268a0427d1SDavid Fries 	struct cn_msg *cn; /* advances as cn_msg is appeneded */
278a0427d1SDavid Fries 	struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */
288a0427d1SDavid Fries 	struct w1_netlink_cmd *cmd; /* advances as cmds are appened */
298a0427d1SDavid Fries 	struct w1_netlink_msg *cur_msg; /* currently message being processed */
308a0427d1SDavid Fries 	/* copy of the original request follows */
318a0427d1SDavid Fries 	struct cn_msg request_cn;
328a0427d1SDavid Fries 	/* followed by variable length:
338a0427d1SDavid Fries 	 * cn_msg, data (w1_netlink_msg and w1_netlink_cmd)
348a0427d1SDavid Fries 	 * one or more struct w1_cb_node
358a0427d1SDavid Fries 	 * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd)
368a0427d1SDavid Fries 	 */
378a0427d1SDavid Fries };
388a0427d1SDavid Fries struct w1_cb_node {
398a0427d1SDavid Fries 	struct w1_async_cmd async;
408a0427d1SDavid Fries 	/* pointers within w1_cb_block and cn data */
418a0427d1SDavid Fries 	struct w1_cb_block *block;
428a0427d1SDavid Fries 	struct w1_netlink_msg *msg;
438a0427d1SDavid Fries 	struct w1_slave *sl;
448a0427d1SDavid Fries 	struct w1_master *dev;
458a0427d1SDavid Fries };
468a0427d1SDavid Fries 
478a0427d1SDavid Fries /**
488a0427d1SDavid Fries  * w1_reply_len() - calculate current reply length, compare to maxlen
498a0427d1SDavid Fries  * @block: block to calculate
508a0427d1SDavid Fries  *
518a0427d1SDavid Fries  * Calculates the current message length including possible multiple
528a0427d1SDavid Fries  * cn_msg and data, excludes the first sizeof(struct cn_msg).  Direclty
538a0427d1SDavid Fries  * compariable to maxlen and usable to send the message.
548a0427d1SDavid Fries  */
w1_reply_len(struct w1_cb_block * block)558a0427d1SDavid Fries static u16 w1_reply_len(struct w1_cb_block *block)
568a0427d1SDavid Fries {
578a0427d1SDavid Fries 	if (!block->cn)
588a0427d1SDavid Fries 		return 0;
598a0427d1SDavid Fries 	return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;
608a0427d1SDavid Fries }
618a0427d1SDavid Fries 
w1_unref_block(struct w1_cb_block * block)628a0427d1SDavid Fries static void w1_unref_block(struct w1_cb_block *block)
638a0427d1SDavid Fries {
648a0427d1SDavid Fries 	if (atomic_sub_return(1, &block->refcnt) == 0) {
658a0427d1SDavid Fries 		u16 len = w1_reply_len(block);
668a0427d1SDavid Fries 		if (len) {
678a0427d1SDavid Fries 			cn_netlink_send_mult(block->first_cn, len,
68*2aa1f7a1SAnjali Kulkarni 					     block->portid, 0,
69*2aa1f7a1SAnjali Kulkarni 					     GFP_KERNEL, NULL, NULL);
708a0427d1SDavid Fries 		}
718a0427d1SDavid Fries 		kfree(block);
728a0427d1SDavid Fries 	}
738a0427d1SDavid Fries }
748a0427d1SDavid Fries 
758a0427d1SDavid Fries /**
768a0427d1SDavid Fries  * w1_reply_make_space() - send message if needed to make space
778a0427d1SDavid Fries  * @block: block to make space on
788a0427d1SDavid Fries  * @space: how many bytes requested
798a0427d1SDavid Fries  *
808a0427d1SDavid Fries  * Verify there is enough room left for the caller to add "space" bytes to the
818a0427d1SDavid Fries  * message, if there isn't send the message and reset.
828a0427d1SDavid Fries  */
w1_reply_make_space(struct w1_cb_block * block,u16 space)838a0427d1SDavid Fries static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
848a0427d1SDavid Fries {
858a0427d1SDavid Fries 	u16 len = w1_reply_len(block);
868a0427d1SDavid Fries 	if (len + space >= block->maxlen) {
87*2aa1f7a1SAnjali Kulkarni 		cn_netlink_send_mult(block->first_cn, len, block->portid,
88*2aa1f7a1SAnjali Kulkarni 				     0, GFP_KERNEL, NULL, NULL);
898a0427d1SDavid Fries 		block->first_cn->len = 0;
908a0427d1SDavid Fries 		block->cn = NULL;
918a0427d1SDavid Fries 		block->msg = NULL;
928a0427d1SDavid Fries 		block->cmd = NULL;
938a0427d1SDavid Fries 	}
948a0427d1SDavid Fries }
958a0427d1SDavid Fries 
968a0427d1SDavid Fries /* Early send when replies aren't bundled. */
w1_netlink_check_send(struct w1_cb_block * block)978a0427d1SDavid Fries static void w1_netlink_check_send(struct w1_cb_block *block)
988a0427d1SDavid Fries {
998a0427d1SDavid Fries 	if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn)
1008a0427d1SDavid Fries 		w1_reply_make_space(block, block->maxlen);
1018a0427d1SDavid Fries }
1028a0427d1SDavid Fries 
1038a0427d1SDavid Fries /**
1048a0427d1SDavid Fries  * w1_netlink_setup_msg() - prepare to write block->msg
1058a0427d1SDavid Fries  * @block: block to operate on
1068a0427d1SDavid Fries  * @ack: determines if cn can be reused
1078a0427d1SDavid Fries  *
1088a0427d1SDavid Fries  * block->cn will be setup with the correct ack, advancing if needed
1098a0427d1SDavid Fries  * block->cn->len does not include space for block->msg
1108a0427d1SDavid Fries  * block->msg advances but remains uninitialized
1118a0427d1SDavid Fries  */
w1_netlink_setup_msg(struct w1_cb_block * block,u32 ack)1128a0427d1SDavid Fries static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack)
1138a0427d1SDavid Fries {
1148a0427d1SDavid Fries 	if (block->cn && block->cn->ack == ack) {
1158a0427d1SDavid Fries 		block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len);
1168a0427d1SDavid Fries 	} else {
1178a0427d1SDavid Fries 		/* advance or set to data */
1188a0427d1SDavid Fries 		if (block->cn)
1198a0427d1SDavid Fries 			block->cn = (struct cn_msg *)(block->cn->data +
1208a0427d1SDavid Fries 				block->cn->len);
1218a0427d1SDavid Fries 		else
1228a0427d1SDavid Fries 			block->cn = block->first_cn;
1238a0427d1SDavid Fries 
1248a0427d1SDavid Fries 		memcpy(block->cn, &block->request_cn, sizeof(*block->cn));
1258a0427d1SDavid Fries 		block->cn->len = 0;
1268a0427d1SDavid Fries 		block->cn->ack = ack;
1278a0427d1SDavid Fries 		block->msg = (struct w1_netlink_msg *)block->cn->data;
1288a0427d1SDavid Fries 	}
1298a0427d1SDavid Fries }
1308a0427d1SDavid Fries 
1318a0427d1SDavid Fries /* Append cmd to msg, include cmd->data as well.  This is because
1328a0427d1SDavid Fries  * any following data goes with the command and in the case of a read is
1338a0427d1SDavid Fries  * the results.
1348a0427d1SDavid Fries  */
w1_netlink_queue_cmd(struct w1_cb_block * block,struct w1_netlink_cmd * cmd)1358a0427d1SDavid Fries static void w1_netlink_queue_cmd(struct w1_cb_block *block,
1368a0427d1SDavid Fries 	struct w1_netlink_cmd *cmd)
1378a0427d1SDavid Fries {
1388a0427d1SDavid Fries 	u32 space;
1398a0427d1SDavid Fries 	w1_reply_make_space(block, sizeof(struct cn_msg) +
1408a0427d1SDavid Fries 		sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len);
1418a0427d1SDavid Fries 
1428a0427d1SDavid Fries 	/* There's a status message sent after each command, so no point
1438a0427d1SDavid Fries 	 * in trying to bundle this cmd after an existing one, because
1448a0427d1SDavid Fries 	 * there won't be one.  Allocate and copy over a new cn_msg.
1458a0427d1SDavid Fries 	 */
1468a0427d1SDavid Fries 	w1_netlink_setup_msg(block, block->request_cn.seq + 1);
1478a0427d1SDavid Fries 	memcpy(block->msg, block->cur_msg, sizeof(*block->msg));
1488a0427d1SDavid Fries 	block->cn->len += sizeof(*block->msg);
1498a0427d1SDavid Fries 	block->msg->len = 0;
1508a0427d1SDavid Fries 	block->cmd = (struct w1_netlink_cmd *)(block->msg->data);
1518a0427d1SDavid Fries 
1528a0427d1SDavid Fries 	space = sizeof(*cmd) + cmd->len;
1538a0427d1SDavid Fries 	if (block->cmd != cmd)
1548a0427d1SDavid Fries 		memcpy(block->cmd, cmd, space);
1558a0427d1SDavid Fries 	block->cn->len += space;
1568a0427d1SDavid Fries 	block->msg->len += space;
1578a0427d1SDavid Fries }
1588a0427d1SDavid Fries 
1598a0427d1SDavid Fries /* Append req_msg and req_cmd, no other commands and no data from req_cmd are
1608a0427d1SDavid Fries  * copied.
1618a0427d1SDavid Fries  */
w1_netlink_queue_status(struct w1_cb_block * block,struct w1_netlink_msg * req_msg,struct w1_netlink_cmd * req_cmd,int error)1628a0427d1SDavid Fries static void w1_netlink_queue_status(struct w1_cb_block *block,
1638a0427d1SDavid Fries 	struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd,
1648a0427d1SDavid Fries 	int error)
1658a0427d1SDavid Fries {
1668a0427d1SDavid Fries 	u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd);
1678a0427d1SDavid Fries 	w1_reply_make_space(block, space);
1688a0427d1SDavid Fries 	w1_netlink_setup_msg(block, block->request_cn.ack);
1698a0427d1SDavid Fries 
1708a0427d1SDavid Fries 	memcpy(block->msg, req_msg, sizeof(*req_msg));
1718a0427d1SDavid Fries 	block->cn->len += sizeof(*req_msg);
1728a0427d1SDavid Fries 	block->msg->len = 0;
1738a0427d1SDavid Fries 	block->msg->status = (u8)-error;
1748a0427d1SDavid Fries 	if (req_cmd) {
1758a0427d1SDavid Fries 		struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data;
1768a0427d1SDavid Fries 		memcpy(cmd, req_cmd, sizeof(*cmd));
1778a0427d1SDavid Fries 		block->cn->len += sizeof(*cmd);
1788a0427d1SDavid Fries 		block->msg->len += sizeof(*cmd);
1798a0427d1SDavid Fries 		cmd->len = 0;
1808a0427d1SDavid Fries 	}
1818a0427d1SDavid Fries 	w1_netlink_check_send(block);
1828a0427d1SDavid Fries }
1838a0427d1SDavid Fries 
1848a0427d1SDavid Fries /**
1858a0427d1SDavid Fries  * w1_netlink_send_error() - sends the error message now
1868a0427d1SDavid Fries  * @cn: original cn_msg
1878a0427d1SDavid Fries  * @msg: original w1_netlink_msg
1888a0427d1SDavid Fries  * @portid: where to send it
1898a0427d1SDavid Fries  * @error: error status
1908a0427d1SDavid Fries  *
1918a0427d1SDavid Fries  * Use when a block isn't available to queue the message to and cn, msg
1928a0427d1SDavid Fries  * might not be contiguous.
1938a0427d1SDavid Fries  */
w1_netlink_send_error(struct cn_msg * cn,struct w1_netlink_msg * msg,int portid,int error)1948a0427d1SDavid Fries static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
1958a0427d1SDavid Fries 	int portid, int error)
1968a0427d1SDavid Fries {
1978a0427d1SDavid Fries 	struct {
1988a0427d1SDavid Fries 		struct cn_msg cn;
1998a0427d1SDavid Fries 		struct w1_netlink_msg msg;
2008a0427d1SDavid Fries 	} packet;
2018a0427d1SDavid Fries 	memcpy(&packet.cn, cn, sizeof(packet.cn));
2028a0427d1SDavid Fries 	memcpy(&packet.msg, msg, sizeof(packet.msg));
2038a0427d1SDavid Fries 	packet.cn.len = sizeof(packet.msg);
2048a0427d1SDavid Fries 	packet.msg.len = 0;
2058a0427d1SDavid Fries 	packet.msg.status = (u8)-error;
2068a0427d1SDavid Fries 	cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL);
2078a0427d1SDavid Fries }
2088a0427d1SDavid Fries 
2098a0427d1SDavid Fries /**
2108a0427d1SDavid Fries  * w1_netlink_send() - sends w1 netlink notifications
2118a0427d1SDavid Fries  * @dev: w1_master the even is associated with or for
2128a0427d1SDavid Fries  * @msg: w1_netlink_msg message to be sent
2138a0427d1SDavid Fries  *
2148a0427d1SDavid Fries  * This are notifications generated from the kernel.
2158a0427d1SDavid Fries  */
w1_netlink_send(struct w1_master * dev,struct w1_netlink_msg * msg)2161da177e4SLinus Torvalds void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
2171da177e4SLinus Torvalds {
2188a0427d1SDavid Fries 	struct {
2198a0427d1SDavid Fries 		struct cn_msg cn;
2208a0427d1SDavid Fries 		struct w1_netlink_msg msg;
2218a0427d1SDavid Fries 	} packet;
2228a0427d1SDavid Fries 	memset(&packet, 0, sizeof(packet));
2231da177e4SLinus Torvalds 
2248a0427d1SDavid Fries 	packet.cn.id.idx = CN_W1_IDX;
2258a0427d1SDavid Fries 	packet.cn.id.val = CN_W1_VAL;
2261da177e4SLinus Torvalds 
2278a0427d1SDavid Fries 	packet.cn.seq = dev->seq++;
2288a0427d1SDavid Fries 	packet.cn.len = sizeof(*msg);
2291da177e4SLinus Torvalds 
2308a0427d1SDavid Fries 	memcpy(&packet.msg, msg, sizeof(*msg));
2318a0427d1SDavid Fries 	packet.msg.len = 0;
23212003375SEvgeniy Polyakov 
2338a0427d1SDavid Fries 	cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
w1_send_slave(struct w1_master * dev,u64 rn)2363b838407SEvgeniy Polyakov static void w1_send_slave(struct w1_master *dev, u64 rn)
2372d833179SEvgeniy Polyakov {
2388a0427d1SDavid Fries 	struct w1_cb_block *block = dev->priv;
2398a0427d1SDavid Fries 	struct w1_netlink_cmd *cache_cmd = block->cmd;
2406b355b33SDavid Fries 	u64 *data;
2412d833179SEvgeniy Polyakov 
2428a0427d1SDavid Fries 	w1_reply_make_space(block, sizeof(*data));
24312003375SEvgeniy Polyakov 
2448a0427d1SDavid Fries 	/* Add cmd back if the packet was sent */
2458a0427d1SDavid Fries 	if (!block->cmd) {
2468a0427d1SDavid Fries 		cache_cmd->len = 0;
2478a0427d1SDavid Fries 		w1_netlink_queue_cmd(block, cache_cmd);
2486b355b33SDavid Fries 	}
2496b355b33SDavid Fries 
2508a0427d1SDavid Fries 	data = (u64 *)(block->cmd->data + block->cmd->len);
2513b838407SEvgeniy Polyakov 
2523b838407SEvgeniy Polyakov 	*data = rn;
2538a0427d1SDavid Fries 	block->cn->len += sizeof(*data);
2548a0427d1SDavid Fries 	block->msg->len += sizeof(*data);
2558a0427d1SDavid Fries 	block->cmd->len += sizeof(*data);
2563b838407SEvgeniy Polyakov }
2573b838407SEvgeniy Polyakov 
w1_found_send_slave(struct w1_master * dev,u64 rn)25870b34d2eSDavid Fries static void w1_found_send_slave(struct w1_master *dev, u64 rn)
2593b838407SEvgeniy Polyakov {
26070b34d2eSDavid Fries 	/* update kernel slave list */
26170b34d2eSDavid Fries 	w1_slave_found(dev, rn);
26270b34d2eSDavid Fries 
26370b34d2eSDavid Fries 	w1_send_slave(dev, rn);
26470b34d2eSDavid Fries }
26570b34d2eSDavid Fries 
26670b34d2eSDavid Fries /* Get the current slave list, or search (with or without alarm) */
w1_get_slaves(struct w1_master * dev,struct w1_netlink_cmd * req_cmd)2678a0427d1SDavid Fries static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd)
26870b34d2eSDavid Fries {
26970b34d2eSDavid Fries 	struct w1_slave *sl;
27070b34d2eSDavid Fries 
2718a0427d1SDavid Fries 	req_cmd->len = 0;
2728a0427d1SDavid Fries 	w1_netlink_queue_cmd(dev->priv, req_cmd);
2733b838407SEvgeniy Polyakov 
27470b34d2eSDavid Fries 	if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
2758a0427d1SDavid Fries 		u64 rn;
2769fcbbac5SDavid Fries 		mutex_lock(&dev->list_mutex);
27770b34d2eSDavid Fries 		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
27870b34d2eSDavid Fries 			memcpy(&rn, &sl->reg_num, sizeof(rn));
27970b34d2eSDavid Fries 			w1_send_slave(dev, rn);
28070b34d2eSDavid Fries 		}
2819fcbbac5SDavid Fries 		mutex_unlock(&dev->list_mutex);
28270b34d2eSDavid Fries 	} else {
2838a0427d1SDavid Fries 		w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ?
28470b34d2eSDavid Fries 			W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
28570b34d2eSDavid Fries 	}
2863b838407SEvgeniy Polyakov 
2872d833179SEvgeniy Polyakov 	return 0;
2882d833179SEvgeniy Polyakov }
2892d833179SEvgeniy Polyakov 
w1_process_command_io(struct w1_master * dev,struct w1_netlink_cmd * cmd)2908a0427d1SDavid Fries static int w1_process_command_io(struct w1_master *dev,
2918a0427d1SDavid Fries 	struct w1_netlink_cmd *cmd)
292c7e26631SEvgeniy Polyakov {
293c7e26631SEvgeniy Polyakov 	int err = 0;
294c7e26631SEvgeniy Polyakov 
295c7e26631SEvgeniy Polyakov 	switch (cmd->cmd) {
296c7e26631SEvgeniy Polyakov 	case W1_CMD_TOUCH:
297c7e26631SEvgeniy Polyakov 		w1_touch_block(dev, cmd->data, cmd->len);
2988a0427d1SDavid Fries 		w1_netlink_queue_cmd(dev->priv, cmd);
299c7e26631SEvgeniy Polyakov 		break;
300c7e26631SEvgeniy Polyakov 	case W1_CMD_READ:
301c7e26631SEvgeniy Polyakov 		w1_read_block(dev, cmd->data, cmd->len);
3028a0427d1SDavid Fries 		w1_netlink_queue_cmd(dev->priv, cmd);
303c7e26631SEvgeniy Polyakov 		break;
304c7e26631SEvgeniy Polyakov 	case W1_CMD_WRITE:
305c7e26631SEvgeniy Polyakov 		w1_write_block(dev, cmd->data, cmd->len);
306c7e26631SEvgeniy Polyakov 		break;
307c7e26631SEvgeniy Polyakov 	default:
3084037014eSEvgeniy Polyakov 		err = -EINVAL;
309c7e26631SEvgeniy Polyakov 		break;
310c7e26631SEvgeniy Polyakov 	}
311c7e26631SEvgeniy Polyakov 
312c7e26631SEvgeniy Polyakov 	return err;
313c7e26631SEvgeniy Polyakov }
314c7e26631SEvgeniy Polyakov 
w1_process_command_addremove(struct w1_master * dev,struct w1_netlink_cmd * cmd)31570b34d2eSDavid Fries static int w1_process_command_addremove(struct w1_master *dev,
31670b34d2eSDavid Fries 	struct w1_netlink_cmd *cmd)
31770b34d2eSDavid Fries {
31870b34d2eSDavid Fries 	struct w1_slave *sl;
31970b34d2eSDavid Fries 	int err = 0;
32070b34d2eSDavid Fries 	struct w1_reg_num *id;
32170b34d2eSDavid Fries 
3228a0427d1SDavid Fries 	if (cmd->len != sizeof(*id))
32370b34d2eSDavid Fries 		return -EINVAL;
32470b34d2eSDavid Fries 
32570b34d2eSDavid Fries 	id = (struct w1_reg_num *)cmd->data;
32670b34d2eSDavid Fries 
32770b34d2eSDavid Fries 	sl = w1_slave_search_device(dev, id);
32870b34d2eSDavid Fries 	switch (cmd->cmd) {
32970b34d2eSDavid Fries 	case W1_CMD_SLAVE_ADD:
33070b34d2eSDavid Fries 		if (sl)
33170b34d2eSDavid Fries 			err = -EINVAL;
33270b34d2eSDavid Fries 		else
33370b34d2eSDavid Fries 			err = w1_attach_slave_device(dev, id);
33470b34d2eSDavid Fries 		break;
33570b34d2eSDavid Fries 	case W1_CMD_SLAVE_REMOVE:
33670b34d2eSDavid Fries 		if (sl)
33770b34d2eSDavid Fries 			w1_slave_detach(sl);
33870b34d2eSDavid Fries 		else
33970b34d2eSDavid Fries 			err = -EINVAL;
34070b34d2eSDavid Fries 		break;
34170b34d2eSDavid Fries 	default:
34270b34d2eSDavid Fries 		err = -EINVAL;
34370b34d2eSDavid Fries 		break;
34470b34d2eSDavid Fries 	}
34570b34d2eSDavid Fries 
34670b34d2eSDavid Fries 	return err;
34770b34d2eSDavid Fries }
34870b34d2eSDavid Fries 
w1_process_command_master(struct w1_master * dev,struct w1_netlink_cmd * req_cmd)34970b34d2eSDavid Fries static int w1_process_command_master(struct w1_master *dev,
35070b34d2eSDavid Fries 	struct w1_netlink_cmd *req_cmd)
3513b838407SEvgeniy Polyakov {
3523b838407SEvgeniy Polyakov 	int err = -EINVAL;
3533b838407SEvgeniy Polyakov 
354d3a8a9dbSDavid Fries 	/* drop bus_mutex for search (does it's own locking), and add/remove
355d3a8a9dbSDavid Fries 	 * which doesn't use the bus
356d3a8a9dbSDavid Fries 	 */
35770b34d2eSDavid Fries 	switch (req_cmd->cmd) {
3583b838407SEvgeniy Polyakov 	case W1_CMD_SEARCH:
3593b838407SEvgeniy Polyakov 	case W1_CMD_ALARM_SEARCH:
36070b34d2eSDavid Fries 	case W1_CMD_LIST_SLAVES:
361d3a8a9dbSDavid Fries 		mutex_unlock(&dev->bus_mutex);
3628a0427d1SDavid Fries 		err = w1_get_slaves(dev, req_cmd);
363d3a8a9dbSDavid Fries 		mutex_lock(&dev->bus_mutex);
3643b838407SEvgeniy Polyakov 		break;
365c7e26631SEvgeniy Polyakov 	case W1_CMD_READ:
366c7e26631SEvgeniy Polyakov 	case W1_CMD_WRITE:
367c7e26631SEvgeniy Polyakov 	case W1_CMD_TOUCH:
3688a0427d1SDavid Fries 		err = w1_process_command_io(dev, req_cmd);
369c7e26631SEvgeniy Polyakov 		break;
370f89735c4SEvgeniy Polyakov 	case W1_CMD_RESET:
371f89735c4SEvgeniy Polyakov 		err = w1_reset_bus(dev);
372f89735c4SEvgeniy Polyakov 		break;
37370b34d2eSDavid Fries 	case W1_CMD_SLAVE_ADD:
37470b34d2eSDavid Fries 	case W1_CMD_SLAVE_REMOVE:
375d3a8a9dbSDavid Fries 		mutex_unlock(&dev->bus_mutex);
376d3a8a9dbSDavid Fries 		mutex_lock(&dev->mutex);
3778a0427d1SDavid Fries 		err = w1_process_command_addremove(dev, req_cmd);
378d3a8a9dbSDavid Fries 		mutex_unlock(&dev->mutex);
379d3a8a9dbSDavid Fries 		mutex_lock(&dev->bus_mutex);
38070b34d2eSDavid Fries 		break;
3813b838407SEvgeniy Polyakov 	default:
3824037014eSEvgeniy Polyakov 		err = -EINVAL;
3833b838407SEvgeniy Polyakov 		break;
3843b838407SEvgeniy Polyakov 	}
3853b838407SEvgeniy Polyakov 
3863b838407SEvgeniy Polyakov 	return err;
3873b838407SEvgeniy Polyakov }
3883b838407SEvgeniy Polyakov 
w1_process_command_slave(struct w1_slave * sl,struct w1_netlink_cmd * cmd)3898a0427d1SDavid Fries static int w1_process_command_slave(struct w1_slave *sl,
3908a0427d1SDavid Fries 		struct w1_netlink_cmd *cmd)
39112003375SEvgeniy Polyakov {
39212003375SEvgeniy Polyakov 	dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
393c7e26631SEvgeniy Polyakov 		__func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id,
394c7e26631SEvgeniy Polyakov 		sl->reg_num.crc, cmd->cmd, cmd->len);
39512003375SEvgeniy Polyakov 
3968a0427d1SDavid Fries 	return w1_process_command_io(sl->master, cmd);
39712003375SEvgeniy Polyakov }
39812003375SEvgeniy Polyakov 
w1_process_command_root(struct cn_msg * req_cn,u32 portid)3998a0427d1SDavid Fries static int w1_process_command_root(struct cn_msg *req_cn, u32 portid)
400610705e7SEvgeniy Polyakov {
4018a0427d1SDavid Fries 	struct w1_master *dev;
402610705e7SEvgeniy Polyakov 	struct cn_msg *cn;
4038a0427d1SDavid Fries 	struct w1_netlink_msg *msg;
404610705e7SEvgeniy Polyakov 	u32 *id;
405610705e7SEvgeniy Polyakov 
406610705e7SEvgeniy Polyakov 	cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
407610705e7SEvgeniy Polyakov 	if (!cn)
408610705e7SEvgeniy Polyakov 		return -ENOMEM;
409610705e7SEvgeniy Polyakov 
410610705e7SEvgeniy Polyakov 	cn->id.idx = CN_W1_IDX;
411610705e7SEvgeniy Polyakov 	cn->id.val = CN_W1_VAL;
412610705e7SEvgeniy Polyakov 
4138a0427d1SDavid Fries 	cn->seq = req_cn->seq;
4148a0427d1SDavid Fries 	cn->ack = req_cn->seq + 1;
415610705e7SEvgeniy Polyakov 	cn->len = sizeof(struct w1_netlink_msg);
4168a0427d1SDavid Fries 	msg = (struct w1_netlink_msg *)cn->data;
417610705e7SEvgeniy Polyakov 
4188a0427d1SDavid Fries 	msg->type = W1_LIST_MASTERS;
4198a0427d1SDavid Fries 	msg->status = 0;
4208a0427d1SDavid Fries 	msg->len = 0;
4218a0427d1SDavid Fries 	id = (u32 *)msg->data;
422610705e7SEvgeniy Polyakov 
423610705e7SEvgeniy Polyakov 	mutex_lock(&w1_mlock);
4248a0427d1SDavid Fries 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
425610705e7SEvgeniy Polyakov 		if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
4265dbf5671SDavid Fries 			cn_netlink_send(cn, portid, 0, GFP_KERNEL);
427610705e7SEvgeniy Polyakov 			cn->len = sizeof(struct w1_netlink_msg);
4288a0427d1SDavid Fries 			msg->len = 0;
4298a0427d1SDavid Fries 			id = (u32 *)msg->data;
430610705e7SEvgeniy Polyakov 		}
431610705e7SEvgeniy Polyakov 
4328a0427d1SDavid Fries 		*id = dev->id;
4338a0427d1SDavid Fries 		msg->len += sizeof(*id);
434610705e7SEvgeniy Polyakov 		cn->len += sizeof(*id);
435610705e7SEvgeniy Polyakov 		id++;
436610705e7SEvgeniy Polyakov 	}
4375dbf5671SDavid Fries 	cn_netlink_send(cn, portid, 0, GFP_KERNEL);
438610705e7SEvgeniy Polyakov 	mutex_unlock(&w1_mlock);
439610705e7SEvgeniy Polyakov 
440610705e7SEvgeniy Polyakov 	kfree(cn);
441610705e7SEvgeniy Polyakov 	return 0;
442610705e7SEvgeniy Polyakov }
443610705e7SEvgeniy Polyakov 
w1_process_cb(struct w1_master * dev,struct w1_async_cmd * async_cmd)4449fcbbac5SDavid Fries static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
4459fcbbac5SDavid Fries {
4469fcbbac5SDavid Fries 	struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
4479fcbbac5SDavid Fries 		async);
4488a0427d1SDavid Fries 	u16 mlen = node->msg->len;
4498a0427d1SDavid Fries 	u16 len;
4509fcbbac5SDavid Fries 	int err = 0;
4519fcbbac5SDavid Fries 	struct w1_slave *sl = node->sl;
4528a0427d1SDavid Fries 	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data;
4539fcbbac5SDavid Fries 
454d3a8a9dbSDavid Fries 	mutex_lock(&dev->bus_mutex);
4558a0427d1SDavid Fries 	dev->priv = node->block;
4569fcbbac5SDavid Fries 	if (sl && w1_reset_select_slave(sl))
4579fcbbac5SDavid Fries 		err = -ENODEV;
4588a0427d1SDavid Fries 	node->block->cur_msg = node->msg;
4599fcbbac5SDavid Fries 
4609fcbbac5SDavid Fries 	while (mlen && !err) {
4619fcbbac5SDavid Fries 		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
4629fcbbac5SDavid Fries 			err = -E2BIG;
4639fcbbac5SDavid Fries 			break;
4649fcbbac5SDavid Fries 		}
4659fcbbac5SDavid Fries 
4669fcbbac5SDavid Fries 		if (sl)
4678a0427d1SDavid Fries 			err = w1_process_command_slave(sl, cmd);
4689fcbbac5SDavid Fries 		else
4698a0427d1SDavid Fries 			err = w1_process_command_master(dev, cmd);
4708a0427d1SDavid Fries 		w1_netlink_check_send(node->block);
4719fcbbac5SDavid Fries 
4728a0427d1SDavid Fries 		w1_netlink_queue_status(node->block, node->msg, cmd, err);
4739fcbbac5SDavid Fries 		err = 0;
4749fcbbac5SDavid Fries 
4758a0427d1SDavid Fries 		len = sizeof(*cmd) + cmd->len;
4768a0427d1SDavid Fries 		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
4778a0427d1SDavid Fries 		mlen -= len;
4789fcbbac5SDavid Fries 	}
4799fcbbac5SDavid Fries 
4809fcbbac5SDavid Fries 	if (!cmd || err)
4818a0427d1SDavid Fries 		w1_netlink_queue_status(node->block, node->msg, cmd, err);
4829fcbbac5SDavid Fries 
483593ceb0cSDavid Fries 	/* ref taken in w1_search_slave or w1_search_master_id when building
484593ceb0cSDavid Fries 	 * the block
485593ceb0cSDavid Fries 	 */
4869fcbbac5SDavid Fries 	if (sl)
4879fcbbac5SDavid Fries 		w1_unref_slave(sl);
4889fcbbac5SDavid Fries 	else
4899fcbbac5SDavid Fries 		atomic_dec(&dev->refcnt);
4908a0427d1SDavid Fries 	dev->priv = NULL;
491d3a8a9dbSDavid Fries 	mutex_unlock(&dev->bus_mutex);
4929fcbbac5SDavid Fries 
4939fcbbac5SDavid Fries 	mutex_lock(&dev->list_mutex);
4949fcbbac5SDavid Fries 	list_del(&async_cmd->async_entry);
4959fcbbac5SDavid Fries 	mutex_unlock(&dev->list_mutex);
4969fcbbac5SDavid Fries 
4978a0427d1SDavid Fries 	w1_unref_block(node->block);
4989fcbbac5SDavid Fries }
4999fcbbac5SDavid Fries 
w1_list_count_cmds(struct w1_netlink_msg * msg,int * cmd_count,u16 * slave_len)5008a0427d1SDavid Fries static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count,
5018a0427d1SDavid Fries 	u16 *slave_len)
50212003375SEvgeniy Polyakov {
5038a0427d1SDavid Fries 	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data;
5048a0427d1SDavid Fries 	u16 mlen = msg->len;
5058a0427d1SDavid Fries 	u16 len;
5068a0427d1SDavid Fries 	int slave_list = 0;
5078a0427d1SDavid Fries 	while (mlen) {
5088a0427d1SDavid Fries 		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen)
5098a0427d1SDavid Fries 			break;
5108a0427d1SDavid Fries 
5118a0427d1SDavid Fries 		switch (cmd->cmd) {
5128a0427d1SDavid Fries 		case W1_CMD_SEARCH:
5138a0427d1SDavid Fries 		case W1_CMD_ALARM_SEARCH:
5148a0427d1SDavid Fries 		case W1_CMD_LIST_SLAVES:
5158a0427d1SDavid Fries 			++slave_list;
5168a0427d1SDavid Fries 		}
5178a0427d1SDavid Fries 		++*cmd_count;
5188a0427d1SDavid Fries 		len = sizeof(*cmd) + cmd->len;
5198a0427d1SDavid Fries 		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
5208a0427d1SDavid Fries 		mlen -= len;
5218a0427d1SDavid Fries 	}
5228a0427d1SDavid Fries 
5238a0427d1SDavid Fries 	if (slave_list) {
5248a0427d1SDavid Fries 		struct w1_master *dev = w1_search_master_id(msg->id.mst.id);
5258a0427d1SDavid Fries 		if (dev) {
5268a0427d1SDavid Fries 			/* Bytes, and likely an overstimate, and if it isn't
5278a0427d1SDavid Fries 			 * the results can still be split between packets.
5288a0427d1SDavid Fries 			 */
5298a0427d1SDavid Fries 			*slave_len += sizeof(struct w1_reg_num) * slave_list *
5308a0427d1SDavid Fries 				(dev->slave_count + dev->max_slave_count);
5318a0427d1SDavid Fries 			/* search incremented it */
5328a0427d1SDavid Fries 			atomic_dec(&dev->refcnt);
5338a0427d1SDavid Fries 		}
5348a0427d1SDavid Fries 	}
5358a0427d1SDavid Fries }
5368a0427d1SDavid Fries 
w1_cn_callback(struct cn_msg * cn,struct netlink_skb_parms * nsp)5378a0427d1SDavid Fries static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp)
5388a0427d1SDavid Fries {
5398a0427d1SDavid Fries 	struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1);
54012003375SEvgeniy Polyakov 	struct w1_slave *sl;
54112003375SEvgeniy Polyakov 	struct w1_master *dev;
5429fcbbac5SDavid Fries 	u16 msg_len;
5438a0427d1SDavid Fries 	u16 slave_len = 0;
54412003375SEvgeniy Polyakov 	int err = 0;
5459fcbbac5SDavid Fries 	struct w1_cb_block *block = NULL;
5469fcbbac5SDavid Fries 	struct w1_cb_node *node = NULL;
5479fcbbac5SDavid Fries 	int node_count = 0;
5488a0427d1SDavid Fries 	int cmd_count = 0;
5498a0427d1SDavid Fries 
5508a0427d1SDavid Fries 	/* If any unknown flag is set let the application know, that way
5518a0427d1SDavid Fries 	 * applications can detect the absence of features in kernels that
5528a0427d1SDavid Fries 	 * don't know about them.  http://lwn.net/Articles/587527/
5538a0427d1SDavid Fries 	 */
5548a0427d1SDavid Fries 	if (cn->flags & ~(W1_CN_BUNDLE)) {
5558a0427d1SDavid Fries 		w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL);
5568a0427d1SDavid Fries 		return;
5578a0427d1SDavid Fries 	}
55812003375SEvgeniy Polyakov 
5599fcbbac5SDavid Fries 	/* Count the number of master or slave commands there are to allocate
5609fcbbac5SDavid Fries 	 * space for one cb_node each.
5619fcbbac5SDavid Fries 	 */
5628a0427d1SDavid Fries 	msg_len = cn->len;
5639fcbbac5SDavid Fries 	while (msg_len && !err) {
5648a0427d1SDavid Fries 		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
5659fcbbac5SDavid Fries 			err = -E2BIG;
5669fcbbac5SDavid Fries 			break;
5679fcbbac5SDavid Fries 		}
5689fcbbac5SDavid Fries 
5698a0427d1SDavid Fries 		/* count messages for nodes and allocate any additional space
5708a0427d1SDavid Fries 		 * required for slave lists
5718a0427d1SDavid Fries 		 */
5728a0427d1SDavid Fries 		if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) {
5739fcbbac5SDavid Fries 			++node_count;
5748a0427d1SDavid Fries 			w1_list_count_cmds(msg, &cmd_count, &slave_len);
5759fcbbac5SDavid Fries 		}
5768a0427d1SDavid Fries 
5778a0427d1SDavid Fries 		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
5788a0427d1SDavid Fries 		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
5798a0427d1SDavid Fries 			sizeof(struct w1_netlink_msg) + msg->len);
5808a0427d1SDavid Fries 	}
5818a0427d1SDavid Fries 	msg = (struct w1_netlink_msg *)(cn + 1);
5829fcbbac5SDavid Fries 	if (node_count) {
5838a0427d1SDavid Fries 		int size;
5844b97b279SDavid Fries 		int reply_size = sizeof(*cn) + cn->len + slave_len;
5858a0427d1SDavid Fries 		if (cn->flags & W1_CN_BUNDLE) {
5868a0427d1SDavid Fries 			/* bundling duplicats some of the messages */
5878a0427d1SDavid Fries 			reply_size += 2 * cmd_count * (sizeof(struct cn_msg) +
5888a0427d1SDavid Fries 				sizeof(struct w1_netlink_msg) +
5898a0427d1SDavid Fries 				sizeof(struct w1_netlink_cmd));
5908a0427d1SDavid Fries 		}
591b04e0854SAndrew F. Davis 		reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size);
5928a0427d1SDavid Fries 
5938a0427d1SDavid Fries 		/* allocate space for the block, a copy of the original message,
5948a0427d1SDavid Fries 		 * one node per cmd to point into the original message,
5958a0427d1SDavid Fries 		 * space for replies which is the original message size plus
5968a0427d1SDavid Fries 		 * space for any list slave data and status messages
5978a0427d1SDavid Fries 		 * cn->len doesn't include itself which is part of the block
5988a0427d1SDavid Fries 		 * */
5998a0427d1SDavid Fries 		size =  /* block + original message */
6008a0427d1SDavid Fries 			sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len +
6018a0427d1SDavid Fries 			/* space for nodes */
6028a0427d1SDavid Fries 			node_count * sizeof(struct w1_cb_node) +
6038a0427d1SDavid Fries 			/* replies */
6048a0427d1SDavid Fries 			sizeof(struct cn_msg) + reply_size;
6058a0427d1SDavid Fries 		block = kzalloc(size, GFP_KERNEL);
6069fcbbac5SDavid Fries 		if (!block) {
6078a0427d1SDavid Fries 			/* if the system is already out of memory,
6088a0427d1SDavid Fries 			 * (A) will this work, and (B) would it be better
6098a0427d1SDavid Fries 			 * to not try?
6108a0427d1SDavid Fries 			 */
6118a0427d1SDavid Fries 			w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM);
6129fcbbac5SDavid Fries 			return;
6139fcbbac5SDavid Fries 		}
6149fcbbac5SDavid Fries 		atomic_set(&block->refcnt, 1);
6155dbf5671SDavid Fries 		block->portid = nsp->portid;
6167cd04013SKees Cook 		block->request_cn = *cn;
6177cd04013SKees Cook 		memcpy(block->request_cn.data, cn->data, cn->len);
6188a0427d1SDavid Fries 		node = (struct w1_cb_node *)(block->request_cn.data + cn->len);
6198a0427d1SDavid Fries 
6208a0427d1SDavid Fries 		/* Sneeky, when not bundling, reply_size is the allocated space
6218a0427d1SDavid Fries 		 * required for the reply, cn_msg isn't part of maxlen so
6228a0427d1SDavid Fries 		 * it should be reply_size - sizeof(struct cn_msg), however
6238a0427d1SDavid Fries 		 * when checking if there is enough space, w1_reply_make_space
6248a0427d1SDavid Fries 		 * is called with the full message size including cn_msg,
6258a0427d1SDavid Fries 		 * because it isn't known at that time if an additional cn_msg
6268a0427d1SDavid Fries 		 * will need to be allocated.  So an extra cn_msg is added
6278a0427d1SDavid Fries 		 * above in "size".
6288a0427d1SDavid Fries 		 */
6298a0427d1SDavid Fries 		block->maxlen = reply_size;
6308a0427d1SDavid Fries 		block->first_cn = (struct cn_msg *)(node + node_count);
6318a0427d1SDavid Fries 		memset(block->first_cn, 0, sizeof(*block->first_cn));
6329fcbbac5SDavid Fries 	}
6339fcbbac5SDavid Fries 
6348a0427d1SDavid Fries 	msg_len = cn->len;
6359fcbbac5SDavid Fries 	while (msg_len && !err) {
63612003375SEvgeniy Polyakov 
63712003375SEvgeniy Polyakov 		dev = NULL;
63812003375SEvgeniy Polyakov 		sl = NULL;
63912003375SEvgeniy Polyakov 
6408a0427d1SDavid Fries 		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
64112003375SEvgeniy Polyakov 			err = -E2BIG;
64212003375SEvgeniy Polyakov 			break;
64312003375SEvgeniy Polyakov 		}
64412003375SEvgeniy Polyakov 
645593ceb0cSDavid Fries 		/* execute on this thread, no need to process later */
6468a0427d1SDavid Fries 		if (msg->type == W1_LIST_MASTERS) {
6478a0427d1SDavid Fries 			err = w1_process_command_root(cn, nsp->portid);
648593ceb0cSDavid Fries 			goto out_cont;
649593ceb0cSDavid Fries 		}
650593ceb0cSDavid Fries 
651593ceb0cSDavid Fries 		/* All following message types require additional data,
652593ceb0cSDavid Fries 		 * check here before references are taken.
653593ceb0cSDavid Fries 		 */
6548a0427d1SDavid Fries 		if (!msg->len) {
655593ceb0cSDavid Fries 			err = -EPROTO;
656593ceb0cSDavid Fries 			goto out_cont;
657593ceb0cSDavid Fries 		}
658593ceb0cSDavid Fries 
6598a0427d1SDavid Fries 		/* both search calls take references */
6608a0427d1SDavid Fries 		if (msg->type == W1_MASTER_CMD) {
6618a0427d1SDavid Fries 			dev = w1_search_master_id(msg->id.mst.id);
6628a0427d1SDavid Fries 		} else if (msg->type == W1_SLAVE_CMD) {
6638a0427d1SDavid Fries 			sl = w1_search_slave((struct w1_reg_num *)msg->id.id);
66412003375SEvgeniy Polyakov 			if (sl)
66512003375SEvgeniy Polyakov 				dev = sl->master;
666610705e7SEvgeniy Polyakov 		} else {
667fdc9167aSFjodor Schelichow 			pr_notice("%s: cn: %x.%x, wrong type: %u, len: %u.\n",
6688a0427d1SDavid Fries 				__func__, cn->id.idx, cn->id.val,
6698a0427d1SDavid Fries 				msg->type, msg->len);
670593ceb0cSDavid Fries 			err = -EPROTO;
671610705e7SEvgeniy Polyakov 			goto out_cont;
67212003375SEvgeniy Polyakov 		}
67312003375SEvgeniy Polyakov 
67412003375SEvgeniy Polyakov 		if (!dev) {
67512003375SEvgeniy Polyakov 			err = -ENODEV;
67612003375SEvgeniy Polyakov 			goto out_cont;
67712003375SEvgeniy Polyakov 		}
67812003375SEvgeniy Polyakov 
6799be62e0bSEvgeniy Polyakov 		err = 0;
6809be62e0bSEvgeniy Polyakov 
6819fcbbac5SDavid Fries 		atomic_inc(&block->refcnt);
6829fcbbac5SDavid Fries 		node->async.cb = w1_process_cb;
6839fcbbac5SDavid Fries 		node->block = block;
6848a0427d1SDavid Fries 		node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn +
6858a0427d1SDavid Fries 			(size_t)((u8 *)msg - (u8 *)cn));
6869fcbbac5SDavid Fries 		node->sl = sl;
6879fcbbac5SDavid Fries 		node->dev = dev;
68812003375SEvgeniy Polyakov 
6899fcbbac5SDavid Fries 		mutex_lock(&dev->list_mutex);
6909fcbbac5SDavid Fries 		list_add_tail(&node->async.async_entry, &dev->async_list);
6919fcbbac5SDavid Fries 		wake_up_process(dev->thread);
6929fcbbac5SDavid Fries 		mutex_unlock(&dev->list_mutex);
6939fcbbac5SDavid Fries 		++node;
69412003375SEvgeniy Polyakov 
69512003375SEvgeniy Polyakov out_cont:
6968a0427d1SDavid Fries 		/* Can't queue because that modifies block and another
6978a0427d1SDavid Fries 		 * thread could be processing the messages by now and
6988a0427d1SDavid Fries 		 * there isn't a lock, send directly.
6998a0427d1SDavid Fries 		 */
7009fcbbac5SDavid Fries 		if (err)
7018a0427d1SDavid Fries 			w1_netlink_send_error(cn, msg, nsp->portid, err);
7028a0427d1SDavid Fries 		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
7038a0427d1SDavid Fries 		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
7048a0427d1SDavid Fries 			sizeof(struct w1_netlink_msg) + msg->len);
70512003375SEvgeniy Polyakov 
70612003375SEvgeniy Polyakov 		/*
70712003375SEvgeniy Polyakov 		 * Let's allow requests for nonexisting devices.
70812003375SEvgeniy Polyakov 		 */
70912003375SEvgeniy Polyakov 		if (err == -ENODEV)
71012003375SEvgeniy Polyakov 			err = 0;
71112003375SEvgeniy Polyakov 	}
7128a0427d1SDavid Fries 	if (block)
7138a0427d1SDavid Fries 		w1_unref_block(block);
71412003375SEvgeniy Polyakov }
71512003375SEvgeniy Polyakov 
w1_init_netlink(void)71612003375SEvgeniy Polyakov int w1_init_netlink(void)
71712003375SEvgeniy Polyakov {
71812003375SEvgeniy Polyakov 	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
71912003375SEvgeniy Polyakov 
72012003375SEvgeniy Polyakov 	return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
72112003375SEvgeniy Polyakov }
72212003375SEvgeniy Polyakov 
w1_fini_netlink(void)72312003375SEvgeniy Polyakov void w1_fini_netlink(void)
72412003375SEvgeniy Polyakov {
72512003375SEvgeniy Polyakov 	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
72612003375SEvgeniy Polyakov 
72712003375SEvgeniy Polyakov 	cn_del_callback(&w1_id);
7282d833179SEvgeniy Polyakov }
7291da177e4SLinus Torvalds #else
w1_netlink_send(struct w1_master * dev,struct w1_netlink_msg * cn)7308a0427d1SDavid Fries void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *cn)
7311da177e4SLinus Torvalds {
7321da177e4SLinus Torvalds }
7332d833179SEvgeniy Polyakov 
w1_init_netlink(void)73412003375SEvgeniy Polyakov int w1_init_netlink(void)
7352d833179SEvgeniy Polyakov {
7362d833179SEvgeniy Polyakov 	return 0;
7372d833179SEvgeniy Polyakov }
7382d833179SEvgeniy Polyakov 
w1_fini_netlink(void)73912003375SEvgeniy Polyakov void w1_fini_netlink(void)
7402d833179SEvgeniy Polyakov {
7412d833179SEvgeniy Polyakov }
7421da177e4SLinus Torvalds #endif
743