diff options
-rw-r--r-- | Documentation/w1/w1.netlink | 29 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 53 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 2 |
3 files changed, 76 insertions, 8 deletions
diff --git a/Documentation/w1/w1.netlink b/Documentation/w1/w1.netlink index 2756681b6ef5..804445f745ed 100644 --- a/Documentation/w1/w1.netlink +++ b/Documentation/w1/w1.netlink | |||
@@ -118,6 +118,35 @@ W1 reset command. | |||
118 | id is equal to the bus master id to use for searching] | 118 | id is equal to the bus master id to use for searching] |
119 | [w1_netlink_cmd cmd = W1_CMD_RESET] | 119 | [w1_netlink_cmd cmd = W1_CMD_RESET] |
120 | 120 | ||
121 | |||
122 | Command status replies. | ||
123 | ====================== | ||
124 | |||
125 | Each command (either root, master or slave with or without w1_netlink_cmd | ||
126 | structure) will be 'acked' by the w1 core. Format of the reply is the same | ||
127 | as request message except that length parameters do not account for data | ||
128 | requested by the user, i.e. read/write/touch IO requests will not contain | ||
129 | data, so w1_netlink_cmd.len will be 0, w1_netlink_msg.len will be size | ||
130 | of the w1_netlink_cmd structure and cn_msg.len will be equal to the sum | ||
131 | of the sizeof(struct w1_netlink_msg) and sizeof(struct w1_netlink_cmd). | ||
132 | If reply is generated for master or root command (which do not have | ||
133 | w1_netlink_cmd attached), reply will contain only cn_msg and w1_netlink_msg | ||
134 | structires. | ||
135 | |||
136 | w1_netlink_msg.status field will carry positive error value | ||
137 | (EINVAL for example) or zero in case of success. | ||
138 | |||
139 | All other fields in every structure will mirror the same parameters in the | ||
140 | request message (except lengths as described above). | ||
141 | |||
142 | Status reply is generated for every w1_netlink_cmd embedded in the | ||
143 | w1_netlink_msg, if there are no w1_netlink_cmd structures, | ||
144 | reply will be generated for the w1_netlink_msg. | ||
145 | |||
146 | All w1_netlink_cmd command structures are handled in every w1_netlink_msg, | ||
147 | even if there were errors, only length mismatch interrupts message processing. | ||
148 | |||
149 | |||
121 | Operation steps in w1 core when new command is received. | 150 | Operation steps in w1 core when new command is received. |
122 | ======================================================= | 151 | ======================================================= |
123 | 152 | ||
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index f978c7504004..fdf72851c574 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -152,7 +152,7 @@ static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, | |||
152 | w1_write_block(dev, cmd->data, cmd->len); | 152 | w1_write_block(dev, cmd->data, cmd->len); |
153 | break; | 153 | break; |
154 | default: | 154 | default: |
155 | err = -1; | 155 | err = -EINVAL; |
156 | break; | 156 | break; |
157 | } | 157 | } |
158 | 158 | ||
@@ -195,14 +195,13 @@ static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_m | |||
195 | case W1_CMD_READ: | 195 | case W1_CMD_READ: |
196 | case W1_CMD_WRITE: | 196 | case W1_CMD_WRITE: |
197 | case W1_CMD_TOUCH: | 197 | case W1_CMD_TOUCH: |
198 | err = w1_process_command_io(dev, msg, hdr, cmd); | 198 | err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); |
199 | break; | 199 | break; |
200 | case W1_CMD_RESET: | 200 | case W1_CMD_RESET: |
201 | err = w1_reset_bus(dev); | 201 | err = w1_reset_bus(dev); |
202 | break; | 202 | break; |
203 | default: | 203 | default: |
204 | cmd->res = EINVAL; | 204 | err = -EINVAL; |
205 | cn_netlink_send(msg, 0, GFP_KERNEL); | ||
206 | break; | 205 | break; |
207 | } | 206 | } |
208 | 207 | ||
@@ -246,7 +245,7 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
246 | w = (struct w1_netlink_msg *)(cn + 1); | 245 | w = (struct w1_netlink_msg *)(cn + 1); |
247 | 246 | ||
248 | w->type = W1_LIST_MASTERS; | 247 | w->type = W1_LIST_MASTERS; |
249 | w->reserved = 0; | 248 | w->status = 0; |
250 | w->len = 0; | 249 | w->len = 0; |
251 | id = (u32 *)(w + 1); | 250 | id = (u32 *)(w + 1); |
252 | 251 | ||
@@ -273,6 +272,40 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mc | |||
273 | return 0; | 272 | return 0; |
274 | } | 273 | } |
275 | 274 | ||
275 | static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, | ||
276 | struct w1_netlink_cmd *rcmd, int error) | ||
277 | { | ||
278 | struct cn_msg *cmsg; | ||
279 | struct w1_netlink_msg *msg; | ||
280 | struct w1_netlink_cmd *cmd; | ||
281 | |||
282 | cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); | ||
283 | if (!cmsg) | ||
284 | return -ENOMEM; | ||
285 | |||
286 | msg = (struct w1_netlink_msg *)(cmsg + 1); | ||
287 | cmd = (struct w1_netlink_cmd *)(msg + 1); | ||
288 | |||
289 | memcpy(cmsg, rcmsg, sizeof(*cmsg)); | ||
290 | cmsg->len = sizeof(*msg); | ||
291 | |||
292 | memcpy(msg, rmsg, sizeof(*msg)); | ||
293 | msg->len = 0; | ||
294 | msg->status = (short)-error; | ||
295 | |||
296 | if (rcmd) { | ||
297 | memcpy(cmd, rcmd, sizeof(*cmd)); | ||
298 | cmd->len = 0; | ||
299 | msg->len += sizeof(*cmd); | ||
300 | cmsg->len += sizeof(*cmd); | ||
301 | } | ||
302 | |||
303 | error = cn_netlink_send(cmsg, 0, GFP_KERNEL); | ||
304 | kfree(cmsg); | ||
305 | |||
306 | return error; | ||
307 | } | ||
308 | |||
276 | static void w1_cn_callback(void *data) | 309 | static void w1_cn_callback(void *data) |
277 | { | 310 | { |
278 | struct cn_msg *msg = data; | 311 | struct cn_msg *msg = data; |
@@ -289,6 +322,7 @@ static void w1_cn_callback(void *data) | |||
289 | 322 | ||
290 | dev = NULL; | 323 | dev = NULL; |
291 | sl = NULL; | 324 | sl = NULL; |
325 | cmd = NULL; | ||
292 | 326 | ||
293 | memcpy(&id, m->id.id, sizeof(id)); | 327 | memcpy(&id, m->id.id, sizeof(id)); |
294 | #if 0 | 328 | #if 0 |
@@ -336,9 +370,12 @@ static void w1_cn_callback(void *data) | |||
336 | } | 370 | } |
337 | 371 | ||
338 | if (sl) | 372 | if (sl) |
339 | w1_process_command_slave(sl, msg, m, cmd); | 373 | err = w1_process_command_slave(sl, msg, m, cmd); |
340 | else | 374 | else |
341 | w1_process_command_master(dev, msg, m, cmd); | 375 | err = w1_process_command_master(dev, msg, m, cmd); |
376 | |||
377 | w1_netlink_send_error(msg, m, cmd, err); | ||
378 | err = 0; | ||
342 | 379 | ||
343 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | 380 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); |
344 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | 381 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); |
@@ -349,6 +386,8 @@ out_up: | |||
349 | atomic_dec(&sl->refcnt); | 386 | atomic_dec(&sl->refcnt); |
350 | mutex_unlock(&dev->mutex); | 387 | mutex_unlock(&dev->mutex); |
351 | out_cont: | 388 | out_cont: |
389 | if (!cmd || err) | ||
390 | w1_netlink_send_error(msg, m, cmd, err); | ||
352 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | 391 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; |
353 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | 392 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); |
354 | 393 | ||
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 68a4ff46cb96..27e950f935b1 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -40,7 +40,7 @@ enum w1_netlink_message_types { | |||
40 | struct w1_netlink_msg | 40 | struct w1_netlink_msg |
41 | { | 41 | { |
42 | __u8 type; | 42 | __u8 type; |
43 | __u8 reserved; | 43 | __u8 status; |
44 | __u16 len; | 44 | __u16 len; |
45 | union { | 45 | union { |
46 | __u8 id[8]; | 46 | __u8 id[8]; |