xref: /OK3568_Linux_fs/kernel/drivers/w1/w1_netlink.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/slab.h>
7*4882a593Smuzhiyun #include <linux/skbuff.h>
8*4882a593Smuzhiyun #include <linux/netlink.h>
9*4882a593Smuzhiyun #include <linux/connector.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "w1_internal.h"
12*4882a593Smuzhiyun #include "w1_netlink.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun /* Bundle together everything required to process a request in one memory
17*4882a593Smuzhiyun  * allocation.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun struct w1_cb_block {
20*4882a593Smuzhiyun 	atomic_t refcnt;
21*4882a593Smuzhiyun 	u32 portid; /* Sending process port ID */
22*4882a593Smuzhiyun 	/* maximum value for first_cn->len */
23*4882a593Smuzhiyun 	u16 maxlen;
24*4882a593Smuzhiyun 	/* pointers to building up the reply message */
25*4882a593Smuzhiyun 	struct cn_msg *first_cn; /* fixed once the structure is populated */
26*4882a593Smuzhiyun 	struct cn_msg *cn; /* advances as cn_msg is appeneded */
27*4882a593Smuzhiyun 	struct w1_netlink_msg *msg; /* advances as w1_netlink_msg is appened */
28*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd; /* advances as cmds are appened */
29*4882a593Smuzhiyun 	struct w1_netlink_msg *cur_msg; /* currently message being processed */
30*4882a593Smuzhiyun 	/* copy of the original request follows */
31*4882a593Smuzhiyun 	struct cn_msg request_cn;
32*4882a593Smuzhiyun 	/* followed by variable length:
33*4882a593Smuzhiyun 	 * cn_msg, data (w1_netlink_msg and w1_netlink_cmd)
34*4882a593Smuzhiyun 	 * one or more struct w1_cb_node
35*4882a593Smuzhiyun 	 * reply first_cn, data (w1_netlink_msg and w1_netlink_cmd)
36*4882a593Smuzhiyun 	 */
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun struct w1_cb_node {
39*4882a593Smuzhiyun 	struct w1_async_cmd async;
40*4882a593Smuzhiyun 	/* pointers within w1_cb_block and cn data */
41*4882a593Smuzhiyun 	struct w1_cb_block *block;
42*4882a593Smuzhiyun 	struct w1_netlink_msg *msg;
43*4882a593Smuzhiyun 	struct w1_slave *sl;
44*4882a593Smuzhiyun 	struct w1_master *dev;
45*4882a593Smuzhiyun };
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /**
48*4882a593Smuzhiyun  * w1_reply_len() - calculate current reply length, compare to maxlen
49*4882a593Smuzhiyun  * @block: block to calculate
50*4882a593Smuzhiyun  *
51*4882a593Smuzhiyun  * Calculates the current message length including possible multiple
52*4882a593Smuzhiyun  * cn_msg and data, excludes the first sizeof(struct cn_msg).  Direclty
53*4882a593Smuzhiyun  * compariable to maxlen and usable to send the message.
54*4882a593Smuzhiyun  */
w1_reply_len(struct w1_cb_block * block)55*4882a593Smuzhiyun static u16 w1_reply_len(struct w1_cb_block *block)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	if (!block->cn)
58*4882a593Smuzhiyun 		return 0;
59*4882a593Smuzhiyun 	return (u8 *)block->cn - (u8 *)block->first_cn + block->cn->len;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
w1_unref_block(struct w1_cb_block * block)62*4882a593Smuzhiyun static void w1_unref_block(struct w1_cb_block *block)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	if (atomic_sub_return(1, &block->refcnt) == 0) {
65*4882a593Smuzhiyun 		u16 len = w1_reply_len(block);
66*4882a593Smuzhiyun 		if (len) {
67*4882a593Smuzhiyun 			cn_netlink_send_mult(block->first_cn, len,
68*4882a593Smuzhiyun 				block->portid, 0, GFP_KERNEL);
69*4882a593Smuzhiyun 		}
70*4882a593Smuzhiyun 		kfree(block);
71*4882a593Smuzhiyun 	}
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun  * w1_reply_make_space() - send message if needed to make space
76*4882a593Smuzhiyun  * @block: block to make space on
77*4882a593Smuzhiyun  * @space: how many bytes requested
78*4882a593Smuzhiyun  *
79*4882a593Smuzhiyun  * Verify there is enough room left for the caller to add "space" bytes to the
80*4882a593Smuzhiyun  * message, if there isn't send the message and reset.
81*4882a593Smuzhiyun  */
w1_reply_make_space(struct w1_cb_block * block,u16 space)82*4882a593Smuzhiyun static void w1_reply_make_space(struct w1_cb_block *block, u16 space)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	u16 len = w1_reply_len(block);
85*4882a593Smuzhiyun 	if (len + space >= block->maxlen) {
86*4882a593Smuzhiyun 		cn_netlink_send_mult(block->first_cn, len, block->portid, 0, GFP_KERNEL);
87*4882a593Smuzhiyun 		block->first_cn->len = 0;
88*4882a593Smuzhiyun 		block->cn = NULL;
89*4882a593Smuzhiyun 		block->msg = NULL;
90*4882a593Smuzhiyun 		block->cmd = NULL;
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun /* Early send when replies aren't bundled. */
w1_netlink_check_send(struct w1_cb_block * block)95*4882a593Smuzhiyun static void w1_netlink_check_send(struct w1_cb_block *block)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	if (!(block->request_cn.flags & W1_CN_BUNDLE) && block->cn)
98*4882a593Smuzhiyun 		w1_reply_make_space(block, block->maxlen);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /**
102*4882a593Smuzhiyun  * w1_netlink_setup_msg() - prepare to write block->msg
103*4882a593Smuzhiyun  * @block: block to operate on
104*4882a593Smuzhiyun  * @ack: determines if cn can be reused
105*4882a593Smuzhiyun  *
106*4882a593Smuzhiyun  * block->cn will be setup with the correct ack, advancing if needed
107*4882a593Smuzhiyun  * block->cn->len does not include space for block->msg
108*4882a593Smuzhiyun  * block->msg advances but remains uninitialized
109*4882a593Smuzhiyun  */
w1_netlink_setup_msg(struct w1_cb_block * block,u32 ack)110*4882a593Smuzhiyun static void w1_netlink_setup_msg(struct w1_cb_block *block, u32 ack)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	if (block->cn && block->cn->ack == ack) {
113*4882a593Smuzhiyun 		block->msg = (struct w1_netlink_msg *)(block->cn->data + block->cn->len);
114*4882a593Smuzhiyun 	} else {
115*4882a593Smuzhiyun 		/* advance or set to data */
116*4882a593Smuzhiyun 		if (block->cn)
117*4882a593Smuzhiyun 			block->cn = (struct cn_msg *)(block->cn->data +
118*4882a593Smuzhiyun 				block->cn->len);
119*4882a593Smuzhiyun 		else
120*4882a593Smuzhiyun 			block->cn = block->first_cn;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		memcpy(block->cn, &block->request_cn, sizeof(*block->cn));
123*4882a593Smuzhiyun 		block->cn->len = 0;
124*4882a593Smuzhiyun 		block->cn->ack = ack;
125*4882a593Smuzhiyun 		block->msg = (struct w1_netlink_msg *)block->cn->data;
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /* Append cmd to msg, include cmd->data as well.  This is because
130*4882a593Smuzhiyun  * any following data goes with the command and in the case of a read is
131*4882a593Smuzhiyun  * the results.
132*4882a593Smuzhiyun  */
w1_netlink_queue_cmd(struct w1_cb_block * block,struct w1_netlink_cmd * cmd)133*4882a593Smuzhiyun static void w1_netlink_queue_cmd(struct w1_cb_block *block,
134*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	u32 space;
137*4882a593Smuzhiyun 	w1_reply_make_space(block, sizeof(struct cn_msg) +
138*4882a593Smuzhiyun 		sizeof(struct w1_netlink_msg) + sizeof(*cmd) + cmd->len);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* There's a status message sent after each command, so no point
141*4882a593Smuzhiyun 	 * in trying to bundle this cmd after an existing one, because
142*4882a593Smuzhiyun 	 * there won't be one.  Allocate and copy over a new cn_msg.
143*4882a593Smuzhiyun 	 */
144*4882a593Smuzhiyun 	w1_netlink_setup_msg(block, block->request_cn.seq + 1);
145*4882a593Smuzhiyun 	memcpy(block->msg, block->cur_msg, sizeof(*block->msg));
146*4882a593Smuzhiyun 	block->cn->len += sizeof(*block->msg);
147*4882a593Smuzhiyun 	block->msg->len = 0;
148*4882a593Smuzhiyun 	block->cmd = (struct w1_netlink_cmd *)(block->msg->data);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	space = sizeof(*cmd) + cmd->len;
151*4882a593Smuzhiyun 	if (block->cmd != cmd)
152*4882a593Smuzhiyun 		memcpy(block->cmd, cmd, space);
153*4882a593Smuzhiyun 	block->cn->len += space;
154*4882a593Smuzhiyun 	block->msg->len += space;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun /* Append req_msg and req_cmd, no other commands and no data from req_cmd are
158*4882a593Smuzhiyun  * copied.
159*4882a593Smuzhiyun  */
w1_netlink_queue_status(struct w1_cb_block * block,struct w1_netlink_msg * req_msg,struct w1_netlink_cmd * req_cmd,int error)160*4882a593Smuzhiyun static void w1_netlink_queue_status(struct w1_cb_block *block,
161*4882a593Smuzhiyun 	struct w1_netlink_msg *req_msg, struct w1_netlink_cmd *req_cmd,
162*4882a593Smuzhiyun 	int error)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	u16 space = sizeof(struct cn_msg) + sizeof(*req_msg) + sizeof(*req_cmd);
165*4882a593Smuzhiyun 	w1_reply_make_space(block, space);
166*4882a593Smuzhiyun 	w1_netlink_setup_msg(block, block->request_cn.ack);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	memcpy(block->msg, req_msg, sizeof(*req_msg));
169*4882a593Smuzhiyun 	block->cn->len += sizeof(*req_msg);
170*4882a593Smuzhiyun 	block->msg->len = 0;
171*4882a593Smuzhiyun 	block->msg->status = (u8)-error;
172*4882a593Smuzhiyun 	if (req_cmd) {
173*4882a593Smuzhiyun 		struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)block->msg->data;
174*4882a593Smuzhiyun 		memcpy(cmd, req_cmd, sizeof(*cmd));
175*4882a593Smuzhiyun 		block->cn->len += sizeof(*cmd);
176*4882a593Smuzhiyun 		block->msg->len += sizeof(*cmd);
177*4882a593Smuzhiyun 		cmd->len = 0;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 	w1_netlink_check_send(block);
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun /**
183*4882a593Smuzhiyun  * w1_netlink_send_error() - sends the error message now
184*4882a593Smuzhiyun  * @cn: original cn_msg
185*4882a593Smuzhiyun  * @msg: original w1_netlink_msg
186*4882a593Smuzhiyun  * @portid: where to send it
187*4882a593Smuzhiyun  * @error: error status
188*4882a593Smuzhiyun  *
189*4882a593Smuzhiyun  * Use when a block isn't available to queue the message to and cn, msg
190*4882a593Smuzhiyun  * might not be contiguous.
191*4882a593Smuzhiyun  */
w1_netlink_send_error(struct cn_msg * cn,struct w1_netlink_msg * msg,int portid,int error)192*4882a593Smuzhiyun static void w1_netlink_send_error(struct cn_msg *cn, struct w1_netlink_msg *msg,
193*4882a593Smuzhiyun 	int portid, int error)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct {
196*4882a593Smuzhiyun 		struct cn_msg cn;
197*4882a593Smuzhiyun 		struct w1_netlink_msg msg;
198*4882a593Smuzhiyun 	} packet;
199*4882a593Smuzhiyun 	memcpy(&packet.cn, cn, sizeof(packet.cn));
200*4882a593Smuzhiyun 	memcpy(&packet.msg, msg, sizeof(packet.msg));
201*4882a593Smuzhiyun 	packet.cn.len = sizeof(packet.msg);
202*4882a593Smuzhiyun 	packet.msg.len = 0;
203*4882a593Smuzhiyun 	packet.msg.status = (u8)-error;
204*4882a593Smuzhiyun 	cn_netlink_send(&packet.cn, portid, 0, GFP_KERNEL);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /**
208*4882a593Smuzhiyun  * w1_netlink_send() - sends w1 netlink notifications
209*4882a593Smuzhiyun  * @dev: w1_master the even is associated with or for
210*4882a593Smuzhiyun  * @msg: w1_netlink_msg message to be sent
211*4882a593Smuzhiyun  *
212*4882a593Smuzhiyun  * This are notifications generated from the kernel.
213*4882a593Smuzhiyun  */
w1_netlink_send(struct w1_master * dev,struct w1_netlink_msg * msg)214*4882a593Smuzhiyun void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct {
217*4882a593Smuzhiyun 		struct cn_msg cn;
218*4882a593Smuzhiyun 		struct w1_netlink_msg msg;
219*4882a593Smuzhiyun 	} packet;
220*4882a593Smuzhiyun 	memset(&packet, 0, sizeof(packet));
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	packet.cn.id.idx = CN_W1_IDX;
223*4882a593Smuzhiyun 	packet.cn.id.val = CN_W1_VAL;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	packet.cn.seq = dev->seq++;
226*4882a593Smuzhiyun 	packet.cn.len = sizeof(*msg);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	memcpy(&packet.msg, msg, sizeof(*msg));
229*4882a593Smuzhiyun 	packet.msg.len = 0;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	cn_netlink_send(&packet.cn, 0, 0, GFP_KERNEL);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
w1_send_slave(struct w1_master * dev,u64 rn)234*4882a593Smuzhiyun static void w1_send_slave(struct w1_master *dev, u64 rn)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	struct w1_cb_block *block = dev->priv;
237*4882a593Smuzhiyun 	struct w1_netlink_cmd *cache_cmd = block->cmd;
238*4882a593Smuzhiyun 	u64 *data;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	w1_reply_make_space(block, sizeof(*data));
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	/* Add cmd back if the packet was sent */
243*4882a593Smuzhiyun 	if (!block->cmd) {
244*4882a593Smuzhiyun 		cache_cmd->len = 0;
245*4882a593Smuzhiyun 		w1_netlink_queue_cmd(block, cache_cmd);
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	data = (u64 *)(block->cmd->data + block->cmd->len);
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	*data = rn;
251*4882a593Smuzhiyun 	block->cn->len += sizeof(*data);
252*4882a593Smuzhiyun 	block->msg->len += sizeof(*data);
253*4882a593Smuzhiyun 	block->cmd->len += sizeof(*data);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun 
w1_found_send_slave(struct w1_master * dev,u64 rn)256*4882a593Smuzhiyun static void w1_found_send_slave(struct w1_master *dev, u64 rn)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	/* update kernel slave list */
259*4882a593Smuzhiyun 	w1_slave_found(dev, rn);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	w1_send_slave(dev, rn);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun /* Get the current slave list, or search (with or without alarm) */
w1_get_slaves(struct w1_master * dev,struct w1_netlink_cmd * req_cmd)265*4882a593Smuzhiyun static int w1_get_slaves(struct w1_master *dev, struct w1_netlink_cmd *req_cmd)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	struct w1_slave *sl;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	req_cmd->len = 0;
270*4882a593Smuzhiyun 	w1_netlink_queue_cmd(dev->priv, req_cmd);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	if (req_cmd->cmd == W1_CMD_LIST_SLAVES) {
273*4882a593Smuzhiyun 		u64 rn;
274*4882a593Smuzhiyun 		mutex_lock(&dev->list_mutex);
275*4882a593Smuzhiyun 		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
276*4882a593Smuzhiyun 			memcpy(&rn, &sl->reg_num, sizeof(rn));
277*4882a593Smuzhiyun 			w1_send_slave(dev, rn);
278*4882a593Smuzhiyun 		}
279*4882a593Smuzhiyun 		mutex_unlock(&dev->list_mutex);
280*4882a593Smuzhiyun 	} else {
281*4882a593Smuzhiyun 		w1_search_process_cb(dev, req_cmd->cmd == W1_CMD_ALARM_SEARCH ?
282*4882a593Smuzhiyun 			W1_ALARM_SEARCH : W1_SEARCH, w1_found_send_slave);
283*4882a593Smuzhiyun 	}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
w1_process_command_io(struct w1_master * dev,struct w1_netlink_cmd * cmd)288*4882a593Smuzhiyun static int w1_process_command_io(struct w1_master *dev,
289*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	int err = 0;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	switch (cmd->cmd) {
294*4882a593Smuzhiyun 	case W1_CMD_TOUCH:
295*4882a593Smuzhiyun 		w1_touch_block(dev, cmd->data, cmd->len);
296*4882a593Smuzhiyun 		w1_netlink_queue_cmd(dev->priv, cmd);
297*4882a593Smuzhiyun 		break;
298*4882a593Smuzhiyun 	case W1_CMD_READ:
299*4882a593Smuzhiyun 		w1_read_block(dev, cmd->data, cmd->len);
300*4882a593Smuzhiyun 		w1_netlink_queue_cmd(dev->priv, cmd);
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 	case W1_CMD_WRITE:
303*4882a593Smuzhiyun 		w1_write_block(dev, cmd->data, cmd->len);
304*4882a593Smuzhiyun 		break;
305*4882a593Smuzhiyun 	default:
306*4882a593Smuzhiyun 		err = -EINVAL;
307*4882a593Smuzhiyun 		break;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	return err;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
w1_process_command_addremove(struct w1_master * dev,struct w1_netlink_cmd * cmd)313*4882a593Smuzhiyun static int w1_process_command_addremove(struct w1_master *dev,
314*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	struct w1_slave *sl;
317*4882a593Smuzhiyun 	int err = 0;
318*4882a593Smuzhiyun 	struct w1_reg_num *id;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (cmd->len != sizeof(*id))
321*4882a593Smuzhiyun 		return -EINVAL;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	id = (struct w1_reg_num *)cmd->data;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	sl = w1_slave_search_device(dev, id);
326*4882a593Smuzhiyun 	switch (cmd->cmd) {
327*4882a593Smuzhiyun 	case W1_CMD_SLAVE_ADD:
328*4882a593Smuzhiyun 		if (sl)
329*4882a593Smuzhiyun 			err = -EINVAL;
330*4882a593Smuzhiyun 		else
331*4882a593Smuzhiyun 			err = w1_attach_slave_device(dev, id);
332*4882a593Smuzhiyun 		break;
333*4882a593Smuzhiyun 	case W1_CMD_SLAVE_REMOVE:
334*4882a593Smuzhiyun 		if (sl)
335*4882a593Smuzhiyun 			w1_slave_detach(sl);
336*4882a593Smuzhiyun 		else
337*4882a593Smuzhiyun 			err = -EINVAL;
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 	default:
340*4882a593Smuzhiyun 		err = -EINVAL;
341*4882a593Smuzhiyun 		break;
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	return err;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
w1_process_command_master(struct w1_master * dev,struct w1_netlink_cmd * req_cmd)347*4882a593Smuzhiyun static int w1_process_command_master(struct w1_master *dev,
348*4882a593Smuzhiyun 	struct w1_netlink_cmd *req_cmd)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	int err = -EINVAL;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	/* drop bus_mutex for search (does it's own locking), and add/remove
353*4882a593Smuzhiyun 	 * which doesn't use the bus
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 	switch (req_cmd->cmd) {
356*4882a593Smuzhiyun 	case W1_CMD_SEARCH:
357*4882a593Smuzhiyun 	case W1_CMD_ALARM_SEARCH:
358*4882a593Smuzhiyun 	case W1_CMD_LIST_SLAVES:
359*4882a593Smuzhiyun 		mutex_unlock(&dev->bus_mutex);
360*4882a593Smuzhiyun 		err = w1_get_slaves(dev, req_cmd);
361*4882a593Smuzhiyun 		mutex_lock(&dev->bus_mutex);
362*4882a593Smuzhiyun 		break;
363*4882a593Smuzhiyun 	case W1_CMD_READ:
364*4882a593Smuzhiyun 	case W1_CMD_WRITE:
365*4882a593Smuzhiyun 	case W1_CMD_TOUCH:
366*4882a593Smuzhiyun 		err = w1_process_command_io(dev, req_cmd);
367*4882a593Smuzhiyun 		break;
368*4882a593Smuzhiyun 	case W1_CMD_RESET:
369*4882a593Smuzhiyun 		err = w1_reset_bus(dev);
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 	case W1_CMD_SLAVE_ADD:
372*4882a593Smuzhiyun 	case W1_CMD_SLAVE_REMOVE:
373*4882a593Smuzhiyun 		mutex_unlock(&dev->bus_mutex);
374*4882a593Smuzhiyun 		mutex_lock(&dev->mutex);
375*4882a593Smuzhiyun 		err = w1_process_command_addremove(dev, req_cmd);
376*4882a593Smuzhiyun 		mutex_unlock(&dev->mutex);
377*4882a593Smuzhiyun 		mutex_lock(&dev->bus_mutex);
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	default:
380*4882a593Smuzhiyun 		err = -EINVAL;
381*4882a593Smuzhiyun 		break;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	return err;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
w1_process_command_slave(struct w1_slave * sl,struct w1_netlink_cmd * cmd)387*4882a593Smuzhiyun static int w1_process_command_slave(struct w1_slave *sl,
388*4882a593Smuzhiyun 		struct w1_netlink_cmd *cmd)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
391*4882a593Smuzhiyun 		__func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id,
392*4882a593Smuzhiyun 		sl->reg_num.crc, cmd->cmd, cmd->len);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	return w1_process_command_io(sl->master, cmd);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
w1_process_command_root(struct cn_msg * req_cn,u32 portid)397*4882a593Smuzhiyun static int w1_process_command_root(struct cn_msg *req_cn, u32 portid)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	struct w1_master *dev;
400*4882a593Smuzhiyun 	struct cn_msg *cn;
401*4882a593Smuzhiyun 	struct w1_netlink_msg *msg;
402*4882a593Smuzhiyun 	u32 *id;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
405*4882a593Smuzhiyun 	if (!cn)
406*4882a593Smuzhiyun 		return -ENOMEM;
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	cn->id.idx = CN_W1_IDX;
409*4882a593Smuzhiyun 	cn->id.val = CN_W1_VAL;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	cn->seq = req_cn->seq;
412*4882a593Smuzhiyun 	cn->ack = req_cn->seq + 1;
413*4882a593Smuzhiyun 	cn->len = sizeof(struct w1_netlink_msg);
414*4882a593Smuzhiyun 	msg = (struct w1_netlink_msg *)cn->data;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	msg->type = W1_LIST_MASTERS;
417*4882a593Smuzhiyun 	msg->status = 0;
418*4882a593Smuzhiyun 	msg->len = 0;
419*4882a593Smuzhiyun 	id = (u32 *)msg->data;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	mutex_lock(&w1_mlock);
422*4882a593Smuzhiyun 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
423*4882a593Smuzhiyun 		if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
424*4882a593Smuzhiyun 			cn_netlink_send(cn, portid, 0, GFP_KERNEL);
425*4882a593Smuzhiyun 			cn->len = sizeof(struct w1_netlink_msg);
426*4882a593Smuzhiyun 			msg->len = 0;
427*4882a593Smuzhiyun 			id = (u32 *)msg->data;
428*4882a593Smuzhiyun 		}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 		*id = dev->id;
431*4882a593Smuzhiyun 		msg->len += sizeof(*id);
432*4882a593Smuzhiyun 		cn->len += sizeof(*id);
433*4882a593Smuzhiyun 		id++;
434*4882a593Smuzhiyun 	}
435*4882a593Smuzhiyun 	cn_netlink_send(cn, portid, 0, GFP_KERNEL);
436*4882a593Smuzhiyun 	mutex_unlock(&w1_mlock);
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	kfree(cn);
439*4882a593Smuzhiyun 	return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun 
w1_process_cb(struct w1_master * dev,struct w1_async_cmd * async_cmd)442*4882a593Smuzhiyun static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	struct w1_cb_node *node = container_of(async_cmd, struct w1_cb_node,
445*4882a593Smuzhiyun 		async);
446*4882a593Smuzhiyun 	u16 mlen = node->msg->len;
447*4882a593Smuzhiyun 	u16 len;
448*4882a593Smuzhiyun 	int err = 0;
449*4882a593Smuzhiyun 	struct w1_slave *sl = node->sl;
450*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)node->msg->data;
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	mutex_lock(&dev->bus_mutex);
453*4882a593Smuzhiyun 	dev->priv = node->block;
454*4882a593Smuzhiyun 	if (sl && w1_reset_select_slave(sl))
455*4882a593Smuzhiyun 		err = -ENODEV;
456*4882a593Smuzhiyun 	node->block->cur_msg = node->msg;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	while (mlen && !err) {
459*4882a593Smuzhiyun 		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
460*4882a593Smuzhiyun 			err = -E2BIG;
461*4882a593Smuzhiyun 			break;
462*4882a593Smuzhiyun 		}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 		if (sl)
465*4882a593Smuzhiyun 			err = w1_process_command_slave(sl, cmd);
466*4882a593Smuzhiyun 		else
467*4882a593Smuzhiyun 			err = w1_process_command_master(dev, cmd);
468*4882a593Smuzhiyun 		w1_netlink_check_send(node->block);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		w1_netlink_queue_status(node->block, node->msg, cmd, err);
471*4882a593Smuzhiyun 		err = 0;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 		len = sizeof(*cmd) + cmd->len;
474*4882a593Smuzhiyun 		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
475*4882a593Smuzhiyun 		mlen -= len;
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	if (!cmd || err)
479*4882a593Smuzhiyun 		w1_netlink_queue_status(node->block, node->msg, cmd, err);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	/* ref taken in w1_search_slave or w1_search_master_id when building
482*4882a593Smuzhiyun 	 * the block
483*4882a593Smuzhiyun 	 */
484*4882a593Smuzhiyun 	if (sl)
485*4882a593Smuzhiyun 		w1_unref_slave(sl);
486*4882a593Smuzhiyun 	else
487*4882a593Smuzhiyun 		atomic_dec(&dev->refcnt);
488*4882a593Smuzhiyun 	dev->priv = NULL;
489*4882a593Smuzhiyun 	mutex_unlock(&dev->bus_mutex);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	mutex_lock(&dev->list_mutex);
492*4882a593Smuzhiyun 	list_del(&async_cmd->async_entry);
493*4882a593Smuzhiyun 	mutex_unlock(&dev->list_mutex);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	w1_unref_block(node->block);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
w1_list_count_cmds(struct w1_netlink_msg * msg,int * cmd_count,u16 * slave_len)498*4882a593Smuzhiyun static void w1_list_count_cmds(struct w1_netlink_msg *msg, int *cmd_count,
499*4882a593Smuzhiyun 	u16 *slave_len)
500*4882a593Smuzhiyun {
501*4882a593Smuzhiyun 	struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)msg->data;
502*4882a593Smuzhiyun 	u16 mlen = msg->len;
503*4882a593Smuzhiyun 	u16 len;
504*4882a593Smuzhiyun 	int slave_list = 0;
505*4882a593Smuzhiyun 	while (mlen) {
506*4882a593Smuzhiyun 		if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen)
507*4882a593Smuzhiyun 			break;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		switch (cmd->cmd) {
510*4882a593Smuzhiyun 		case W1_CMD_SEARCH:
511*4882a593Smuzhiyun 		case W1_CMD_ALARM_SEARCH:
512*4882a593Smuzhiyun 		case W1_CMD_LIST_SLAVES:
513*4882a593Smuzhiyun 			++slave_list;
514*4882a593Smuzhiyun 		}
515*4882a593Smuzhiyun 		++*cmd_count;
516*4882a593Smuzhiyun 		len = sizeof(*cmd) + cmd->len;
517*4882a593Smuzhiyun 		cmd = (struct w1_netlink_cmd *)((u8 *)cmd + len);
518*4882a593Smuzhiyun 		mlen -= len;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	if (slave_list) {
522*4882a593Smuzhiyun 		struct w1_master *dev = w1_search_master_id(msg->id.mst.id);
523*4882a593Smuzhiyun 		if (dev) {
524*4882a593Smuzhiyun 			/* Bytes, and likely an overstimate, and if it isn't
525*4882a593Smuzhiyun 			 * the results can still be split between packets.
526*4882a593Smuzhiyun 			 */
527*4882a593Smuzhiyun 			*slave_len += sizeof(struct w1_reg_num) * slave_list *
528*4882a593Smuzhiyun 				(dev->slave_count + dev->max_slave_count);
529*4882a593Smuzhiyun 			/* search incremented it */
530*4882a593Smuzhiyun 			atomic_dec(&dev->refcnt);
531*4882a593Smuzhiyun 		}
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
w1_cn_callback(struct cn_msg * cn,struct netlink_skb_parms * nsp)535*4882a593Smuzhiyun static void w1_cn_callback(struct cn_msg *cn, struct netlink_skb_parms *nsp)
536*4882a593Smuzhiyun {
537*4882a593Smuzhiyun 	struct w1_netlink_msg *msg = (struct w1_netlink_msg *)(cn + 1);
538*4882a593Smuzhiyun 	struct w1_slave *sl;
539*4882a593Smuzhiyun 	struct w1_master *dev;
540*4882a593Smuzhiyun 	u16 msg_len;
541*4882a593Smuzhiyun 	u16 slave_len = 0;
542*4882a593Smuzhiyun 	int err = 0;
543*4882a593Smuzhiyun 	struct w1_cb_block *block = NULL;
544*4882a593Smuzhiyun 	struct w1_cb_node *node = NULL;
545*4882a593Smuzhiyun 	int node_count = 0;
546*4882a593Smuzhiyun 	int cmd_count = 0;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	/* If any unknown flag is set let the application know, that way
549*4882a593Smuzhiyun 	 * applications can detect the absence of features in kernels that
550*4882a593Smuzhiyun 	 * don't know about them.  http://lwn.net/Articles/587527/
551*4882a593Smuzhiyun 	 */
552*4882a593Smuzhiyun 	if (cn->flags & ~(W1_CN_BUNDLE)) {
553*4882a593Smuzhiyun 		w1_netlink_send_error(cn, msg, nsp->portid, -EINVAL);
554*4882a593Smuzhiyun 		return;
555*4882a593Smuzhiyun 	}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	/* Count the number of master or slave commands there are to allocate
558*4882a593Smuzhiyun 	 * space for one cb_node each.
559*4882a593Smuzhiyun 	 */
560*4882a593Smuzhiyun 	msg_len = cn->len;
561*4882a593Smuzhiyun 	while (msg_len && !err) {
562*4882a593Smuzhiyun 		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
563*4882a593Smuzhiyun 			err = -E2BIG;
564*4882a593Smuzhiyun 			break;
565*4882a593Smuzhiyun 		}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 		/* count messages for nodes and allocate any additional space
568*4882a593Smuzhiyun 		 * required for slave lists
569*4882a593Smuzhiyun 		 */
570*4882a593Smuzhiyun 		if (msg->type == W1_MASTER_CMD || msg->type == W1_SLAVE_CMD) {
571*4882a593Smuzhiyun 			++node_count;
572*4882a593Smuzhiyun 			w1_list_count_cmds(msg, &cmd_count, &slave_len);
573*4882a593Smuzhiyun 		}
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
576*4882a593Smuzhiyun 		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
577*4882a593Smuzhiyun 			sizeof(struct w1_netlink_msg) + msg->len);
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun 	msg = (struct w1_netlink_msg *)(cn + 1);
580*4882a593Smuzhiyun 	if (node_count) {
581*4882a593Smuzhiyun 		int size;
582*4882a593Smuzhiyun 		int reply_size = sizeof(*cn) + cn->len + slave_len;
583*4882a593Smuzhiyun 		if (cn->flags & W1_CN_BUNDLE) {
584*4882a593Smuzhiyun 			/* bundling duplicats some of the messages */
585*4882a593Smuzhiyun 			reply_size += 2 * cmd_count * (sizeof(struct cn_msg) +
586*4882a593Smuzhiyun 				sizeof(struct w1_netlink_msg) +
587*4882a593Smuzhiyun 				sizeof(struct w1_netlink_cmd));
588*4882a593Smuzhiyun 		}
589*4882a593Smuzhiyun 		reply_size = min(CONNECTOR_MAX_MSG_SIZE, reply_size);
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 		/* allocate space for the block, a copy of the original message,
592*4882a593Smuzhiyun 		 * one node per cmd to point into the original message,
593*4882a593Smuzhiyun 		 * space for replies which is the original message size plus
594*4882a593Smuzhiyun 		 * space for any list slave data and status messages
595*4882a593Smuzhiyun 		 * cn->len doesn't include itself which is part of the block
596*4882a593Smuzhiyun 		 * */
597*4882a593Smuzhiyun 		size =  /* block + original message */
598*4882a593Smuzhiyun 			sizeof(struct w1_cb_block) + sizeof(*cn) + cn->len +
599*4882a593Smuzhiyun 			/* space for nodes */
600*4882a593Smuzhiyun 			node_count * sizeof(struct w1_cb_node) +
601*4882a593Smuzhiyun 			/* replies */
602*4882a593Smuzhiyun 			sizeof(struct cn_msg) + reply_size;
603*4882a593Smuzhiyun 		block = kzalloc(size, GFP_KERNEL);
604*4882a593Smuzhiyun 		if (!block) {
605*4882a593Smuzhiyun 			/* if the system is already out of memory,
606*4882a593Smuzhiyun 			 * (A) will this work, and (B) would it be better
607*4882a593Smuzhiyun 			 * to not try?
608*4882a593Smuzhiyun 			 */
609*4882a593Smuzhiyun 			w1_netlink_send_error(cn, msg, nsp->portid, -ENOMEM);
610*4882a593Smuzhiyun 			return;
611*4882a593Smuzhiyun 		}
612*4882a593Smuzhiyun 		atomic_set(&block->refcnt, 1);
613*4882a593Smuzhiyun 		block->portid = nsp->portid;
614*4882a593Smuzhiyun 		memcpy(&block->request_cn, cn, sizeof(*cn) + cn->len);
615*4882a593Smuzhiyun 		node = (struct w1_cb_node *)(block->request_cn.data + cn->len);
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 		/* Sneeky, when not bundling, reply_size is the allocated space
618*4882a593Smuzhiyun 		 * required for the reply, cn_msg isn't part of maxlen so
619*4882a593Smuzhiyun 		 * it should be reply_size - sizeof(struct cn_msg), however
620*4882a593Smuzhiyun 		 * when checking if there is enough space, w1_reply_make_space
621*4882a593Smuzhiyun 		 * is called with the full message size including cn_msg,
622*4882a593Smuzhiyun 		 * because it isn't known at that time if an additional cn_msg
623*4882a593Smuzhiyun 		 * will need to be allocated.  So an extra cn_msg is added
624*4882a593Smuzhiyun 		 * above in "size".
625*4882a593Smuzhiyun 		 */
626*4882a593Smuzhiyun 		block->maxlen = reply_size;
627*4882a593Smuzhiyun 		block->first_cn = (struct cn_msg *)(node + node_count);
628*4882a593Smuzhiyun 		memset(block->first_cn, 0, sizeof(*block->first_cn));
629*4882a593Smuzhiyun 	}
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	msg_len = cn->len;
632*4882a593Smuzhiyun 	while (msg_len && !err) {
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		dev = NULL;
635*4882a593Smuzhiyun 		sl = NULL;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 		if (msg->len + sizeof(struct w1_netlink_msg) > msg_len) {
638*4882a593Smuzhiyun 			err = -E2BIG;
639*4882a593Smuzhiyun 			break;
640*4882a593Smuzhiyun 		}
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 		/* execute on this thread, no need to process later */
643*4882a593Smuzhiyun 		if (msg->type == W1_LIST_MASTERS) {
644*4882a593Smuzhiyun 			err = w1_process_command_root(cn, nsp->portid);
645*4882a593Smuzhiyun 			goto out_cont;
646*4882a593Smuzhiyun 		}
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 		/* All following message types require additional data,
649*4882a593Smuzhiyun 		 * check here before references are taken.
650*4882a593Smuzhiyun 		 */
651*4882a593Smuzhiyun 		if (!msg->len) {
652*4882a593Smuzhiyun 			err = -EPROTO;
653*4882a593Smuzhiyun 			goto out_cont;
654*4882a593Smuzhiyun 		}
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 		/* both search calls take references */
657*4882a593Smuzhiyun 		if (msg->type == W1_MASTER_CMD) {
658*4882a593Smuzhiyun 			dev = w1_search_master_id(msg->id.mst.id);
659*4882a593Smuzhiyun 		} else if (msg->type == W1_SLAVE_CMD) {
660*4882a593Smuzhiyun 			sl = w1_search_slave((struct w1_reg_num *)msg->id.id);
661*4882a593Smuzhiyun 			if (sl)
662*4882a593Smuzhiyun 				dev = sl->master;
663*4882a593Smuzhiyun 		} else {
664*4882a593Smuzhiyun 			pr_notice("%s: cn: %x.%x, wrong type: %u, len: %u.\n",
665*4882a593Smuzhiyun 				__func__, cn->id.idx, cn->id.val,
666*4882a593Smuzhiyun 				msg->type, msg->len);
667*4882a593Smuzhiyun 			err = -EPROTO;
668*4882a593Smuzhiyun 			goto out_cont;
669*4882a593Smuzhiyun 		}
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 		if (!dev) {
672*4882a593Smuzhiyun 			err = -ENODEV;
673*4882a593Smuzhiyun 			goto out_cont;
674*4882a593Smuzhiyun 		}
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 		err = 0;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 		atomic_inc(&block->refcnt);
679*4882a593Smuzhiyun 		node->async.cb = w1_process_cb;
680*4882a593Smuzhiyun 		node->block = block;
681*4882a593Smuzhiyun 		node->msg = (struct w1_netlink_msg *)((u8 *)&block->request_cn +
682*4882a593Smuzhiyun 			(size_t)((u8 *)msg - (u8 *)cn));
683*4882a593Smuzhiyun 		node->sl = sl;
684*4882a593Smuzhiyun 		node->dev = dev;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 		mutex_lock(&dev->list_mutex);
687*4882a593Smuzhiyun 		list_add_tail(&node->async.async_entry, &dev->async_list);
688*4882a593Smuzhiyun 		wake_up_process(dev->thread);
689*4882a593Smuzhiyun 		mutex_unlock(&dev->list_mutex);
690*4882a593Smuzhiyun 		++node;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun out_cont:
693*4882a593Smuzhiyun 		/* Can't queue because that modifies block and another
694*4882a593Smuzhiyun 		 * thread could be processing the messages by now and
695*4882a593Smuzhiyun 		 * there isn't a lock, send directly.
696*4882a593Smuzhiyun 		 */
697*4882a593Smuzhiyun 		if (err)
698*4882a593Smuzhiyun 			w1_netlink_send_error(cn, msg, nsp->portid, err);
699*4882a593Smuzhiyun 		msg_len -= sizeof(struct w1_netlink_msg) + msg->len;
700*4882a593Smuzhiyun 		msg = (struct w1_netlink_msg *)(((u8 *)msg) +
701*4882a593Smuzhiyun 			sizeof(struct w1_netlink_msg) + msg->len);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 		/*
704*4882a593Smuzhiyun 		 * Let's allow requests for nonexisting devices.
705*4882a593Smuzhiyun 		 */
706*4882a593Smuzhiyun 		if (err == -ENODEV)
707*4882a593Smuzhiyun 			err = 0;
708*4882a593Smuzhiyun 	}
709*4882a593Smuzhiyun 	if (block)
710*4882a593Smuzhiyun 		w1_unref_block(block);
711*4882a593Smuzhiyun }
712*4882a593Smuzhiyun 
w1_init_netlink(void)713*4882a593Smuzhiyun int w1_init_netlink(void)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
w1_fini_netlink(void)720*4882a593Smuzhiyun void w1_fini_netlink(void)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	cn_del_callback(&w1_id);
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun #else
w1_netlink_send(struct w1_master * dev,struct w1_netlink_msg * cn)727*4882a593Smuzhiyun void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *cn)
728*4882a593Smuzhiyun {
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
w1_init_netlink(void)731*4882a593Smuzhiyun int w1_init_netlink(void)
732*4882a593Smuzhiyun {
733*4882a593Smuzhiyun 	return 0;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
w1_fini_netlink(void)736*4882a593Smuzhiyun void w1_fini_netlink(void)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun #endif
740