Commit 3b8384070ea1dc358f6da6233b3b6c0926ae1bf4

Authored by Evgeniy Polyakov
Committed by Linus Torvalds
1 parent 9be62e0b2f

w1: list slaves commands

Initiates search (or alarm search) and returns all found devices to
userspace.  Found devices are not added into the system (i.e.  they are
not attached to family devices or bus masters), it will be done via (if
was not done yet) usual timed searching.

Signed-off-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 85 additions and 17 deletions Inline Diff

drivers/w1/w1_netlink.c
1 /* 1 /*
2 * w1_netlink.c 2 * w1_netlink.c
3 * 3 *
4 * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru> 4 * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
5 * 5 *
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or 9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. 10 * (at your option) any later version.
11 * 11 *
12 * This program is distributed in the hope that it will be useful, 12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details. 15 * GNU General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU General Public License 17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software 18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */ 20 */
21 21
22 #include <linux/skbuff.h> 22 #include <linux/skbuff.h>
23 #include <linux/netlink.h> 23 #include <linux/netlink.h>
24 #include <linux/connector.h> 24 #include <linux/connector.h>
25 25
26 #include "w1.h" 26 #include "w1.h"
27 #include "w1_log.h" 27 #include "w1_log.h"
28 #include "w1_netlink.h" 28 #include "w1_netlink.h"
29 29
30 #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE))) 30 #if defined(CONFIG_W1_CON) && (defined(CONFIG_CONNECTOR) || (defined(CONFIG_CONNECTOR_MODULE) && defined(CONFIG_W1_MODULE)))
31 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) 31 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
32 { 32 {
33 char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)]; 33 char buf[sizeof(struct cn_msg) + sizeof(struct w1_netlink_msg)];
34 struct cn_msg *m = (struct cn_msg *)buf; 34 struct cn_msg *m = (struct cn_msg *)buf;
35 struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1); 35 struct w1_netlink_msg *w = (struct w1_netlink_msg *)(m+1);
36 36
37 memset(buf, 0, sizeof(buf)); 37 memset(buf, 0, sizeof(buf));
38 38
39 m->id.idx = CN_W1_IDX; 39 m->id.idx = CN_W1_IDX;
40 m->id.val = CN_W1_VAL; 40 m->id.val = CN_W1_VAL;
41 41
42 m->seq = dev->seq++; 42 m->seq = dev->seq++;
43 m->len = sizeof(struct w1_netlink_msg); 43 m->len = sizeof(struct w1_netlink_msg);
44 44
45 memcpy(w, msg, sizeof(struct w1_netlink_msg)); 45 memcpy(w, msg, sizeof(struct w1_netlink_msg));
46 46
47 cn_netlink_send(m, 0, GFP_KERNEL); 47 cn_netlink_send(m, 0, GFP_KERNEL);
48 } 48 }
49 49
50 static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, 50 static void w1_send_slave(struct w1_master *dev, u64 rn)
51 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
52 { 51 {
53 dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", 52 struct cn_msg *msg = dev->priv;
54 __func__, dev->name, cmd->cmd, cmd->len); 53 struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
54 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
55 int avail;
55 56
56 if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) 57 avail = dev->priv_size - cmd->len;
57 return -EINVAL;
58 58
59 w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); 59 if (avail > 8) {
60 u64 *data = (void *)(cmd + 1) + cmd->len;
61
62 *data = rn;
63 cmd->len += 8;
64 hdr->len += 8;
65 msg->len += 8;
66 return;
67 }
68
69 msg->ack++;
70 cn_netlink_send(msg, 0, GFP_KERNEL);
71
72 msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
73 hdr->len = sizeof(struct w1_netlink_cmd);
74 cmd->len = 0;
75 }
76
77 static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg,
78 unsigned int avail)
79 {
80 struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1);
81 struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1);
82 int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH;
83
84 dev->priv = msg;
85 dev->priv_size = avail;
86
87 w1_search_devices(dev, search_type, w1_send_slave);
88
89 msg->ack = 0;
90 cn_netlink_send(msg, 0, GFP_KERNEL);
91
92 dev->priv = NULL;
93 dev->priv_size = 0;
94
60 return 0; 95 return 0;
61 } 96 }
62 97
98 static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg,
99 struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd)
100 {
101 int err = -EINVAL;
102 struct cn_msg *msg;
103 struct w1_netlink_msg *hdr;
104 struct w1_netlink_cmd *cmd;
105
106 msg = kzalloc(PAGE_SIZE, GFP_KERNEL);
107 if (!msg)
108 return -ENOMEM;
109
110 msg->id = req_msg->id;
111 msg->seq = req_msg->seq;
112 msg->ack = 0;
113 msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd);
114
115 hdr = (struct w1_netlink_msg *)(msg + 1);
116 cmd = (struct w1_netlink_cmd *)(hdr + 1);
117
118 hdr->type = W1_MASTER_CMD;
119 hdr->id = req_hdr->id;
120 hdr->len = sizeof(struct w1_netlink_cmd);
121
122 cmd->cmd = req_cmd->cmd;
123 cmd->len = 0;
124
125 switch (cmd->cmd) {
126 case W1_CMD_SEARCH:
127 case W1_CMD_ALARM_SEARCH:
128 err = w1_process_search_command(dev, msg,
129 PAGE_SIZE - msg->len - sizeof(struct cn_msg));
130 break;
131 default:
132 cmd->res = EINVAL;
133 cn_netlink_send(msg, 0, GFP_KERNEL);
134 break;
135 }
136
137 kfree(msg);
138 return err;
139 }
140
63 static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, 141 static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg,
64 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) 142 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
65 { 143 {
66 void *data; 144 void *data;
67 struct w1_netlink_msg *h; 145 struct w1_netlink_msg *h;
68 struct w1_netlink_cmd *c; 146 struct w1_netlink_cmd *c;
69 struct cn_msg *cm; 147 struct cn_msg *cm;
70 int err; 148 int err;
71 149
72 data = kzalloc(sizeof(struct cn_msg) + 150 data = kzalloc(sizeof(struct cn_msg) +
73 sizeof(struct w1_netlink_msg) + 151 sizeof(struct w1_netlink_msg) +
74 sizeof(struct w1_netlink_cmd) + 152 sizeof(struct w1_netlink_cmd) +
75 cmd->len, GFP_KERNEL); 153 cmd->len, GFP_KERNEL);
76 if (!data) 154 if (!data)
77 return -ENOMEM; 155 return -ENOMEM;
78 156
79 cm = (struct cn_msg *)(data); 157 cm = (struct cn_msg *)(data);
80 h = (struct w1_netlink_msg *)(cm + 1); 158 h = (struct w1_netlink_msg *)(cm + 1);
81 c = (struct w1_netlink_cmd *)(h + 1); 159 c = (struct w1_netlink_cmd *)(h + 1);
82 160
83 memcpy(cm, msg, sizeof(struct cn_msg)); 161 memcpy(cm, msg, sizeof(struct cn_msg));
84 memcpy(h, hdr, sizeof(struct w1_netlink_msg)); 162 memcpy(h, hdr, sizeof(struct w1_netlink_msg));
85 memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); 163 memcpy(c, cmd, sizeof(struct w1_netlink_cmd));
86 164
87 cm->ack = msg->seq+1; 165 cm->ack = msg->seq+1;
88 cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; 166 cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len;
89 167
90 h->len = sizeof(struct w1_netlink_cmd) + cmd->len; 168 h->len = sizeof(struct w1_netlink_cmd) + cmd->len;
91 169
92 memcpy(c->data, cmd->data, c->len); 170 memcpy(c->data, cmd->data, c->len);
93 171
94 err = cn_netlink_send(cm, 0, GFP_KERNEL); 172 err = cn_netlink_send(cm, 0, GFP_KERNEL);
95 173
96 kfree(data); 174 kfree(data);
97 175
98 return err; 176 return err;
99 } 177 }
100 178
101 static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, 179 static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg,
102 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) 180 struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd)
103 { 181 {
104 int err = 0; 182 int err = 0;
105 183
106 dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", 184 dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n",
107 __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, 185 __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc,
108 cmd->cmd, cmd->len); 186 cmd->cmd, cmd->len);
109 187
110 switch (cmd->cmd) { 188 switch (cmd->cmd) {
111 case W1_CMD_TOUCH: 189 case W1_CMD_TOUCH:
112 w1_touch_block(sl->master, cmd->data, cmd->len); 190 w1_touch_block(sl->master, cmd->data, cmd->len);
113 w1_send_read_reply(sl, msg, hdr, cmd); 191 w1_send_read_reply(sl, msg, hdr, cmd);
114 break; 192 break;
115 case W1_CMD_READ: 193 case W1_CMD_READ:
116 w1_read_block(sl->master, cmd->data, cmd->len); 194 w1_read_block(sl->master, cmd->data, cmd->len);
117 w1_send_read_reply(sl, msg, hdr, cmd); 195 w1_send_read_reply(sl, msg, hdr, cmd);
118 break; 196 break;
119 case W1_CMD_WRITE: 197 case W1_CMD_WRITE:
120 w1_write_block(sl->master, cmd->data, cmd->len); 198 w1_write_block(sl->master, cmd->data, cmd->len);
121 break; 199 break;
122 case W1_CMD_SEARCH:
123 case W1_CMD_ALARM_SEARCH:
124 w1_search_process(sl->master,
125 (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH);
126 break;
127 default: 200 default:
128 err = -1; 201 err = -1;
129 break; 202 break;
130 } 203 }
131 204
132 return err; 205 return err;
133 } 206 }
134 207
135 static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) 208 static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd)
136 { 209 {
137 struct w1_master *m; 210 struct w1_master *m;
138 struct cn_msg *cn; 211 struct cn_msg *cn;
139 struct w1_netlink_msg *w; 212 struct w1_netlink_msg *w;
140 u32 *id; 213 u32 *id;
141 214
142 if (mcmd->type != W1_LIST_MASTERS) { 215 if (mcmd->type != W1_LIST_MASTERS) {
143 printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", 216 printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n",
144 __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); 217 __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len);
145 return -EPROTO; 218 return -EPROTO;
146 } 219 }
147 220
148 cn = kmalloc(PAGE_SIZE, GFP_KERNEL); 221 cn = kmalloc(PAGE_SIZE, GFP_KERNEL);
149 if (!cn) 222 if (!cn)
150 return -ENOMEM; 223 return -ENOMEM;
151 224
152 cn->id.idx = CN_W1_IDX; 225 cn->id.idx = CN_W1_IDX;
153 cn->id.val = CN_W1_VAL; 226 cn->id.val = CN_W1_VAL;
154 227
155 cn->seq = msg->seq; 228 cn->seq = msg->seq;
156 cn->ack = 1; 229 cn->ack = 1;
157 cn->len = sizeof(struct w1_netlink_msg); 230 cn->len = sizeof(struct w1_netlink_msg);
158 w = (struct w1_netlink_msg *)(cn + 1); 231 w = (struct w1_netlink_msg *)(cn + 1);
159 232
160 w->type = W1_LIST_MASTERS; 233 w->type = W1_LIST_MASTERS;
161 w->reserved = 0; 234 w->reserved = 0;
162 w->len = 0; 235 w->len = 0;
163 id = (u32 *)(w + 1); 236 id = (u32 *)(w + 1);
164 237
165 mutex_lock(&w1_mlock); 238 mutex_lock(&w1_mlock);
166 list_for_each_entry(m, &w1_masters, w1_master_entry) { 239 list_for_each_entry(m, &w1_masters, w1_master_entry) {
167 if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { 240 if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) {
168 cn_netlink_send(cn, 0, GFP_KERNEL); 241 cn_netlink_send(cn, 0, GFP_KERNEL);
169 cn->ack++; 242 cn->ack++;
170 cn->len = sizeof(struct w1_netlink_msg); 243 cn->len = sizeof(struct w1_netlink_msg);
171 w->len = 0; 244 w->len = 0;
172 id = (u32 *)(w + 1); 245 id = (u32 *)(w + 1);
173 } 246 }
174 247
175 *id = m->id; 248 *id = m->id;
176 w->len += sizeof(*id); 249 w->len += sizeof(*id);
177 cn->len += sizeof(*id); 250 cn->len += sizeof(*id);
178 id++; 251 id++;
179 } 252 }
180 cn->ack = 0; 253 cn->ack = 0;
181 cn_netlink_send(cn, 0, GFP_KERNEL); 254 cn_netlink_send(cn, 0, GFP_KERNEL);
182 mutex_unlock(&w1_mlock); 255 mutex_unlock(&w1_mlock);
183 256
184 kfree(cn); 257 kfree(cn);
185 return 0; 258 return 0;
186 } 259 }
187 260
188 static void w1_cn_callback(void *data) 261 static void w1_cn_callback(void *data)
189 { 262 {
190 struct cn_msg *msg = data; 263 struct cn_msg *msg = data;
191 struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); 264 struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1);
192 struct w1_netlink_cmd *cmd; 265 struct w1_netlink_cmd *cmd;
193 struct w1_slave *sl; 266 struct w1_slave *sl;
194 struct w1_master *dev; 267 struct w1_master *dev;
195 int err = 0; 268 int err = 0;
196 269
197 while (msg->len && !err) { 270 while (msg->len && !err) {
198 struct w1_reg_num id; 271 struct w1_reg_num id;
199 u16 mlen = m->len; 272 u16 mlen = m->len;
200 u8 *cmd_data = m->data; 273 u8 *cmd_data = m->data;
201 274
202 dev = NULL; 275 dev = NULL;
203 sl = NULL; 276 sl = NULL;
204 277
205 memcpy(&id, m->id.id, sizeof(id)); 278 memcpy(&id, m->id.id, sizeof(id));
206 #if 0 279 #if 0
207 printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", 280 printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n",
208 __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); 281 __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len);
209 #endif 282 #endif
210 if (m->len + sizeof(struct w1_netlink_msg) > msg->len) { 283 if (m->len + sizeof(struct w1_netlink_msg) > msg->len) {
211 err = -E2BIG; 284 err = -E2BIG;
212 break; 285 break;
213 } 286 }
214 287
215 if (m->type == W1_MASTER_CMD) { 288 if (m->type == W1_MASTER_CMD) {
216 dev = w1_search_master_id(m->id.mst.id); 289 dev = w1_search_master_id(m->id.mst.id);
217 } else if (m->type == W1_SLAVE_CMD) { 290 } else if (m->type == W1_SLAVE_CMD) {
218 sl = w1_search_slave(&id); 291 sl = w1_search_slave(&id);
219 if (sl) 292 if (sl)
220 dev = sl->master; 293 dev = sl->master;
221 } else { 294 } else {
222 err = w1_process_command_root(msg, m); 295 err = w1_process_command_root(msg, m);
223 goto out_cont; 296 goto out_cont;
224 } 297 }
225 298
226 if (!dev) { 299 if (!dev) {
227 err = -ENODEV; 300 err = -ENODEV;
228 goto out_cont; 301 goto out_cont;
229 } 302 }
230 303
231 err = 0; 304 err = 0;
232 if (!mlen) 305 if (!mlen)
233 goto out_cont; 306 goto out_cont;
234 307
235 mutex_lock(&dev->mutex); 308 mutex_lock(&dev->mutex);
236 309
237 if (sl && w1_reset_select_slave(sl)) { 310 if (sl && w1_reset_select_slave(sl)) {
238 err = -ENODEV; 311 err = -ENODEV;
239 goto out_up; 312 goto out_up;
240 } 313 }
241 314
242 while (mlen) { 315 while (mlen) {
243 cmd = (struct w1_netlink_cmd *)cmd_data; 316 cmd = (struct w1_netlink_cmd *)cmd_data;
244 317
245 if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) { 318 if (cmd->len + sizeof(struct w1_netlink_cmd) > mlen) {
246 err = -E2BIG; 319 err = -E2BIG;
247 break; 320 break;
248 } 321 }
249 322
250 if (sl) 323 if (sl)
251 w1_process_command_slave(sl, msg, m, cmd); 324 w1_process_command_slave(sl, msg, m, cmd);
252 else 325 else
253 w1_process_command_master(dev, msg, m, cmd); 326 w1_process_command_master(dev, msg, m, cmd);
254 327
255 cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); 328 cmd_data += cmd->len + sizeof(struct w1_netlink_cmd);
256 mlen -= cmd->len + sizeof(struct w1_netlink_cmd); 329 mlen -= cmd->len + sizeof(struct w1_netlink_cmd);
257 } 330 }
258 out_up: 331 out_up:
259 atomic_dec(&dev->refcnt); 332 atomic_dec(&dev->refcnt);
260 if (sl) 333 if (sl)
261 atomic_dec(&sl->refcnt); 334 atomic_dec(&sl->refcnt);
262 mutex_unlock(&dev->mutex); 335 mutex_unlock(&dev->mutex);
263 out_cont: 336 out_cont:
264 msg->len -= sizeof(struct w1_netlink_msg) + m->len; 337 msg->len -= sizeof(struct w1_netlink_msg) + m->len;
265 m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); 338 m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len);
266 339
267 /* 340 /*
268 * Let's allow requests for nonexisting devices. 341 * Let's allow requests for nonexisting devices.
269 */ 342 */
270 if (err == -ENODEV) 343 if (err == -ENODEV)
271 err = 0; 344 err = 0;
272 } 345 }
273 #if 0
274 if (err) {
275 printk("%s: malformed message. Dropping.\n", __func__);
276 }
277 #endif
278 } 346 }
279 347
280 int w1_init_netlink(void) 348 int w1_init_netlink(void)
281 { 349 {
282 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 350 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
283 351
284 return cn_add_callback(&w1_id, "w1", &w1_cn_callback); 352 return cn_add_callback(&w1_id, "w1", &w1_cn_callback);
285 } 353 }
286 354
287 void w1_fini_netlink(void) 355 void w1_fini_netlink(void)
288 { 356 {
289 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL}; 357 struct cb_id w1_id = {.idx = CN_W1_IDX, .val = CN_W1_VAL};
290 358
291 cn_del_callback(&w1_id); 359 cn_del_callback(&w1_id);
292 } 360 }
293 #else 361 #else
294 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) 362 void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg)
295 { 363 {