114fbff6bSArnd Bergmann /* 214fbff6bSArnd Bergmann * cn_test.c 314fbff6bSArnd Bergmann * 414fbff6bSArnd Bergmann * 2004+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net> 514fbff6bSArnd Bergmann * All rights reserved. 614fbff6bSArnd Bergmann * 714fbff6bSArnd Bergmann * This program is free software; you can redistribute it and/or modify 814fbff6bSArnd Bergmann * it under the terms of the GNU General Public License as published by 914fbff6bSArnd Bergmann * the Free Software Foundation; either version 2 of the License, or 1014fbff6bSArnd Bergmann * (at your option) any later version. 1114fbff6bSArnd Bergmann * 1214fbff6bSArnd Bergmann * This program is distributed in the hope that it will be useful, 1314fbff6bSArnd Bergmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 1414fbff6bSArnd Bergmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1514fbff6bSArnd Bergmann * GNU General Public License for more details. 1614fbff6bSArnd Bergmann * 1714fbff6bSArnd Bergmann * You should have received a copy of the GNU General Public License 1814fbff6bSArnd Bergmann * along with this program; if not, write to the Free Software 1914fbff6bSArnd Bergmann * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2014fbff6bSArnd Bergmann */ 2114fbff6bSArnd Bergmann 2214fbff6bSArnd Bergmann #define pr_fmt(fmt) "cn_test: " fmt 2314fbff6bSArnd Bergmann 2414fbff6bSArnd Bergmann #include <linux/kernel.h> 2514fbff6bSArnd Bergmann #include <linux/module.h> 2614fbff6bSArnd Bergmann #include <linux/moduleparam.h> 2714fbff6bSArnd Bergmann #include <linux/skbuff.h> 2814fbff6bSArnd Bergmann #include <linux/slab.h> 2914fbff6bSArnd Bergmann #include <linux/timer.h> 3014fbff6bSArnd Bergmann 3114fbff6bSArnd Bergmann #include <linux/connector.h> 3214fbff6bSArnd Bergmann 3314fbff6bSArnd Bergmann static struct cb_id cn_test_id = { CN_NETLINK_USERS + 3, 0x456 }; 3414fbff6bSArnd Bergmann static char cn_test_name[] = "cn_test"; 3514fbff6bSArnd Bergmann static struct sock *nls; 3614fbff6bSArnd Bergmann static struct timer_list cn_test_timer; 3714fbff6bSArnd Bergmann 3814fbff6bSArnd Bergmann static void cn_test_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) 3914fbff6bSArnd Bergmann { 4014fbff6bSArnd Bergmann pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", 4114fbff6bSArnd Bergmann __func__, jiffies, msg->id.idx, msg->id.val, 4214fbff6bSArnd Bergmann msg->seq, msg->ack, msg->len, 4314fbff6bSArnd Bergmann msg->len ? (char *)msg->data : ""); 4414fbff6bSArnd Bergmann } 4514fbff6bSArnd Bergmann 4614fbff6bSArnd Bergmann /* 4714fbff6bSArnd Bergmann * Do not remove this function even if no one is using it as 4814fbff6bSArnd Bergmann * this is an example of how to get notifications about new 4914fbff6bSArnd Bergmann * connector user registration 5014fbff6bSArnd Bergmann */ 5114fbff6bSArnd Bergmann #if 0 5214fbff6bSArnd Bergmann static int cn_test_want_notify(void) 5314fbff6bSArnd Bergmann { 5414fbff6bSArnd Bergmann struct cn_ctl_msg *ctl; 5514fbff6bSArnd Bergmann struct cn_notify_req *req; 5614fbff6bSArnd Bergmann struct cn_msg *msg = NULL; 5714fbff6bSArnd Bergmann int size, size0; 5814fbff6bSArnd Bergmann struct sk_buff *skb; 5914fbff6bSArnd Bergmann struct nlmsghdr *nlh; 6014fbff6bSArnd Bergmann u32 group = 1; 6114fbff6bSArnd Bergmann 6214fbff6bSArnd Bergmann size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req); 6314fbff6bSArnd Bergmann 6414fbff6bSArnd Bergmann size = NLMSG_SPACE(size0); 6514fbff6bSArnd Bergmann 6614fbff6bSArnd Bergmann skb = alloc_skb(size, GFP_ATOMIC); 6714fbff6bSArnd Bergmann if (!skb) { 6814fbff6bSArnd Bergmann pr_err("failed to allocate new skb with size=%u\n", size); 6914fbff6bSArnd Bergmann return -ENOMEM; 7014fbff6bSArnd Bergmann } 7114fbff6bSArnd Bergmann 7214fbff6bSArnd Bergmann nlh = nlmsg_put(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh), 0); 7314fbff6bSArnd Bergmann if (!nlh) { 7414fbff6bSArnd Bergmann kfree_skb(skb); 7514fbff6bSArnd Bergmann return -EMSGSIZE; 7614fbff6bSArnd Bergmann } 7714fbff6bSArnd Bergmann 7814fbff6bSArnd Bergmann msg = nlmsg_data(nlh); 7914fbff6bSArnd Bergmann 8014fbff6bSArnd Bergmann memset(msg, 0, size0); 8114fbff6bSArnd Bergmann 8214fbff6bSArnd Bergmann msg->id.idx = -1; 8314fbff6bSArnd Bergmann msg->id.val = -1; 8414fbff6bSArnd Bergmann msg->seq = 0x123; 8514fbff6bSArnd Bergmann msg->ack = 0x345; 8614fbff6bSArnd Bergmann msg->len = size0 - sizeof(*msg); 8714fbff6bSArnd Bergmann 8814fbff6bSArnd Bergmann ctl = (struct cn_ctl_msg *)(msg + 1); 8914fbff6bSArnd Bergmann 9014fbff6bSArnd Bergmann ctl->idx_notify_num = 1; 9114fbff6bSArnd Bergmann ctl->val_notify_num = 2; 9214fbff6bSArnd Bergmann ctl->group = group; 9314fbff6bSArnd Bergmann ctl->len = msg->len - sizeof(*ctl); 9414fbff6bSArnd Bergmann 9514fbff6bSArnd Bergmann req = (struct cn_notify_req *)(ctl + 1); 9614fbff6bSArnd Bergmann 9714fbff6bSArnd Bergmann /* 9814fbff6bSArnd Bergmann * Idx. 9914fbff6bSArnd Bergmann */ 10014fbff6bSArnd Bergmann req->first = cn_test_id.idx; 10114fbff6bSArnd Bergmann req->range = 10; 10214fbff6bSArnd Bergmann 10314fbff6bSArnd Bergmann /* 10414fbff6bSArnd Bergmann * Val 0. 10514fbff6bSArnd Bergmann */ 10614fbff6bSArnd Bergmann req++; 10714fbff6bSArnd Bergmann req->first = cn_test_id.val; 10814fbff6bSArnd Bergmann req->range = 10; 10914fbff6bSArnd Bergmann 11014fbff6bSArnd Bergmann /* 11114fbff6bSArnd Bergmann * Val 1. 11214fbff6bSArnd Bergmann */ 11314fbff6bSArnd Bergmann req++; 11414fbff6bSArnd Bergmann req->first = cn_test_id.val + 20; 11514fbff6bSArnd Bergmann req->range = 10; 11614fbff6bSArnd Bergmann 11714fbff6bSArnd Bergmann NETLINK_CB(skb).dst_group = ctl->group; 11814fbff6bSArnd Bergmann //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC); 11914fbff6bSArnd Bergmann netlink_unicast(nls, skb, 0, 0); 12014fbff6bSArnd Bergmann 12114fbff6bSArnd Bergmann pr_info("request was sent: group=0x%x\n", ctl->group); 12214fbff6bSArnd Bergmann 12314fbff6bSArnd Bergmann return 0; 12414fbff6bSArnd Bergmann } 12514fbff6bSArnd Bergmann #endif 12614fbff6bSArnd Bergmann 12714fbff6bSArnd Bergmann static u32 cn_test_timer_counter; 128*0d694234SKees Cook static void cn_test_timer_func(struct timer_list *unused) 12914fbff6bSArnd Bergmann { 13014fbff6bSArnd Bergmann struct cn_msg *m; 13114fbff6bSArnd Bergmann char data[32]; 13214fbff6bSArnd Bergmann 133*0d694234SKees Cook pr_debug("%s: timer fired\n", __func__); 13414fbff6bSArnd Bergmann 13514fbff6bSArnd Bergmann m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); 13614fbff6bSArnd Bergmann if (m) { 13714fbff6bSArnd Bergmann 13814fbff6bSArnd Bergmann memcpy(&m->id, &cn_test_id, sizeof(m->id)); 13914fbff6bSArnd Bergmann m->seq = cn_test_timer_counter; 14014fbff6bSArnd Bergmann m->len = sizeof(data); 14114fbff6bSArnd Bergmann 14214fbff6bSArnd Bergmann m->len = 14314fbff6bSArnd Bergmann scnprintf(data, sizeof(data), "counter = %u", 14414fbff6bSArnd Bergmann cn_test_timer_counter) + 1; 14514fbff6bSArnd Bergmann 14614fbff6bSArnd Bergmann memcpy(m + 1, data, m->len); 14714fbff6bSArnd Bergmann 14814fbff6bSArnd Bergmann cn_netlink_send(m, 0, 0, GFP_ATOMIC); 14914fbff6bSArnd Bergmann kfree(m); 15014fbff6bSArnd Bergmann } 15114fbff6bSArnd Bergmann 15214fbff6bSArnd Bergmann cn_test_timer_counter++; 15314fbff6bSArnd Bergmann 15414fbff6bSArnd Bergmann mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); 15514fbff6bSArnd Bergmann } 15614fbff6bSArnd Bergmann 15714fbff6bSArnd Bergmann static int cn_test_init(void) 15814fbff6bSArnd Bergmann { 15914fbff6bSArnd Bergmann int err; 16014fbff6bSArnd Bergmann 16114fbff6bSArnd Bergmann err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback); 16214fbff6bSArnd Bergmann if (err) 16314fbff6bSArnd Bergmann goto err_out; 16414fbff6bSArnd Bergmann cn_test_id.val++; 16514fbff6bSArnd Bergmann err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback); 16614fbff6bSArnd Bergmann if (err) { 16714fbff6bSArnd Bergmann cn_del_callback(&cn_test_id); 16814fbff6bSArnd Bergmann goto err_out; 16914fbff6bSArnd Bergmann } 17014fbff6bSArnd Bergmann 171*0d694234SKees Cook timer_setup(&cn_test_timer, cn_test_timer_func, 0); 17214fbff6bSArnd Bergmann mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); 17314fbff6bSArnd Bergmann 17414fbff6bSArnd Bergmann pr_info("initialized with id={%u.%u}\n", 17514fbff6bSArnd Bergmann cn_test_id.idx, cn_test_id.val); 17614fbff6bSArnd Bergmann 17714fbff6bSArnd Bergmann return 0; 17814fbff6bSArnd Bergmann 17914fbff6bSArnd Bergmann err_out: 18014fbff6bSArnd Bergmann if (nls && nls->sk_socket) 18114fbff6bSArnd Bergmann sock_release(nls->sk_socket); 18214fbff6bSArnd Bergmann 18314fbff6bSArnd Bergmann return err; 18414fbff6bSArnd Bergmann } 18514fbff6bSArnd Bergmann 18614fbff6bSArnd Bergmann static void cn_test_fini(void) 18714fbff6bSArnd Bergmann { 18814fbff6bSArnd Bergmann del_timer_sync(&cn_test_timer); 18914fbff6bSArnd Bergmann cn_del_callback(&cn_test_id); 19014fbff6bSArnd Bergmann cn_test_id.val--; 19114fbff6bSArnd Bergmann cn_del_callback(&cn_test_id); 19214fbff6bSArnd Bergmann if (nls && nls->sk_socket) 19314fbff6bSArnd Bergmann sock_release(nls->sk_socket); 19414fbff6bSArnd Bergmann } 19514fbff6bSArnd Bergmann 19614fbff6bSArnd Bergmann module_init(cn_test_init); 19714fbff6bSArnd Bergmann module_exit(cn_test_fini); 19814fbff6bSArnd Bergmann 19914fbff6bSArnd Bergmann MODULE_LICENSE("GPL"); 20014fbff6bSArnd Bergmann MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); 20114fbff6bSArnd Bergmann MODULE_DESCRIPTION("Connector's test module"); 202