diff options
-rw-r--r-- | drivers/w1/w1_netlink.c | 56 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 1 |
2 files changed, 57 insertions, 0 deletions
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 65c5ebd0787..2e07b59b985 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -128,6 +128,59 @@ static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, return err; } +static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) +{ + struct w1_master *m; + struct cn_msg *cn; + struct w1_netlink_msg *w; + u32 *id; + + if (mcmd->type != W1_LIST_MASTERS) { + printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", + __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); + return -EPROTO; + } + + cn = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!cn) + return -ENOMEM; + + cn->id.idx = CN_W1_IDX; + cn->id.val = CN_W1_VAL; + + cn->seq = msg->seq; + cn->ack = 1; + cn->len = sizeof(struct w1_netlink_msg); + w = (struct w1_netlink_msg *)(cn + 1); + + w->type = W1_LIST_MASTERS; + w->reserved = 0; + w->len = 0; + id = (u32 *)(w + 1); + + mutex_lock(&w1_mlock); + list_for_each_entry(m, &w1_masters, w1_master_entry) { + if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { + cn_netlink_send(cn, 0, GFP_KERNEL); + cn->ack++; + cn->len = sizeof(struct w1_netlink_msg); + w->len = 0; + id = (u32 *)(w + 1); + } + + *id = m->id; + w->len += sizeof(*id); + cn->len += sizeof(*id); + id++; + } + cn->ack = 0; + cn_netlink_send(cn, 0, GFP_KERNEL); + mutex_unlock(&w1_mlock); + + kfree(cn); + return 0; +} + static void w1_cn_callback(void *data) { struct cn_msg *msg = data; @@ -164,6 +217,9 @@ static void w1_cn_callback(void *data) sl = w1_search_slave(&id); if (sl) dev = sl->master; + } else { + err = w1_process_command_root(msg, m); + goto out_cont; } if (!dev) { diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 56122b9e929..21913dfc0f3 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h @@ -34,6 +34,7 @@ enum w1_netlink_message_types { W1_MASTER_REMOVE, W1_MASTER_CMD, W1_SLAVE_CMD, + W1_LIST_MASTERS, }; struct w1_netlink_msg |