···11+/*22+ * cn_test.c33+ * 44+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>55+ * All rights reserved.66+ * 77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License as published by99+ * the Free Software Foundation; either version 2 of the License, or1010+ * (at your option) any later version.1111+ *1212+ * This program is distributed in the hope that it will be useful,1313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1414+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1515+ * GNU General Public License for more details.1616+ *1717+ * You should have received a copy of the GNU General Public License1818+ * along with this program; if not, write to the Free Software1919+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2020+ */2121+2222+#include <linux/kernel.h>2323+#include <linux/module.h>2424+#include <linux/moduleparam.h>2525+#include <linux/skbuff.h>2626+#include <linux/timer.h>2727+2828+#include "connector.h"2929+3030+static struct cb_id cn_test_id = { 0x123, 0x456 };3131+static char cn_test_name[] = "cn_test";3232+static struct sock *nls;3333+static struct timer_list cn_test_timer;3434+3535+void cn_test_callback(void *data)3636+{3737+ struct cn_msg *msg = (struct cn_msg *)data;3838+3939+ printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",4040+ __func__, jiffies, msg->id.idx, msg->id.val,4141+ msg->seq, msg->ack, msg->len, (char *)msg->data);4242+}4343+4444+static int cn_test_want_notify(void)4545+{4646+ struct cn_ctl_msg *ctl;4747+ struct cn_notify_req *req;4848+ struct cn_msg *msg = NULL;4949+ int size, size0;5050+ struct sk_buff *skb;5151+ struct nlmsghdr *nlh;5252+ u32 group = 1;5353+5454+ size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req);5555+5656+ size = NLMSG_SPACE(size0);5757+5858+ skb = alloc_skb(size, GFP_ATOMIC);5959+ if (!skb) {6060+ printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",6161+ size);6262+6363+ return -ENOMEM;6464+ }6565+6666+ nlh = NLMSG_PUT(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh));6767+6868+ msg = (struct cn_msg *)NLMSG_DATA(nlh);6969+7070+ memset(msg, 0, size0);7171+7272+ msg->id.idx = -1;7373+ msg->id.val = -1;7474+ msg->seq = 0x123;7575+ msg->ack = 0x345;7676+ msg->len = size0 - sizeof(*msg);7777+7878+ ctl = (struct cn_ctl_msg *)(msg + 1);7979+8080+ ctl->idx_notify_num = 1;8181+ ctl->val_notify_num = 2;8282+ ctl->group = group;8383+ ctl->len = msg->len - sizeof(*ctl);8484+8585+ req = (struct cn_notify_req *)(ctl + 1);8686+8787+ /*8888+ * Idx.8989+ */9090+ req->first = cn_test_id.idx;9191+ req->range = 10;9292+9393+ /*9494+ * Val 0.9595+ */9696+ req++;9797+ req->first = cn_test_id.val;9898+ req->range = 10;9999+100100+ /*101101+ * Val 1.102102+ */103103+ req++;104104+ req->first = cn_test_id.val + 20;105105+ req->range = 10;106106+107107+ NETLINK_CB(skb).dst_groups = ctl->group;108108+ //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);109109+ netlink_unicast(nls, skb, 0, 0);110110+111111+ printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);112112+113113+ return 0;114114+115115+nlmsg_failure:116116+ printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);117117+ kfree_skb(skb);118118+ return -EINVAL;119119+}120120+121121+static u32 cn_test_timer_counter;122122+static void cn_test_timer_func(unsigned long __data)123123+{124124+ struct cn_msg *m;125125+ char data[32];126126+127127+ m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);128128+ if (m) {129129+ memset(m, 0, sizeof(*m) + sizeof(data));130130+131131+ memcpy(&m->id, &cn_test_id, sizeof(m->id));132132+ m->seq = cn_test_timer_counter;133133+ m->len = sizeof(data);134134+135135+ m->len =136136+ scnprintf(data, sizeof(data), "counter = %u",137137+ cn_test_timer_counter) + 1;138138+139139+ memcpy(m + 1, data, m->len);140140+141141+ cn_netlink_send(m, 0, gfp_any());142142+ kfree(m);143143+ }144144+145145+ cn_test_timer_counter++;146146+147147+ mod_timer(&cn_test_timer, jiffies + HZ);148148+}149149+150150+static int cn_test_init(void)151151+{152152+ int err;153153+154154+ err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);155155+ if (err)156156+ goto err_out;157157+ cn_test_id.val++;158158+ err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);159159+ if (err) {160160+ cn_del_callback(&cn_test_id);161161+ goto err_out;162162+ }163163+164164+ init_timer(&cn_test_timer);165165+ cn_test_timer.function = cn_test_timer_func;166166+ cn_test_timer.expires = jiffies + HZ;167167+ cn_test_timer.data = 0;168168+ add_timer(&cn_test_timer);169169+170170+ return 0;171171+172172+ err_out:173173+ if (nls && nls->sk_socket)174174+ sock_release(nls->sk_socket);175175+176176+ return err;177177+}178178+179179+static void cn_test_fini(void)180180+{181181+ del_timer_sync(&cn_test_timer);182182+ cn_del_callback(&cn_test_id);183183+ cn_test_id.val--;184184+ cn_del_callback(&cn_test_id);185185+ if (nls && nls->sk_socket)186186+ sock_release(nls->sk_socket);187187+}188188+189189+module_init(cn_test_init);190190+module_exit(cn_test_fini);191191+192192+MODULE_LICENSE("GPL");193193+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");194194+MODULE_DESCRIPTION("Connector's test module");
+133
Documentation/connector/connector.txt
···11+/*****************************************/22+Kernel Connector.33+/*****************************************/44+55+Kernel connector - new netlink based userspace <-> kernel space easy66+to use communication module.77+88+Connector driver adds possibility to connect various agents using99+netlink based network. One must register callback and1010+identifier. When driver receives special netlink message with1111+appropriate identifier, appropriate callback will be called.1212+1313+From the userspace point of view it's quite straightforward:1414+1515+ socket();1616+ bind();1717+ send();1818+ recv();1919+2020+But if kernelspace want to use full power of such connections, driver2121+writer must create special sockets, must know about struct sk_buff2222+handling... Connector allows any kernelspace agents to use netlink2323+based networking for inter-process communication in a significantly2424+easier way:2525+2626+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));2727+void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);2828+2929+struct cb_id3030+{3131+ __u32 idx;3232+ __u32 val;3333+};3434+3535+idx and val are unique identifiers which must be registered in3636+connector.h for in-kernel usage. void (*callback) (void *) - is a3737+callback function which will be called when message with above idx.val3838+will be received by connector core. Argument for that function must3939+be dereferenced to struct cn_msg *.4040+4141+struct cn_msg4242+{4343+ struct cb_id id;4444+4545+ __u32 seq;4646+ __u32 ack;4747+4848+ __u32 len; /* Length of the following data */4949+ __u8 data[0];5050+};5151+5252+/*****************************************/5353+Connector interfaces.5454+/*****************************************/5555+5656+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));5757+5858+Registers new callback with connector core.5959+6060+struct cb_id *id - unique connector's user identifier.6161+ It must be registered in connector.h for legal in-kernel users.6262+char *name - connector's callback symbolic name.6363+void (*callback) (void *) - connector's callback.6464+ Argument must be dereferenced to struct cn_msg *.6565+6666+void cn_del_callback(struct cb_id *id);6767+6868+Unregisters new callback with connector core.6969+7070+struct cb_id *id - unique connector's user identifier.7171+7272+void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);7373+7474+Sends message to the specified groups. It can be safely called from7575+any context, but may silently fail under strong memory pressure.7676+7777+struct cn_msg * - message header(with attached data).7878+u32 __group - destination group.7979+ If __group is zero, then appropriate group will8080+ be searched through all registered connector users,8181+ and message will be delivered to the group which was8282+ created for user with the same ID as in msg.8383+ If __group is not zero, then message will be delivered8484+ to the specified group.8585+int gfp_mask - GFP mask.8686+8787+Note: When registering new callback user, connector core assigns8888+netlink group to the user which is equal to it's id.idx.8989+9090+/*****************************************/9191+Protocol description.9292+/*****************************************/9393+9494+Current offers transport layer with fixed header. Recommended9595+protocol which uses such header is following:9696+9797+msg->seq and msg->ack are used to determine message genealogy. When9898+someone sends message it puts there locally unique sequence and random9999+acknowledge numbers. Sequence number may be copied into100100+nlmsghdr->nlmsg_seq too.101101+102102+Sequence number is incremented with each message to be sent.103103+104104+If we expect reply to our message, then sequence number in received105105+message MUST be the same as in original message, and acknowledge106106+number MUST be the same + 1.107107+108108+If we receive message and it's sequence number is not equal to one we109109+are expecting, then it is new message. If we receive message and it's110110+sequence number is the same as one we are expecting, but it's111111+acknowledge is not equal acknowledge number in original message + 1,112112+then it is new message.113113+114114+Obviously, protocol header contains above id.115115+116116+connector allows event notification in the following form: kernel117117+driver or userspace process can ask connector to notify it when118118+selected id's will be turned on or off(registered or unregistered it's119119+callback). It is done by sending special command to connector120120+driver(it also registers itself with id={-1, -1}).121121+122122+As example of usage Documentation/connector now contains cn_test.c -123123+testing module which uses connector to request notification and to124124+send messages.125125+126126+/*****************************************/127127+Reliability.128128+/*****************************************/129129+130130+Netlink itself is not reliable protocol, that means that messages can131131+be lost due to memory pressure or process' receiving queue overflowed,132132+so caller is warned must be prepared. That is why struct cn_msg [main133133+connector's message header] contains u32 seq and u32 ack fields.
···1717# default.1818obj-y += char/19192020+obj-$(CONFIG_CONNECTOR) += connector/2121+2022# i810fb and intelfb depend on char/agp/2123obj-$(CONFIG_FB_I810) += video/i810/2224obj-$(CONFIG_FB_INTEL) += video/intelfb/
+13
drivers/connector/Kconfig
···11+menu "Connector - unified userspace <-> kernelspace linker"22+33+config CONNECTOR44+ tristate "Connector - unified userspace <-> kernelspace linker"55+ depends on NET66+ ---help---77+ This is unified userspace <-> kernelspace connector working on top88+ of the netlink socket protocol.99+1010+ Connector support can also be built as a module. If so, the module1111+ will be called cn.ko.1212+1313+endmenu
···11+/*22+ * cn_queue.c33+ * 44+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>55+ * All rights reserved.66+ * 77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License as published by99+ * the Free Software Foundation; either version 2 of the License, or1010+ * (at your option) any later version.1111+ *1212+ * This program is distributed in the hope that it will be useful,1313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1414+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1515+ * GNU General Public License for more details.1616+ *1717+ * You should have received a copy of the GNU General Public License1818+ * along with this program; if not, write to the Free Software1919+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2020+ *2121+ */2222+2323+#include <linux/kernel.h>2424+#include <linux/module.h>2525+#include <linux/list.h>2626+#include <linux/workqueue.h>2727+#include <linux/spinlock.h>2828+#include <linux/slab.h>2929+#include <linux/skbuff.h>3030+#include <linux/suspend.h>3131+#include <linux/connector.h>3232+#include <linux/delay.h>3333+3434+static void cn_queue_wrapper(void *data)3535+{3636+ struct cn_callback_entry *cbq = data;3737+3838+ cbq->cb->callback(cbq->cb->priv);3939+ cbq->destruct_data(cbq->ddata);4040+ cbq->ddata = NULL;4141+}4242+4343+static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)4444+{4545+ struct cn_callback_entry *cbq;4646+4747+ cbq = kzalloc(sizeof(*cbq), GFP_KERNEL);4848+ if (!cbq) {4949+ printk(KERN_ERR "Failed to create new callback queue.\n");5050+ return NULL;5151+ }5252+5353+ cbq->cb = cb;5454+ INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);5555+ return cbq;5656+}5757+5858+static void cn_queue_free_callback(struct cn_callback_entry *cbq)5959+{6060+ cancel_delayed_work(&cbq->work);6161+ flush_workqueue(cbq->pdev->cn_queue);6262+6363+ kfree(cbq);6464+}6565+6666+int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)6767+{6868+ return ((i1->idx == i2->idx) && (i1->val == i2->val));6969+}7070+7171+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)7272+{7373+ struct cn_callback_entry *cbq, *__cbq;7474+ int found = 0;7575+7676+ cbq = cn_queue_alloc_callback_entry(cb);7777+ if (!cbq)7878+ return -ENOMEM;7979+8080+ atomic_inc(&dev->refcnt);8181+ cbq->pdev = dev;8282+8383+ spin_lock_bh(&dev->queue_lock);8484+ list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {8585+ if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {8686+ found = 1;8787+ break;8888+ }8989+ }9090+ if (!found)9191+ list_add_tail(&cbq->callback_entry, &dev->queue_list);9292+ spin_unlock_bh(&dev->queue_lock);9393+9494+ if (found) {9595+ atomic_dec(&dev->refcnt);9696+ cn_queue_free_callback(cbq);9797+ return -EINVAL;9898+ }9999+100100+ cbq->nls = dev->nls;101101+ cbq->seq = 0;102102+ cbq->group = cbq->cb->id.idx;103103+104104+ return 0;105105+}106106+107107+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)108108+{109109+ struct cn_callback_entry *cbq, *n;110110+ int found = 0;111111+112112+ spin_lock_bh(&dev->queue_lock);113113+ list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {114114+ if (cn_cb_equal(&cbq->cb->id, id)) {115115+ list_del(&cbq->callback_entry);116116+ found = 1;117117+ break;118118+ }119119+ }120120+ spin_unlock_bh(&dev->queue_lock);121121+122122+ if (found) {123123+ cn_queue_free_callback(cbq);124124+ atomic_dec_and_test(&dev->refcnt);125125+ }126126+}127127+128128+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)129129+{130130+ struct cn_queue_dev *dev;131131+132132+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);133133+ if (!dev)134134+ return NULL;135135+136136+ snprintf(dev->name, sizeof(dev->name), "%s", name);137137+ atomic_set(&dev->refcnt, 0);138138+ INIT_LIST_HEAD(&dev->queue_list);139139+ spin_lock_init(&dev->queue_lock);140140+141141+ dev->nls = nls;142142+ dev->netlink_groups = 0;143143+144144+ dev->cn_queue = create_workqueue(dev->name);145145+ if (!dev->cn_queue) {146146+ kfree(dev);147147+ return NULL;148148+ }149149+150150+ return dev;151151+}152152+153153+void cn_queue_free_dev(struct cn_queue_dev *dev)154154+{155155+ struct cn_callback_entry *cbq, *n;156156+157157+ flush_workqueue(dev->cn_queue);158158+ destroy_workqueue(dev->cn_queue);159159+160160+ spin_lock_bh(&dev->queue_lock);161161+ list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)162162+ list_del(&cbq->callback_entry);163163+ spin_unlock_bh(&dev->queue_lock);164164+165165+ while (atomic_read(&dev->refcnt)) {166166+ printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",167167+ dev->name, atomic_read(&dev->refcnt));168168+ msleep(1000);169169+ }170170+171171+ kfree(dev);172172+ dev = NULL;173173+}
+486
drivers/connector/connector.c
···11+/*22+ * connector.c33+ * 44+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>55+ * All rights reserved.66+ * 77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License as published by99+ * the Free Software Foundation; either version 2 of the License, or1010+ * (at your option) any later version.1111+ *1212+ * This program is distributed in the hope that it will be useful,1313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1414+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1515+ * GNU General Public License for more details.1616+ *1717+ * You should have received a copy of the GNU General Public License1818+ * along with this program; if not, write to the Free Software1919+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2020+ */2121+2222+#include <linux/kernel.h>2323+#include <linux/module.h>2424+#include <linux/list.h>2525+#include <linux/skbuff.h>2626+#include <linux/netlink.h>2727+#include <linux/moduleparam.h>2828+#include <linux/connector.h>2929+3030+#include <net/sock.h>3131+3232+MODULE_LICENSE("GPL");3333+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");3434+MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");3535+3636+static u32 cn_idx = CN_IDX_CONNECTOR;3737+static u32 cn_val = CN_VAL_CONNECTOR;3838+3939+module_param(cn_idx, uint, 0);4040+module_param(cn_val, uint, 0);4141+MODULE_PARM_DESC(cn_idx, "Connector's main device idx.");4242+MODULE_PARM_DESC(cn_val, "Connector's main device val.");4343+4444+static DECLARE_MUTEX(notify_lock);4545+static LIST_HEAD(notify_list);4646+4747+static struct cn_dev cdev;4848+4949+int cn_already_initialized = 0;5050+5151+/*5252+ * msg->seq and msg->ack are used to determine message genealogy.5353+ * When someone sends message it puts there locally unique sequence5454+ * and random acknowledge numbers. Sequence number may be copied into5555+ * nlmsghdr->nlmsg_seq too.5656+ *5757+ * Sequence number is incremented with each message to be sent.5858+ *5959+ * If we expect reply to our message then the sequence number in6060+ * received message MUST be the same as in original message, and6161+ * acknowledge number MUST be the same + 1.6262+ *6363+ * If we receive a message and its sequence number is not equal to the6464+ * one we are expecting then it is a new message.6565+ *6666+ * If we receive a message and its sequence number is the same as one6767+ * we are expecting but it's acknowledgement number is not equal to6868+ * the acknowledgement number in the original message + 1, then it is6969+ * a new message.7070+ *7171+ */7272+int cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask)7373+{7474+ struct cn_callback_entry *__cbq;7575+ unsigned int size;7676+ struct sk_buff *skb;7777+ struct nlmsghdr *nlh;7878+ struct cn_msg *data;7979+ struct cn_dev *dev = &cdev;8080+ u32 group = 0;8181+ int found = 0;8282+8383+ if (!__group) {8484+ spin_lock_bh(&dev->cbdev->queue_lock);8585+ list_for_each_entry(__cbq, &dev->cbdev->queue_list,8686+ callback_entry) {8787+ if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {8888+ found = 1;8989+ group = __cbq->group;9090+ }9191+ }9292+ spin_unlock_bh(&dev->cbdev->queue_lock);9393+9494+ if (!found)9595+ return -ENODEV;9696+ } else {9797+ group = __group;9898+ }9999+100100+ size = NLMSG_SPACE(sizeof(*msg) + msg->len);101101+102102+ skb = alloc_skb(size, gfp_mask);103103+ if (!skb)104104+ return -ENOMEM;105105+106106+ nlh = NLMSG_PUT(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh));107107+108108+ data = NLMSG_DATA(nlh);109109+110110+ memcpy(data, msg, sizeof(*data) + msg->len);111111+112112+ NETLINK_CB(skb).dst_group = group;113113+114114+ netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);115115+116116+ return 0;117117+118118+nlmsg_failure:119119+ kfree_skb(skb);120120+ return -EINVAL;121121+}122122+123123+/*124124+ * Callback helper - queues work and setup destructor for given data.125125+ */126126+static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)127127+{128128+ struct cn_callback_entry *__cbq;129129+ struct cn_dev *dev = &cdev;130130+ int found = 0;131131+132132+ spin_lock_bh(&dev->cbdev->queue_lock);133133+ list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {134134+ if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {135135+ /*136136+ * Let's scream if there is some magic and the137137+ * data will arrive asynchronously here.138138+ * [i.e. netlink messages will be queued].139139+ * After the first warning I will fix it140140+ * quickly, but now I think it is141141+ * impossible. --zbr (2004_04_27).142142+ */143143+ if (likely(!test_bit(0, &__cbq->work.pending) &&144144+ __cbq->ddata == NULL)) {145145+ __cbq->cb->priv = msg;146146+147147+ __cbq->ddata = data;148148+ __cbq->destruct_data = destruct_data;149149+150150+ if (queue_work(dev->cbdev->cn_queue,151151+ &__cbq->work))152152+ found = 1;153153+ } else {154154+ printk("%s: cbq->data=%p, "155155+ "work->pending=%08lx.\n",156156+ __func__, __cbq->ddata,157157+ __cbq->work.pending);158158+ WARN_ON(1);159159+ }160160+ break;161161+ }162162+ }163163+ spin_unlock_bh(&dev->cbdev->queue_lock);164164+165165+ return found ? 0 : -ENODEV;166166+}167167+168168+/*169169+ * Skb receive helper - checks skb and msg size and calls callback170170+ * helper.171171+ */172172+static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh)173173+{174174+ u32 pid, uid, seq, group;175175+ struct cn_msg *msg;176176+177177+ pid = NETLINK_CREDS(skb)->pid;178178+ uid = NETLINK_CREDS(skb)->uid;179179+ seq = nlh->nlmsg_seq;180180+ group = NETLINK_CB((skb)).dst_group;181181+ msg = NLMSG_DATA(nlh);182182+183183+ return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);184184+}185185+186186+/*187187+ * Main netlink receiving function.188188+ *189189+ * It checks skb and netlink header sizes and calls the skb receive190190+ * helper with a shared skb.191191+ */192192+static void cn_rx_skb(struct sk_buff *__skb)193193+{194194+ struct nlmsghdr *nlh;195195+ u32 len;196196+ int err;197197+ struct sk_buff *skb;198198+199199+ skb = skb_get(__skb);200200+201201+ if (skb->len >= NLMSG_SPACE(0)) {202202+ nlh = (struct nlmsghdr *)skb->data;203203+204204+ if (nlh->nlmsg_len < sizeof(struct cn_msg) ||205205+ skb->len < nlh->nlmsg_len ||206206+ nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {207207+ kfree_skb(skb);208208+ goto out;209209+ }210210+211211+ len = NLMSG_ALIGN(nlh->nlmsg_len);212212+ if (len > skb->len)213213+ len = skb->len;214214+215215+ err = __cn_rx_skb(skb, nlh);216216+ if (err < 0)217217+ kfree_skb(skb);218218+ }219219+220220+out:221221+ kfree_skb(__skb);222222+}223223+224224+/*225225+ * Netlink socket input callback - dequeues the skbs and calls the226226+ * main netlink receiving function.227227+ */228228+static void cn_input(struct sock *sk, int len)229229+{230230+ struct sk_buff *skb;231231+232232+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)233233+ cn_rx_skb(skb);234234+}235235+236236+/*237237+ * Notification routing.238238+ *239239+ * Gets id and checks if there are notification request for it's idx240240+ * and val. If there are such requests notify the listeners with the241241+ * given notify event.242242+ *243243+ */244244+static void cn_notify(struct cb_id *id, u32 notify_event)245245+{246246+ struct cn_ctl_entry *ent;247247+248248+ down(¬ify_lock);249249+ list_for_each_entry(ent, ¬ify_list, notify_entry) {250250+ int i;251251+ struct cn_notify_req *req;252252+ struct cn_ctl_msg *ctl = ent->msg;253253+ int idx_found, val_found;254254+255255+ idx_found = val_found = 0;256256+257257+ req = (struct cn_notify_req *)ctl->data;258258+ for (i = 0; i < ctl->idx_notify_num; ++i, ++req) {259259+ if (id->idx >= req->first && 260260+ id->idx < req->first + req->range) {261261+ idx_found = 1;262262+ break;263263+ }264264+ }265265+266266+ for (i = 0; i < ctl->val_notify_num; ++i, ++req) {267267+ if (id->val >= req->first && 268268+ id->val < req->first + req->range) {269269+ val_found = 1;270270+ break;271271+ }272272+ }273273+274274+ if (idx_found && val_found) {275275+ struct cn_msg m = { .ack = notify_event, };276276+277277+ memcpy(&m.id, id, sizeof(m.id));278278+ cn_netlink_send(&m, ctl->group, GFP_KERNEL);279279+ }280280+ }281281+ up(¬ify_lock);282282+}283283+284284+/*285285+ * Callback add routing - adds callback with given ID and name.286286+ * If there is registered callback with the same ID it will not be added.287287+ *288288+ * May sleep.289289+ */290290+int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))291291+{292292+ int err;293293+ struct cn_dev *dev = &cdev;294294+ struct cn_callback *cb;295295+296296+ cb = kzalloc(sizeof(*cb), GFP_KERNEL);297297+ if (!cb)298298+ return -ENOMEM;299299+300300+ scnprintf(cb->name, sizeof(cb->name), "%s", name);301301+302302+ memcpy(&cb->id, id, sizeof(cb->id));303303+ cb->callback = callback;304304+305305+ err = cn_queue_add_callback(dev->cbdev, cb);306306+ if (err) {307307+ kfree(cb);308308+ return err;309309+ }310310+311311+ cn_notify(id, 0);312312+313313+ return 0;314314+}315315+316316+/*317317+ * Callback remove routing - removes callback318318+ * with given ID.319319+ * If there is no registered callback with given320320+ * ID nothing happens.321321+ *322322+ * May sleep while waiting for reference counter to become zero.323323+ */324324+void cn_del_callback(struct cb_id *id)325325+{326326+ struct cn_dev *dev = &cdev;327327+328328+ cn_queue_del_callback(dev->cbdev, id);329329+ cn_notify(id, 1);330330+}331331+332332+/*333333+ * Checks two connector's control messages to be the same.334334+ * Returns 1 if they are the same or if the first one is corrupted.335335+ */336336+static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)337337+{338338+ int i;339339+ struct cn_notify_req *req1, *req2;340340+341341+ if (m1->idx_notify_num != m2->idx_notify_num)342342+ return 0;343343+344344+ if (m1->val_notify_num != m2->val_notify_num)345345+ return 0;346346+347347+ if (m1->len != m2->len)348348+ return 0;349349+350350+ if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) !=351351+ m1->len)352352+ return 1;353353+354354+ req1 = (struct cn_notify_req *)m1->data;355355+ req2 = (struct cn_notify_req *)m2->data;356356+357357+ for (i = 0; i < m1->idx_notify_num; ++i) {358358+ if (req1->first != req2->first || req1->range != req2->range)359359+ return 0;360360+ req1++;361361+ req2++;362362+ }363363+364364+ for (i = 0; i < m1->val_notify_num; ++i) {365365+ if (req1->first != req2->first || req1->range != req2->range)366366+ return 0;367367+ req1++;368368+ req2++;369369+ }370370+371371+ return 1;372372+}373373+374374+/*375375+ * Main connector device's callback.376376+ *377377+ * Used for notification of a request's processing.378378+ */379379+static void cn_callback(void *data)380380+{381381+ struct cn_msg *msg = data;382382+ struct cn_ctl_msg *ctl;383383+ struct cn_ctl_entry *ent;384384+ u32 size;385385+386386+ if (msg->len < sizeof(*ctl))387387+ return;388388+389389+ ctl = (struct cn_ctl_msg *)msg->data;390390+391391+ size = (sizeof(*ctl) + ((ctl->idx_notify_num +392392+ ctl->val_notify_num) *393393+ sizeof(struct cn_notify_req)));394394+395395+ if (msg->len != size)396396+ return;397397+398398+ if (ctl->len + sizeof(*ctl) != msg->len)399399+ return;400400+401401+ /*402402+ * Remove notification.403403+ */404404+ if (ctl->group == 0) {405405+ struct cn_ctl_entry *n;406406+407407+ down(¬ify_lock);408408+ list_for_each_entry_safe(ent, n, ¬ify_list, notify_entry) {409409+ if (cn_ctl_msg_equals(ent->msg, ctl)) {410410+ list_del(&ent->notify_entry);411411+ kfree(ent);412412+ }413413+ }414414+ up(¬ify_lock);415415+416416+ return;417417+ }418418+419419+ size += sizeof(*ent);420420+421421+ ent = kzalloc(size, GFP_KERNEL);422422+ if (!ent)423423+ return;424424+425425+ ent->msg = (struct cn_ctl_msg *)(ent + 1);426426+427427+ memcpy(ent->msg, ctl, size - sizeof(*ent));428428+429429+ down(¬ify_lock);430430+ list_add(&ent->notify_entry, ¬ify_list);431431+ up(¬ify_lock);432432+}433433+434434+static int __init cn_init(void)435435+{436436+ struct cn_dev *dev = &cdev;437437+ int err;438438+439439+ dev->input = cn_input;440440+ dev->id.idx = cn_idx;441441+ dev->id.val = cn_val;442442+443443+ dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,444444+ CN_NETLINK_USERS + 0xf,445445+ dev->input, THIS_MODULE);446446+ if (!dev->nls)447447+ return -EIO;448448+449449+ dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);450450+ if (!dev->cbdev) {451451+ if (dev->nls->sk_socket)452452+ sock_release(dev->nls->sk_socket);453453+ return -EINVAL;454454+ }455455+456456+ err = cn_add_callback(&dev->id, "connector", &cn_callback);457457+ if (err) {458458+ cn_queue_free_dev(dev->cbdev);459459+ if (dev->nls->sk_socket)460460+ sock_release(dev->nls->sk_socket);461461+ return -EINVAL;462462+ }463463+464464+ cn_already_initialized = 1;465465+466466+ return 0;467467+}468468+469469+static void __exit cn_fini(void)470470+{471471+ struct cn_dev *dev = &cdev;472472+473473+ cn_already_initialized = 0;474474+475475+ cn_del_callback(&dev->id);476476+ cn_queue_free_dev(dev->cbdev);477477+ if (dev->nls->sk_socket)478478+ sock_release(dev->nls->sk_socket);479479+}480480+481481+module_init(cn_init);482482+module_exit(cn_fini);483483+484484+EXPORT_SYMBOL_GPL(cn_add_callback);485485+EXPORT_SYMBOL_GPL(cn_del_callback);486486+EXPORT_SYMBOL_GPL(cn_netlink_send);
+2
drivers/net/bnx2.c
···50155015 .phys_id = bnx2_phys_id,50165016 .get_stats_count = bnx2_get_stats_count,50175017 .get_ethtool_stats = bnx2_get_ethtool_stats,50185018+ .get_perm_addr = ethtool_op_get_perm_addr,50185019};5019502050205021/* Called with rtnl_lock */···54435442 pci_set_drvdata(pdev, dev);5444544354455444 memcpy(dev->dev_addr, bp->mac_addr, 6);54455445+ memcpy(dev->perm_addr, bp->mac_addr, 6);54465446 bp->name = board_info[ent->driver_data].name,54475447 printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "54485448 "IRQ %d, ",
···11+/*22+ * connector.h33+ * 44+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>55+ * All rights reserved.66+ * 77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of the GNU General Public License as published by99+ * the Free Software Foundation; either version 2 of the License, or1010+ * (at your option) any later version.1111+ *1212+ * This program is distributed in the hope that it will be useful,1313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of1414+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1515+ * GNU General Public License for more details.1616+ *1717+ * You should have received a copy of the GNU General Public License1818+ * along with this program; if not, write to the Free Software1919+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA2020+ */2121+2222+#ifndef __CONNECTOR_H2323+#define __CONNECTOR_H2424+2525+#include <asm/types.h>2626+2727+#define CN_IDX_CONNECTOR 0xffffffff2828+#define CN_VAL_CONNECTOR 0xffffffff2929+3030+#define CN_NETLINK_USERS 13131+3232+/*3333+ * Maximum connector's message size.3434+ */3535+#define CONNECTOR_MAX_MSG_SIZE 10243636+3737+/*3838+ * idx and val are unique identifiers which 3939+ * are used for message routing and 4040+ * must be registered in connector.h for in-kernel usage.4141+ */4242+4343+struct cb_id {4444+ __u32 idx;4545+ __u32 val;4646+};4747+4848+struct cn_msg {4949+ struct cb_id id;5050+5151+ __u32 seq;5252+ __u32 ack;5353+5454+ __u16 len; /* Length of the following data */5555+ __u16 flags;5656+ __u8 data[0];5757+};5858+5959+/*6060+ * Notify structure - requests notification about6161+ * registering/unregistering idx/val in range [first, first+range].6262+ */6363+struct cn_notify_req {6464+ __u32 first;6565+ __u32 range;6666+};6767+6868+/*6969+ * Main notification control message7070+ * *_notify_num - number of appropriate cn_notify_req structures after 7171+ * this struct.7272+ * group - notification receiver's idx.7373+ * len - total length of the attached data.7474+ */7575+struct cn_ctl_msg {7676+ __u32 idx_notify_num;7777+ __u32 val_notify_num;7878+ __u32 group;7979+ __u32 len;8080+ __u8 data[0];8181+};8282+8383+#ifdef __KERNEL__8484+8585+#include <asm/atomic.h>8686+8787+#include <linux/list.h>8888+#include <linux/workqueue.h>8989+9090+#include <net/sock.h>9191+9292+#define CN_CBQ_NAMELEN 329393+9494+struct cn_queue_dev {9595+ atomic_t refcnt;9696+ unsigned char name[CN_CBQ_NAMELEN];9797+9898+ struct workqueue_struct *cn_queue;9999+100100+ struct list_head queue_list;101101+ spinlock_t queue_lock;102102+103103+ int netlink_groups;104104+ struct sock *nls;105105+};106106+107107+struct cn_callback {108108+ unsigned char name[CN_CBQ_NAMELEN];109109+110110+ struct cb_id id;111111+ void (*callback) (void *);112112+ void *priv;113113+};114114+115115+struct cn_callback_entry {116116+ struct list_head callback_entry;117117+ struct cn_callback *cb;118118+ struct work_struct work;119119+ struct cn_queue_dev *pdev;120120+121121+ void (*destruct_data) (void *);122122+ void *ddata;123123+124124+ int seq, group;125125+ struct sock *nls;126126+};127127+128128+struct cn_ctl_entry {129129+ struct list_head notify_entry;130130+ struct cn_ctl_msg *msg;131131+};132132+133133+struct cn_dev {134134+ struct cb_id id;135135+136136+ u32 seq, groups;137137+ struct sock *nls;138138+ void (*input) (struct sock * sk, int len);139139+140140+ struct cn_queue_dev *cbdev;141141+};142142+143143+int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));144144+void cn_del_callback(struct cb_id *);145145+int cn_netlink_send(struct cn_msg *, u32, int);146146+147147+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb);148148+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);149149+150150+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);151151+void cn_queue_free_dev(struct cn_queue_dev *dev);152152+153153+int cn_cb_equal(struct cb_id *, struct cb_id *);154154+155155+extern int cn_already_initialized;156156+157157+#endif /* __KERNEL__ */158158+#endif /* __CONNECTOR_H */
···14521452 thread_lock();14531453 t->control |= T_REMDEV;14541454 thread_unlock();14551455- current->state = TASK_INTERRUPTIBLE;14561456- schedule_timeout(HZ/8); /* Propagate thread->control */14551455+ schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */14571456 ret = count;14581457 sprintf(pg_result, "OK: rem_device_all");14591458 goto out;···17151716 printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));17161717 while (now < spin_until_us) {17171718 /* TODO: optimise sleeping behavior */17181718- if (spin_until_us - now > (1000000/HZ)+1) {17191719- current->state = TASK_INTERRUPTIBLE;17201720- schedule_timeout(1);17211721- } else if (spin_until_us - now > 100) {17191719+ if (spin_until_us - now > jiffies_to_usecs(1)+1)17201720+ schedule_timeout_interruptible(1);17211721+ else if (spin_until_us - now > 100) {17221722 do_softirq();17231723 if (!pkt_dev->running)17241724 return;···24472449 }24482450 thread_unlock();2449245124502450- current->state = TASK_INTERRUPTIBLE;24512451- schedule_timeout(HZ/8); /* Propagate thread->control */24522452+ schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */2452245324532454 pktgen_wait_all_threads_run();24542455}
+8
net/dccp/ccids/ccid3.c
···10951095{10961096 const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);1097109710981098+ /* Listen socks doesn't have a private CCID block */10991099+ if (sk->sk_state == DCCP_LISTEN)11001100+ return;11011101+10981102 BUG_ON(hcrx == NULL);1099110311001104 info->tcpi_ca_state = hcrx->ccid3hcrx_state;···11091105static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)11101106{11111107 const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);11081108+11091109+ /* Listen socks doesn't have a private CCID block */11101110+ if (sk->sk_state == DCCP_LISTEN)11111111+ return;1112111211131113 BUG_ON(hctx == NULL);11141114
+2-4
net/ipv4/ipconfig.c
···11031103#endif1104110411051105 jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);11061106- while (time_before(jiffies, jiff) && !ic_got_reply) {11071107- set_current_state(TASK_UNINTERRUPTIBLE);11081108- schedule_timeout(1);11091109- }11061106+ while (time_before(jiffies, jiff) && !ic_got_reply)11071107+ schedule_timeout_uninterruptible(1);11101108#ifdef IPCONFIG_DHCP11111109 /* DHCP isn't done until we get a DHCPACK. */11121110 if ((ic_got_reply & IC_BOOTP)
+3-6
net/irda/ircomm/ircomm_tty.c
···567567 self->tty = NULL;568568569569 if (self->blocked_open) {570570- if (self->close_delay) {571571- current->state = TASK_INTERRUPTIBLE;572572- schedule_timeout(self->close_delay);573573- }570570+ if (self->close_delay)571571+ schedule_timeout_interruptible(self->close_delay);574572 wake_up_interruptible(&self->open_wait);575573 }576574···861863 spin_lock_irqsave(&self->spinlock, flags);862864 while (self->tx_skb && self->tx_skb->len) {863865 spin_unlock_irqrestore(&self->spinlock, flags);864864- current->state = TASK_INTERRUPTIBLE;865865- schedule_timeout(poll_time);866866+ schedule_timeout_interruptible(poll_time);866867 spin_lock_irqsave(&self->spinlock, flags);867868 if (signal_pending(current))868869 break;
+13-15
net/netrom/af_netrom.c
···5656int sysctl_netrom_transport_no_activity_timeout = NR_DEFAULT_IDLE;5757int sysctl_netrom_routing_control = NR_DEFAULT_ROUTING;5858int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;5959+int sysctl_netrom_reset_circuit = NR_DEFAULT_RESET;59606061static unsigned short circuit = 0x101;6162···909908 if (frametype != NR_CONNREQ) {910909 /*911910 * Here it would be nice to be able to send a reset but912912- * NET/ROM doesn't have one. The following hack would913913- * have been a way to extend the protocol but apparently914914- * it kills BPQ boxes... :-(911911+ * NET/ROM doesn't have one. We've tried to extend the protocol912912+ * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that913913+ * apparently kills BPQ boxes... :-(914914+ * So now we try to follow the established behaviour of915915+ * G8PZT's Xrouter which is sending packets with command type 7916916+ * as an extension of the protocol.915917 */916916-#if 0917917- /*918918- * Never reply to a CONNACK/CHOKE.919919- */920920- if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)921921- nr_transmit_refusal(skb, 1);922922-#endif918918+ if (sysctl_netrom_reset_circuit &&919919+ (frametype != NR_RESET || flags != 0))920920+ nr_transmit_reset(skb, 1);921921+923922 return 0;924923 }925924···11881187 }1189118811901189 case SIOCGSTAMP:11911191- ret = -EINVAL;11921192- if (sk != NULL)11931193- ret = sock_get_timestamp(sk, argp);11901190+ ret = sock_get_timestamp(sk, argp);11941191 release_sock(sk);11951192 return ret;11961193···13921393 struct net_device *dev;1393139413941395 sprintf(name, "nr%d", i);13951395- dev = alloc_netdev(sizeof(struct net_device_stats), name,13961396- nr_setup);13961396+ dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);13971397 if (!dev) {13981398 printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");13991399 goto fail;
···9898 nr_disconnect(sk, ECONNREFUSED);9999 break;100100101101+ case NR_RESET:102102+ if (sysctl_netrom_reset_circuit);103103+ nr_disconnect(sk, ECONNRESET);104104+ break;105105+101106 default:102107 break;103108 }···127122128123 case NR_DISCACK:129124 nr_disconnect(sk, 0);125125+ break;126126+127127+ case NR_RESET:128128+ if (sysctl_netrom_reset_circuit);129129+ nr_disconnect(sk, ECONNRESET);130130 break;131131132132 default:···262252 nr_start_t2timer(sk);263253 }264254 }255255+ break;256256+257257+ case NR_RESET:258258+ if (sysctl_netrom_reset_circuit);259259+ nr_disconnect(sk, ECONNRESET);265260 break;266261267262 default:
+3-4
net/netrom/nr_subr.c
···210210}211211212212/*213213- * This routine is called when a Connect Acknowledge with the Choke Flag214214- * set is needed to refuse a connection.213213+ * This routine is called to send an error reply.215214 */216216-void nr_transmit_refusal(struct sk_buff *skb, int mine)215215+void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)217216{218217 struct sk_buff *skbn;219218 unsigned char *dptr;···253254 *dptr++ = 0;254255 }255256256256- *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;257257+ *dptr++ = cmdflags;257258 *dptr++ = 0;258259259260 if (!nr_route_frame(skbn, NULL))
···12431243 amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);12441244 if (amount < 0)12451245 amount = 0;12461246- return put_user(amount, (unsigned int __user *)argp);12461246+ return put_user(amount, (unsigned int __user *) argp);12471247 }1248124812491249 case TIOCINQ: {···12521252 /* These two are safe on a single CPU system as only user tasks fiddle here */12531253 if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)12541254 amount = skb->len;12551255- return put_user(amount, (unsigned int __user *)argp);12551255+ return put_user(amount, (unsigned int __user *) argp);12561256 }1257125712581258 case SIOCGSTAMP:12591259- if (sk != NULL) 12601260- return sock_get_timestamp(sk, (struct timeval __user *)argp);12611261- return -EINVAL;12591259+ return sock_get_timestamp(sk, (struct timeval __user *) argp);1262126012631261 case SIOCGIFADDR:12641262 case SIOCSIFADDR: