Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Sep 2005 22:55:09 +0000 (15:55 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 12 Sep 2005 22:55:09 +0000 (15:55 -0700)
37 files changed:
Documentation/connector/cn_test.c [new file with mode: 0644]
Documentation/connector/connector.txt [new file with mode: 0644]
drivers/Kconfig
drivers/Makefile
drivers/connector/Kconfig [new file with mode: 0644]
drivers/connector/Makefile [new file with mode: 0644]
drivers/connector/cn_queue.c [new file with mode: 0644]
drivers/connector/connector.c [new file with mode: 0644]
drivers/net/bnx2.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_epp.c
drivers/net/hamradio/bpqether.c
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/hdlcdrv.c
drivers/net/hamradio/mkiss.c
drivers/net/hamradio/scc.c
drivers/net/hamradio/yam.c
drivers/net/tg3.c
include/linux/connector.h [new file with mode: 0644]
include/linux/netlink.h
include/linux/sysctl.h
include/net/ax25.h
include/net/netrom.h
net/ax25/af_ax25.c
net/ax25/ax25_ip.c
net/core/pktgen.c
net/dccp/ccids/ccid3.c
net/ipv4/ipconfig.c
net/irda/ircomm/ircomm_tty.c
net/netrom/af_netrom.c
net/netrom/nr_dev.c
net/netrom/nr_in.c
net/netrom/nr_subr.c
net/netrom/sysctl_net_netrom.c
net/rose/af_rose.c
net/rose/rose_dev.c
net/sunrpc/svcsock.c

diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
new file mode 100644 (file)
index 0000000..b7de82e
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *     cn_test.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/timer.h>
+
+#include "connector.h"
+
+static struct cb_id cn_test_id = { 0x123, 0x456 };
+static char cn_test_name[] = "cn_test";
+static struct sock *nls;
+static struct timer_list cn_test_timer;
+
+void cn_test_callback(void *data)
+{
+       struct cn_msg *msg = (struct cn_msg *)data;
+
+       printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n",
+              __func__, jiffies, msg->id.idx, msg->id.val,
+              msg->seq, msg->ack, msg->len, (char *)msg->data);
+}
+
+static int cn_test_want_notify(void)
+{
+       struct cn_ctl_msg *ctl;
+       struct cn_notify_req *req;
+       struct cn_msg *msg = NULL;
+       int size, size0;
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       u32 group = 1;
+
+       size0 = sizeof(*msg) + sizeof(*ctl) + 3 * sizeof(*req);
+
+       size = NLMSG_SPACE(size0);
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_ERR "Failed to allocate new skb with size=%u.\n",
+                      size);
+
+               return -ENOMEM;
+       }
+
+       nlh = NLMSG_PUT(skb, 0, 0x123, NLMSG_DONE, size - sizeof(*nlh));
+
+       msg = (struct cn_msg *)NLMSG_DATA(nlh);
+
+       memset(msg, 0, size0);
+
+       msg->id.idx = -1;
+       msg->id.val = -1;
+       msg->seq = 0x123;
+       msg->ack = 0x345;
+       msg->len = size0 - sizeof(*msg);
+
+       ctl = (struct cn_ctl_msg *)(msg + 1);
+
+       ctl->idx_notify_num = 1;
+       ctl->val_notify_num = 2;
+       ctl->group = group;
+       ctl->len = msg->len - sizeof(*ctl);
+
+       req = (struct cn_notify_req *)(ctl + 1);
+
+       /*
+        * Idx.
+        */
+       req->first = cn_test_id.idx;
+       req->range = 10;
+
+       /*
+        * Val 0.
+        */
+       req++;
+       req->first = cn_test_id.val;
+       req->range = 10;
+
+       /*
+        * Val 1.
+        */
+       req++;
+       req->first = cn_test_id.val + 20;
+       req->range = 10;
+
+       NETLINK_CB(skb).dst_groups = ctl->group;
+       //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC);
+       netlink_unicast(nls, skb, 0, 0);
+
+       printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group);
+
+       return 0;
+
+nlmsg_failure:
+       printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack);
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static u32 cn_test_timer_counter;
+static void cn_test_timer_func(unsigned long __data)
+{
+       struct cn_msg *m;
+       char data[32];
+
+       m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
+       if (m) {
+               memset(m, 0, sizeof(*m) + sizeof(data));
+
+               memcpy(&m->id, &cn_test_id, sizeof(m->id));
+               m->seq = cn_test_timer_counter;
+               m->len = sizeof(data);
+
+               m->len =
+                   scnprintf(data, sizeof(data), "counter = %u",
+                             cn_test_timer_counter) + 1;
+
+               memcpy(m + 1, data, m->len);
+
+               cn_netlink_send(m, 0, gfp_any());
+               kfree(m);
+       }
+
+       cn_test_timer_counter++;
+
+       mod_timer(&cn_test_timer, jiffies + HZ);
+}
+
+static int cn_test_init(void)
+{
+       int err;
+
+       err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+       if (err)
+               goto err_out;
+       cn_test_id.val++;
+       err = cn_add_callback(&cn_test_id, cn_test_name, cn_test_callback);
+       if (err) {
+               cn_del_callback(&cn_test_id);
+               goto err_out;
+       }
+
+       init_timer(&cn_test_timer);
+       cn_test_timer.function = cn_test_timer_func;
+       cn_test_timer.expires = jiffies + HZ;
+       cn_test_timer.data = 0;
+       add_timer(&cn_test_timer);
+
+       return 0;
+
+      err_out:
+       if (nls && nls->sk_socket)
+               sock_release(nls->sk_socket);
+
+       return err;
+}
+
+static void cn_test_fini(void)
+{
+       del_timer_sync(&cn_test_timer);
+       cn_del_callback(&cn_test_id);
+       cn_test_id.val--;
+       cn_del_callback(&cn_test_id);
+       if (nls && nls->sk_socket)
+               sock_release(nls->sk_socket);
+}
+
+module_init(cn_test_init);
+module_exit(cn_test_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Connector's test module");
diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt
new file mode 100644 (file)
index 0000000..54a0a14
--- /dev/null
@@ -0,0 +1,133 @@
+/*****************************************/
+Kernel Connector.
+/*****************************************/
+
+Kernel connector - new netlink based userspace <-> kernel space easy
+to use communication module.
+
+Connector driver adds possibility to connect various agents using
+netlink based network.  One must register callback and
+identifier. When driver receives special netlink message with
+appropriate identifier, appropriate callback will be called.
+
+From the userspace point of view it's quite straightforward:
+
+       socket();
+       bind();
+       send();
+       recv();
+
+But if kernelspace want to use full power of such connections, driver
+writer must create special sockets, must know about struct sk_buff
+handling...  Connector allows any kernelspace agents to use netlink
+based networking for inter-process communication in a significantly
+easier way:
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+void cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask);
+
+struct cb_id
+{
+       __u32                   idx;
+       __u32                   val;
+};
+
+idx and val are unique identifiers which must be registered in
+connector.h for in-kernel usage.  void (*callback) (void *) - is a
+callback function which will be called when message with above idx.val
+will be received by connector core.  Argument for that function must
+be dereferenced to struct cn_msg *.
+
+struct cn_msg
+{
+       struct cb_id            id;
+
+       __u32                   seq;
+       __u32                   ack;
+
+       __u32                   len;            /* Length of the following data */
+       __u8                    data[0];
+};
+
+/*****************************************/
+Connector interfaces.
+/*****************************************/
+
+int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *));
+
+Registers new callback with connector core.
+
+struct cb_id *id               - unique connector's user identifier.
+                                 It must be registered in connector.h for legal in-kernel users.
+char *name                     - connector's callback symbolic name.
+void (*callback) (void *)      - connector's callback.
+                                 Argument must be dereferenced to struct cn_msg *.
+
+void cn_del_callback(struct cb_id *id);
+
+Unregisters new callback with connector core.
+
+struct cb_id *id               - unique connector's user identifier.
+
+void cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask);
+
+Sends message to the specified groups.  It can be safely called from
+any context, but may silently fail under strong memory pressure.
+
+struct cn_msg *                        - message header(with attached data).
+u32 __group                    - destination group.
+                                 If __group is zero, then appropriate group will
+                                 be searched through all registered connector users,
+                                 and message will be delivered to the group which was
+                                 created for user with the same ID as in msg.
+                                 If __group is not zero, then message will be delivered
+                                 to the specified group.
+int gfp_mask                   - GFP mask.
+
+Note: When registering new callback user, connector core assigns
+netlink group to the user which is equal to it's id.idx.
+
+/*****************************************/
+Protocol description.
+/*****************************************/
+
+Current offers transport layer with fixed header.  Recommended
+protocol which uses such header is following:
+
+msg->seq and msg->ack are used to determine message genealogy.  When
+someone sends message it puts there locally unique sequence and random
+acknowledge numbers.  Sequence number may be copied into
+nlmsghdr->nlmsg_seq too.
+
+Sequence number is incremented with each message to be sent.
+
+If we expect reply to our message, then sequence number in received
+message MUST be the same as in original message, and acknowledge
+number MUST be the same + 1.
+
+If we receive message and it's sequence number is not equal to one we
+are expecting, then it is new message.  If we receive message and it's
+sequence number is the same as one we are expecting, but it's
+acknowledge is not equal acknowledge number in original message + 1,
+then it is new message.
+
+Obviously, protocol header contains above id.
+
+connector allows event notification in the following form: kernel
+driver or userspace process can ask connector to notify it when
+selected id's will be turned on or off(registered or unregistered it's
+callback). It is done by sending special command to connector
+driver(it also registers itself with id={-1, -1}).
+
+As example of usage Documentation/connector now contains cn_test.c -
+testing module which uses connector to request notification and to
+send messages.
+
+/*****************************************/
+Reliability.
+/*****************************************/
+
+Netlink itself is not reliable protocol, that means that messages can
+be lost due to memory pressure or process' receiving queue overflowed,
+so caller is warned must be prepared. That is why struct cn_msg [main
+connector's message header] contains u32 seq and u32 ack fields.
index 46d655fab1159c54768d08d226ac3bc36a393b2a..48f446d3c671ade5a5198384c729f83118a35033 100644 (file)
@@ -4,6 +4,8 @@ menu "Device Drivers"
 
 source "drivers/base/Kconfig"
 
+source "drivers/connector/Kconfig"
+
 source "drivers/mtd/Kconfig"
 
 source "drivers/parport/Kconfig"
index 86c8654a0ca940d183adb4f945fa757b358e0d48..1a109a6dd953d90c4bb74146ccdbc6699f02a9e4 100644 (file)
@@ -17,6 +17,8 @@ obj-$(CONFIG_PNP)             += pnp/
 # default.
 obj-y                          += char/
 
+obj-$(CONFIG_CONNECTOR)                += connector/
+
 # i810fb and intelfb depend on char/agp/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
new file mode 100644 (file)
index 0000000..0bc2059
--- /dev/null
@@ -0,0 +1,13 @@
+menu "Connector - unified userspace <-> kernelspace linker"
+
+config CONNECTOR
+       tristate "Connector - unified userspace <-> kernelspace linker"
+       depends on NET
+       ---help---
+         This is unified userspace <-> kernelspace connector working on top
+         of the netlink socket protocol.
+
+         Connector support can also be built as a module.  If so, the module
+         will be called cn.ko.
+
+endmenu
diff --git a/drivers/connector/Makefile b/drivers/connector/Makefile
new file mode 100644 (file)
index 0000000..12ca79e
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CONNECTOR)                += cn.o
+
+cn-y                           += cn_queue.o connector.o
diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c
new file mode 100644 (file)
index 0000000..9666321
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ *     cn_queue.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/suspend.h>
+#include <linux/connector.h>
+#include <linux/delay.h>
+
+static void cn_queue_wrapper(void *data)
+{
+       struct cn_callback_entry *cbq = data;
+
+       cbq->cb->callback(cbq->cb->priv);
+       cbq->destruct_data(cbq->ddata);
+       cbq->ddata = NULL;
+}
+
+static struct cn_callback_entry *cn_queue_alloc_callback_entry(struct cn_callback *cb)
+{
+       struct cn_callback_entry *cbq;
+
+       cbq = kzalloc(sizeof(*cbq), GFP_KERNEL);
+       if (!cbq) {
+               printk(KERN_ERR "Failed to create new callback queue.\n");
+               return NULL;
+       }
+
+       cbq->cb = cb;
+       INIT_WORK(&cbq->work, &cn_queue_wrapper, cbq);
+       return cbq;
+}
+
+static void cn_queue_free_callback(struct cn_callback_entry *cbq)
+{
+       cancel_delayed_work(&cbq->work);
+       flush_workqueue(cbq->pdev->cn_queue);
+
+       kfree(cbq);
+}
+
+int cn_cb_equal(struct cb_id *i1, struct cb_id *i2)
+{
+       return ((i1->idx == i2->idx) && (i1->val == i2->val));
+}
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb)
+{
+       struct cn_callback_entry *cbq, *__cbq;
+       int found = 0;
+
+       cbq = cn_queue_alloc_callback_entry(cb);
+       if (!cbq)
+               return -ENOMEM;
+
+       atomic_inc(&dev->refcnt);
+       cbq->pdev = dev;
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry(__cbq, &dev->queue_list, callback_entry) {
+               if (cn_cb_equal(&__cbq->cb->id, &cb->id)) {
+                       found = 1;
+                       break;
+               }
+       }
+       if (!found)
+               list_add_tail(&cbq->callback_entry, &dev->queue_list);
+       spin_unlock_bh(&dev->queue_lock);
+
+       if (found) {
+               atomic_dec(&dev->refcnt);
+               cn_queue_free_callback(cbq);
+               return -EINVAL;
+       }
+
+       cbq->nls = dev->nls;
+       cbq->seq = 0;
+       cbq->group = cbq->cb->id.idx;
+
+       return 0;
+}
+
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id)
+{
+       struct cn_callback_entry *cbq, *n;
+       int found = 0;
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry) {
+               if (cn_cb_equal(&cbq->cb->id, id)) {
+                       list_del(&cbq->callback_entry);
+                       found = 1;
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev->queue_lock);
+
+       if (found) {
+               cn_queue_free_callback(cbq);
+               atomic_dec_and_test(&dev->refcnt);
+       }
+}
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *nls)
+{
+       struct cn_queue_dev *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return NULL;
+
+       snprintf(dev->name, sizeof(dev->name), "%s", name);
+       atomic_set(&dev->refcnt, 0);
+       INIT_LIST_HEAD(&dev->queue_list);
+       spin_lock_init(&dev->queue_lock);
+
+       dev->nls = nls;
+       dev->netlink_groups = 0;
+
+       dev->cn_queue = create_workqueue(dev->name);
+       if (!dev->cn_queue) {
+               kfree(dev);
+               return NULL;
+       }
+
+       return dev;
+}
+
+void cn_queue_free_dev(struct cn_queue_dev *dev)
+{
+       struct cn_callback_entry *cbq, *n;
+
+       flush_workqueue(dev->cn_queue);
+       destroy_workqueue(dev->cn_queue);
+
+       spin_lock_bh(&dev->queue_lock);
+       list_for_each_entry_safe(cbq, n, &dev->queue_list, callback_entry)
+               list_del(&cbq->callback_entry);
+       spin_unlock_bh(&dev->queue_lock);
+
+       while (atomic_read(&dev->refcnt)) {
+               printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
+                      dev->name, atomic_read(&dev->refcnt));
+               msleep(1000);
+       }
+
+       kfree(dev);
+       dev = NULL;
+}
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
new file mode 100644 (file)
index 0000000..aaf6d46
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ *     connector.c
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/moduleparam.h>
+#include <linux/connector.h>
+
+#include <net/sock.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_DESCRIPTION("Generic userspace <-> kernelspace connector.");
+
+static u32 cn_idx = CN_IDX_CONNECTOR;
+static u32 cn_val = CN_VAL_CONNECTOR;
+
+module_param(cn_idx, uint, 0);
+module_param(cn_val, uint, 0);
+MODULE_PARM_DESC(cn_idx, "Connector's main device idx.");
+MODULE_PARM_DESC(cn_val, "Connector's main device val.");
+
+static DECLARE_MUTEX(notify_lock);
+static LIST_HEAD(notify_list);
+
+static struct cn_dev cdev;
+
+int cn_already_initialized = 0;
+
+/*
+ * msg->seq and msg->ack are used to determine message genealogy.
+ * When someone sends message it puts there locally unique sequence
+ * and random acknowledge numbers.  Sequence number may be copied into
+ * nlmsghdr->nlmsg_seq too.
+ *
+ * Sequence number is incremented with each message to be sent.
+ *
+ * If we expect reply to our message then the sequence number in
+ * received message MUST be the same as in original message, and
+ * acknowledge number MUST be the same + 1.
+ *
+ * If we receive a message and its sequence number is not equal to the
+ * one we are expecting then it is a new message.
+ *
+ * If we receive a message and its sequence number is the same as one
+ * we are expecting but it's acknowledgement number is not equal to
+ * the acknowledgement number in the original message + 1, then it is
+ * a new message.
+ *
+ */
+int cn_netlink_send(struct cn_msg *msg, u32 __group, int gfp_mask)
+{
+       struct cn_callback_entry *__cbq;
+       unsigned int size;
+       struct sk_buff *skb;
+       struct nlmsghdr *nlh;
+       struct cn_msg *data;
+       struct cn_dev *dev = &cdev;
+       u32 group = 0;
+       int found = 0;
+
+       if (!__group) {
+               spin_lock_bh(&dev->cbdev->queue_lock);
+               list_for_each_entry(__cbq, &dev->cbdev->queue_list,
+                                   callback_entry) {
+                       if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+                               found = 1;
+                               group = __cbq->group;
+                       }
+               }
+               spin_unlock_bh(&dev->cbdev->queue_lock);
+
+               if (!found)
+                       return -ENODEV;
+       } else {
+               group = __group;
+       }
+
+       size = NLMSG_SPACE(sizeof(*msg) + msg->len);
+
+       skb = alloc_skb(size, gfp_mask);
+       if (!skb)
+               return -ENOMEM;
+
+       nlh = NLMSG_PUT(skb, 0, msg->seq, NLMSG_DONE, size - sizeof(*nlh));
+
+       data = NLMSG_DATA(nlh);
+
+       memcpy(data, msg, sizeof(*data) + msg->len);
+
+       NETLINK_CB(skb).dst_group = group;
+
+       netlink_broadcast(dev->nls, skb, 0, group, gfp_mask);
+
+       return 0;
+
+nlmsg_failure:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+/*
+ * Callback helper - queues work and setup destructor for given data.
+ */
+static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
+{
+       struct cn_callback_entry *__cbq;
+       struct cn_dev *dev = &cdev;
+       int found = 0;
+
+       spin_lock_bh(&dev->cbdev->queue_lock);
+       list_for_each_entry(__cbq, &dev->cbdev->queue_list, callback_entry) {
+               if (cn_cb_equal(&__cbq->cb->id, &msg->id)) {
+                       /*
+                        * Let's scream if there is some magic and the
+                        * data will arrive asynchronously here.
+                        * [i.e. netlink messages will be queued].
+                        * After the first warning I will fix it
+                        * quickly, but now I think it is
+                        * impossible. --zbr (2004_04_27).
+                        */
+                       if (likely(!test_bit(0, &__cbq->work.pending) &&
+                                       __cbq->ddata == NULL)) {
+                               __cbq->cb->priv = msg;
+
+                               __cbq->ddata = data;
+                               __cbq->destruct_data = destruct_data;
+
+                               if (queue_work(dev->cbdev->cn_queue,
+                                               &__cbq->work))
+                                       found = 1;
+                       } else {
+                               printk("%s: cbq->data=%p, "
+                                      "work->pending=%08lx.\n",
+                                      __func__, __cbq->ddata,
+                                      __cbq->work.pending);
+                               WARN_ON(1);
+                       }
+                       break;
+               }
+       }
+       spin_unlock_bh(&dev->cbdev->queue_lock);
+
+       return found ? 0 : -ENODEV;
+}
+
+/*
+ * Skb receive helper - checks skb and msg size and calls callback
+ * helper.
+ */
+static int __cn_rx_skb(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+       u32 pid, uid, seq, group;
+       struct cn_msg *msg;
+
+       pid = NETLINK_CREDS(skb)->pid;
+       uid = NETLINK_CREDS(skb)->uid;
+       seq = nlh->nlmsg_seq;
+       group = NETLINK_CB((skb)).dst_group;
+       msg = NLMSG_DATA(nlh);
+
+       return cn_call_callback(msg, (void (*)(void *))kfree_skb, skb);
+}
+
+/*
+ * Main netlink receiving function.
+ *
+ * It checks skb and netlink header sizes and calls the skb receive
+ * helper with a shared skb.
+ */
+static void cn_rx_skb(struct sk_buff *__skb)
+{
+       struct nlmsghdr *nlh;
+       u32 len;
+       int err;
+       struct sk_buff *skb;
+
+       skb = skb_get(__skb);
+
+       if (skb->len >= NLMSG_SPACE(0)) {
+               nlh = (struct nlmsghdr *)skb->data;
+
+               if (nlh->nlmsg_len < sizeof(struct cn_msg) ||
+                   skb->len < nlh->nlmsg_len ||
+                   nlh->nlmsg_len > CONNECTOR_MAX_MSG_SIZE) {
+                       kfree_skb(skb);
+                       goto out;
+               }
+
+               len = NLMSG_ALIGN(nlh->nlmsg_len);
+               if (len > skb->len)
+                       len = skb->len;
+
+               err = __cn_rx_skb(skb, nlh);
+               if (err < 0)
+                       kfree_skb(skb);
+       }
+
+out:
+       kfree_skb(__skb);
+}
+
+/*
+ * Netlink socket input callback - dequeues the skbs and calls the
+ * main netlink receiving function.
+ */
+static void cn_input(struct sock *sk, int len)
+{
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
+               cn_rx_skb(skb);
+}
+
+/*
+ * Notification routing.
+ *
+ * Gets id and checks if there are notification request for it's idx
+ * and val.  If there are such requests notify the listeners with the
+ * given notify event.
+ *
+ */
+static void cn_notify(struct cb_id *id, u32 notify_event)
+{
+       struct cn_ctl_entry *ent;
+
+       down(&notify_lock);
+       list_for_each_entry(ent, &notify_list, notify_entry) {
+               int i;
+               struct cn_notify_req *req;
+               struct cn_ctl_msg *ctl = ent->msg;
+               int idx_found, val_found;
+
+               idx_found = val_found = 0;
+
+               req = (struct cn_notify_req *)ctl->data;
+               for (i = 0; i < ctl->idx_notify_num; ++i, ++req) {
+                       if (id->idx >= req->first && 
+                                       id->idx < req->first + req->range) {
+                               idx_found = 1;
+                               break;
+                       }
+               }
+
+               for (i = 0; i < ctl->val_notify_num; ++i, ++req) {
+                       if (id->val >= req->first && 
+                                       id->val < req->first + req->range) {
+                               val_found = 1;
+                               break;
+                       }
+               }
+
+               if (idx_found && val_found) {
+                       struct cn_msg m = { .ack = notify_event, };
+
+                       memcpy(&m.id, id, sizeof(m.id));
+                       cn_netlink_send(&m, ctl->group, GFP_KERNEL);
+               }
+       }
+       up(&notify_lock);
+}
+
+/*
+ * Callback add routing - adds callback with given ID and name.
+ * If there is registered callback with the same ID it will not be added.
+ *
+ * May sleep.
+ */
+int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *))
+{
+       int err;
+       struct cn_dev *dev = &cdev;
+       struct cn_callback *cb;
+
+       cb = kzalloc(sizeof(*cb), GFP_KERNEL);
+       if (!cb)
+               return -ENOMEM;
+
+       scnprintf(cb->name, sizeof(cb->name), "%s", name);
+
+       memcpy(&cb->id, id, sizeof(cb->id));
+       cb->callback = callback;
+
+       err = cn_queue_add_callback(dev->cbdev, cb);
+       if (err) {
+               kfree(cb);
+               return err;
+       }
+
+       cn_notify(id, 0);
+
+       return 0;
+}
+
+/*
+ * Callback remove routing - removes callback
+ * with given ID.
+ * If there is no registered callback with given
+ * ID nothing happens.
+ *
+ * May sleep while waiting for reference counter to become zero.
+ */
+void cn_del_callback(struct cb_id *id)
+{
+       struct cn_dev *dev = &cdev;
+
+       cn_queue_del_callback(dev->cbdev, id);
+       cn_notify(id, 1);
+}
+
+/*
+ * Checks two connector's control messages to be the same.
+ * Returns 1 if they are the same or if the first one is corrupted.
+ */
+static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2)
+{
+       int i;
+       struct cn_notify_req *req1, *req2;
+
+       if (m1->idx_notify_num != m2->idx_notify_num)
+               return 0;
+
+       if (m1->val_notify_num != m2->val_notify_num)
+               return 0;
+
+       if (m1->len != m2->len)
+               return 0;
+
+       if ((m1->idx_notify_num + m1->val_notify_num) * sizeof(*req1) !=
+           m1->len)
+               return 1;
+
+       req1 = (struct cn_notify_req *)m1->data;
+       req2 = (struct cn_notify_req *)m2->data;
+
+       for (i = 0; i < m1->idx_notify_num; ++i) {
+               if (req1->first != req2->first || req1->range != req2->range)
+                       return 0;
+               req1++;
+               req2++;
+       }
+
+       for (i = 0; i < m1->val_notify_num; ++i) {
+               if (req1->first != req2->first || req1->range != req2->range)
+                       return 0;
+               req1++;
+               req2++;
+       }
+
+       return 1;
+}
+
+/*
+ * Main connector device's callback.
+ *
+ * Used for notification of a request's processing.
+ */
+static void cn_callback(void *data)
+{
+       struct cn_msg *msg = data;
+       struct cn_ctl_msg *ctl;
+       struct cn_ctl_entry *ent;
+       u32 size;
+
+       if (msg->len < sizeof(*ctl))
+               return;
+
+       ctl = (struct cn_ctl_msg *)msg->data;
+
+       size = (sizeof(*ctl) + ((ctl->idx_notify_num +
+                                ctl->val_notify_num) *
+                               sizeof(struct cn_notify_req)));
+
+       if (msg->len != size)
+               return;
+
+       if (ctl->len + sizeof(*ctl) != msg->len)
+               return;
+
+       /*
+        * Remove notification.
+        */
+       if (ctl->group == 0) {
+               struct cn_ctl_entry *n;
+
+               down(&notify_lock);
+               list_for_each_entry_safe(ent, n, &notify_list, notify_entry) {
+                       if (cn_ctl_msg_equals(ent->msg, ctl)) {
+                               list_del(&ent->notify_entry);
+                               kfree(ent);
+                       }
+               }
+               up(&notify_lock);
+
+               return;
+       }
+
+       size += sizeof(*ent);
+
+       ent = kzalloc(size, GFP_KERNEL);
+       if (!ent)
+               return;
+
+       ent->msg = (struct cn_ctl_msg *)(ent + 1);
+
+       memcpy(ent->msg, ctl, size - sizeof(*ent));
+
+       down(&notify_lock);
+       list_add(&ent->notify_entry, &notify_list);
+       up(&notify_lock);
+}
+
+static int __init cn_init(void)
+{
+       struct cn_dev *dev = &cdev;
+       int err;
+
+       dev->input = cn_input;
+       dev->id.idx = cn_idx;
+       dev->id.val = cn_val;
+
+       dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
+                                        CN_NETLINK_USERS + 0xf,
+                                        dev->input, THIS_MODULE);
+       if (!dev->nls)
+               return -EIO;
+
+       dev->cbdev = cn_queue_alloc_dev("cqueue", dev->nls);
+       if (!dev->cbdev) {
+               if (dev->nls->sk_socket)
+                       sock_release(dev->nls->sk_socket);
+               return -EINVAL;
+       }
+
+       err = cn_add_callback(&dev->id, "connector", &cn_callback);
+       if (err) {
+               cn_queue_free_dev(dev->cbdev);
+               if (dev->nls->sk_socket)
+                       sock_release(dev->nls->sk_socket);
+               return -EINVAL;
+       }
+
+       cn_already_initialized = 1;
+
+       return 0;
+}
+
+static void __exit cn_fini(void)
+{
+       struct cn_dev *dev = &cdev;
+
+       cn_already_initialized = 0;
+
+       cn_del_callback(&dev->id);
+       cn_queue_free_dev(dev->cbdev);
+       if (dev->nls->sk_socket)
+               sock_release(dev->nls->sk_socket);
+}
+
+module_init(cn_init);
+module_exit(cn_fini);
+
+EXPORT_SYMBOL_GPL(cn_add_callback);
+EXPORT_SYMBOL_GPL(cn_del_callback);
+EXPORT_SYMBOL_GPL(cn_netlink_send);
index 83598e32179cee8c1f81b851e37c67f8fc736f87..3a2ace01e444d082daaa31dc30de97c542d19054 100644 (file)
@@ -5015,6 +5015,7 @@ static struct ethtool_ops bnx2_ethtool_ops = {
        .phys_id                = bnx2_phys_id,
        .get_stats_count        = bnx2_get_stats_count,
        .get_ethtool_stats      = bnx2_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 /* Called with rtnl_lock */
@@ -5442,6 +5443,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_drvdata(pdev, dev);
 
        memcpy(dev->dev_addr, bp->mac_addr, 6);
+       memcpy(dev->perm_addr, bp->mac_addr, 6);
        bp->name = board_info[ent->driver_data].name,
        printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
                "IRQ %d, ",
index 0b230222bfeab592fa23ec7836accddc79df7a62..90999867a32c56fd6819acee43ef1934984b061d 100644 (file)
@@ -293,7 +293,7 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev,
 {
 #ifdef CONFIG_INET
        if (type != htons(ETH_P_AX25))
-               return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+               return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
 }
index 5298096afbdb6efc7a9031ec2d746a0e3438772f..e4188d082f011f0e0fa56080db7d8f9ca9913fc0 100644 (file)
@@ -40,7 +40,7 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
+#include <linux/crc-ccitt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/workqueue.h>
 #include <linux/fs.h>
 #include <linux/parport.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
 #include <linux/if_arp.h>
-#include <linux/kmod.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
 #include <linux/jiffies.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-#include <linux/crc-ccitt.h>
+#include <asm/uaccess.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -1177,13 +1171,8 @@ static void baycom_probe(struct net_device *dev)
        /* Fill in the fields of the device structure */
        bc->skb = NULL;
        
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->set_mac_address = baycom_set_mac_address;
        
        dev->type = ARPHRD_AX25;           /* AF_AX25 device */
index 2946e037a9b1f1e4bab304c2982a0575bf07c69d..1756f0ed54ccc7a43de7613896f090d38c98f365 100644 (file)
@@ -488,7 +488,7 @@ static void bpq_setup(struct net_device *dev)
        dev->flags      = 0;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header     = ax25_encapsulate;
+       dev->hard_header     = ax25_hard_header;
        dev->rebuild_header  = ax25_rebuild_header;
 #endif
 
index f515245a3fd0997f049aaa626ba8af0300b2ad9d..3be3f916643a17fcb53574f83cf39d8c8ae5bb9e 100644 (file)
@@ -449,12 +449,12 @@ module_exit(dmascc_exit);
 static void dev_setup(struct net_device *dev)
 {
        dev->type = ARPHRD_AX25;
-       dev->hard_header_len = 73;
+       dev->hard_header_len = AX25_MAX_HEADER_LEN;
        dev->mtu = 1500;
-       dev->addr_len = 7;
+       dev->addr_len = AX25_ADDR_LEN;
        dev->tx_queue_len = 64;
-       memcpy(dev->broadcast, ax25_broadcast, 7);
-       memcpy(dev->dev_addr, ax25_test, 7);
+       memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
 }
 
 static int __init setup_adapter(int card_base, int type, int n)
@@ -600,7 +600,7 @@ static int __init setup_adapter(int card_base, int type, int n)
                dev->do_ioctl = scc_ioctl;
                dev->hard_start_xmit = scc_send_packet;
                dev->get_stats = scc_get_stats;
-               dev->hard_header = ax25_encapsulate;
+               dev->hard_header = ax25_hard_header;
                dev->rebuild_header = ax25_rebuild_header;
                dev->set_mac_address = scc_set_mac_address;
        }
index b4c836e4fe860d4a4e7fe0d82a52736dd7432f2c..dacc7687b97f8b2bfe3290ede1cd6137c5ed08d9 100644 (file)
@@ -42,7 +42,6 @@
 
 /*****************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/net.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
-#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-#include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/hdlcdrv.h>
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h> 
+#include <asm/uaccess.h>
 
-/* make genksyms happy */
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
 #include <linux/crc-ccitt.h>
 
 /* --------------------------------------------------------------------- */
@@ -708,13 +701,8 @@ static void hdlcdrv_setup(struct net_device *dev)
 
        s->skb = NULL;
        
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
        dev->set_mac_address = hdlcdrv_set_mac_address;
        
        dev->type = ARPHRD_AX25;           /* AF_AX25 device */
index 63b1a2b86acb19650fdee9e84efb2e86e7971bed..d9fe64b46f4bf4bc1505bee23f2e8e92c86fa772 100644 (file)
@@ -500,7 +500,7 @@ static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short
 {
 #ifdef CONFIG_INET
        if (type != htons(ETH_P_AX25))
-               return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+               return ax25_hard_header(skb, dev, type, daddr, saddr, len);
 #endif
        return 0;
 }
index c27e417f32bf5958e322d4277dc7a808c2777284..6ace0e914fd1f2705a00609d23df8e07f44941dd 100644 (file)
@@ -1557,7 +1557,7 @@ static void scc_net_setup(struct net_device *dev)
        dev->stop            = scc_net_close;
 
        dev->hard_start_xmit = scc_net_tx;
-       dev->hard_header     = ax25_encapsulate;
+       dev->hard_header     = ax25_hard_header;
        dev->rebuild_header  = ax25_rebuild_header;
        dev->set_mac_address = scc_net_set_mac_address;
        dev->get_stats       = scc_net_get_stats;
index f52ee3162c51dc29f2ac586be3dfc610fe3363ee..fe22479eb2028097213e5f987a1768e453477fc3 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-/* prototypes for ax25_encapsulate and ax25_rebuild_header */
 #include <net/ax25.h>
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-
-/* make genksyms happy */
-#include <linux/ip.h>
-#include <linux/udp.h>
-#include <linux/tcp.h>
 
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
@@ -1116,23 +1108,17 @@ static void yam_setup(struct net_device *dev)
 
        skb_queue_head_init(&yp->send_queue);
 
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-       dev->hard_header = ax25_encapsulate;
+       dev->hard_header = ax25_hard_header;
        dev->rebuild_header = ax25_rebuild_header;
-#else                                                  /* CONFIG_AX25 || CONFIG_AX25_MODULE */
-       dev->hard_header = NULL;
-       dev->rebuild_header = NULL;
-#endif                                                 /* CONFIG_AX25 || CONFIG_AX25_MODULE */
 
        dev->set_mac_address = yam_set_mac_address;
 
-       dev->type = ARPHRD_AX25;        /* AF_AX25 device */
-       dev->hard_header_len = 73;      /* We do digipeaters now */
-       dev->mtu = 256;                         /* AX25 is the default */
-       dev->addr_len = 7;                      /* sizeof an ax.25 address */
-       memcpy(dev->broadcast, ax25_bcast, 7);
-       memcpy(dev->dev_addr, ax25_test, 7);
-
+       dev->type = ARPHRD_AX25;
+       dev->hard_header_len = AX25_MAX_HEADER_LEN;
+       dev->mtu = AX25_MTU;
+       dev->addr_len = AX25_ADDR_LEN;
+       memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+       memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
 }
 
 static int __init yam_init_driver(void)
index dc57352e5a974e8f7c64433e71cda98728ac5d0b..7599f52e15b3ca65abd356ce4e13d424e064a21c 100644 (file)
@@ -6893,8 +6893,7 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
                get_stat64(&hw_stats->tx_octets);
 
        stats->rx_errors = old_stats->rx_errors +
-               get_stat64(&hw_stats->rx_errors) +
-               get_stat64(&hw_stats->rx_discards);
+               get_stat64(&hw_stats->rx_errors);
        stats->tx_errors = old_stats->tx_errors +
                get_stat64(&hw_stats->tx_errors) +
                get_stat64(&hw_stats->tx_mac_errors) +
@@ -6922,6 +6921,9 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
        stats->rx_crc_errors = old_stats->rx_crc_errors +
                calc_crc_errors(tp);
 
+       stats->rx_missed_errors = old_stats->rx_missed_errors +
+               get_stat64(&hw_stats->rx_discards);
+
        return stats;
 }
 
@@ -8303,6 +8305,7 @@ static struct ethtool_ops tg3_ethtool_ops = {
        .get_ethtool_stats      = tg3_get_ethtool_stats,
        .get_coalesce           = tg3_get_coalesce,
        .set_coalesce           = tg3_set_coalesce,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
 };
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9781,6 +9784,7 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
                if (prom_getproplen(node, "local-mac-address") == 6) {
                        prom_getproperty(node, "local-mac-address",
                                         dev->dev_addr, 6);
+                       memcpy(dev->perm_addr, dev->dev_addr, 6);
                        return 0;
                }
        }
@@ -9792,6 +9796,7 @@ static int __devinit tg3_get_default_macaddr_sparc(struct tg3 *tp)
        struct net_device *dev = tp->dev;
 
        memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+       memcpy(dev->perm_addr, idprom->id_ethaddr, 6);
        return 0;
 }
 #endif
@@ -9861,6 +9866,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
 #endif
                return -EINVAL;
        }
+       memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        return 0;
 }
 
diff --git a/include/linux/connector.h b/include/linux/connector.h
new file mode 100644 (file)
index 0000000..96de263
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ *     connector.h
+ * 
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * All rights reserved.
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CONNECTOR_H
+#define __CONNECTOR_H
+
+#include <asm/types.h>
+
+#define CN_IDX_CONNECTOR               0xffffffff
+#define CN_VAL_CONNECTOR               0xffffffff
+
+#define CN_NETLINK_USERS               1
+
+/*
+ * Maximum connector's message size.
+ */
+#define CONNECTOR_MAX_MSG_SIZE         1024
+
+/*
+ * idx and val are unique identifiers which 
+ * are used for message routing and 
+ * must be registered in connector.h for in-kernel usage.
+ */
+
+struct cb_id {
+       __u32 idx;
+       __u32 val;
+};
+
+struct cn_msg {
+       struct cb_id id;
+
+       __u32 seq;
+       __u32 ack;
+
+       __u16 len;              /* Length of the following data */
+       __u16 flags;
+       __u8 data[0];
+};
+
+/*
+ * Notify structure - requests notification about
+ * registering/unregistering idx/val in range [first, first+range].
+ */
+struct cn_notify_req {
+       __u32 first;
+       __u32 range;
+};
+
+/*
+ * Main notification control message
+ * *_notify_num        - number of appropriate cn_notify_req structures after 
+ *                             this struct.
+ * group               - notification receiver's idx.
+ * len                         - total length of the attached data.
+ */
+struct cn_ctl_msg {
+       __u32 idx_notify_num;
+       __u32 val_notify_num;
+       __u32 group;
+       __u32 len;
+       __u8 data[0];
+};
+
+#ifdef __KERNEL__
+
+#include <asm/atomic.h>
+
+#include <linux/list.h>
+#include <linux/workqueue.h>
+
+#include <net/sock.h>
+
+#define CN_CBQ_NAMELEN         32
+
+struct cn_queue_dev {
+       atomic_t refcnt;
+       unsigned char name[CN_CBQ_NAMELEN];
+
+       struct workqueue_struct *cn_queue;
+
+       struct list_head queue_list;
+       spinlock_t queue_lock;
+
+       int netlink_groups;
+       struct sock *nls;
+};
+
+struct cn_callback {
+       unsigned char name[CN_CBQ_NAMELEN];
+
+       struct cb_id id;
+       void (*callback) (void *);
+       void *priv;
+};
+
+struct cn_callback_entry {
+       struct list_head callback_entry;
+       struct cn_callback *cb;
+       struct work_struct work;
+       struct cn_queue_dev *pdev;
+
+       void (*destruct_data) (void *);
+       void *ddata;
+
+       int seq, group;
+       struct sock *nls;
+};
+
+struct cn_ctl_entry {
+       struct list_head notify_entry;
+       struct cn_ctl_msg *msg;
+};
+
+struct cn_dev {
+       struct cb_id id;
+
+       u32 seq, groups;
+       struct sock *nls;
+       void (*input) (struct sock * sk, int len);
+
+       struct cn_queue_dev *cbdev;
+};
+
+int cn_add_callback(struct cb_id *, char *, void (*callback) (void *));
+void cn_del_callback(struct cb_id *);
+int cn_netlink_send(struct cn_msg *, u32, int);
+
+int cn_queue_add_callback(struct cn_queue_dev *dev, struct cn_callback *cb);
+void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id);
+
+struct cn_queue_dev *cn_queue_alloc_dev(char *name, struct sock *);
+void cn_queue_free_dev(struct cn_queue_dev *dev);
+
+int cn_cb_equal(struct cb_id *, struct cb_id *);
+
+extern int cn_already_initialized;
+
+#endif                         /* __KERNEL__ */
+#endif                         /* __CONNECTOR_H */
index 1675186689361370861897bd7b12a1003c9e5af3..7bbd25970c9ebfb4a5a73ef1b555082e748e6752 100644 (file)
@@ -15,6 +15,7 @@
 #define NETLINK_ISCSI          8       /* Open-iSCSI */
 #define NETLINK_AUDIT          9       /* auditing */
 #define NETLINK_FIB_LOOKUP     10      
+#define NETLINK_CONNECTOR      11
 #define NETLINK_NETFILTER      12      /* netfilter subsystem */
 #define NETLINK_IP6_FW         13
 #define NETLINK_DNRTMSG                14      /* DECnet routing messages */
index 532a6c5c24e9cc105b30accf34f4a6e792967988..3a29a9f9b451d7f3b0e6135ff7d4fcc0fa886027 100644 (file)
@@ -544,7 +544,8 @@ enum {
        NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8,
        NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9,
        NET_NETROM_ROUTING_CONTROL=10,
-       NET_NETROM_LINK_FAILS_COUNT=11
+       NET_NETROM_LINK_FAILS_COUNT=11,
+       NET_NETROM_RESET=12
 };
 
 /* /proc/sys/net/ax25 */
index 227d3378decd8cf86d8467652f6e9ebc9e3daec5..9dbcd9e51c00a33d1502824929468ce6a9e594c2 100644 (file)
 
 /* AX.25 Protocol IDs */
 #define AX25_P_ROSE                    0x01
-#define AX25_P_IP                      0xCC
-#define AX25_P_ARP                     0xCD
-#define AX25_P_TEXT                    0xF0
-#define AX25_P_NETROM                  0xCF
-#define        AX25_P_SEGMENT                  0x08
+#define AX25_P_VJCOMP                  0x06    /* Compressed TCP/IP packet   */
+                                               /* Van Jacobsen (RFC 1144)    */
+#define AX25_P_VJUNCOMP                        0x07    /* Uncompressed TCP/IP packet */
+                                               /* Van Jacobsen (RFC 1144)    */
+#define        AX25_P_SEGMENT                  0x08    /* Segmentation fragment      */
+#define AX25_P_TEXNET                  0xc3    /* TEXTNET datagram protocol  */
+#define AX25_P_LQ                      0xc4    /* Link Quality Protocol      */
+#define AX25_P_ATALK                   0xca    /* Appletalk                  */
+#define AX25_P_ATALK_ARP               0xcb    /* Appletalk ARP              */
+#define AX25_P_IP                      0xcc    /* ARPA Internet Protocol     */
+#define AX25_P_ARP                     0xcd    /* ARPA Adress Resolution     */
+#define AX25_P_FLEXNET                 0xce    /* FlexNet                    */
+#define AX25_P_NETROM                  0xcf    /* NET/ROM                    */
+#define AX25_P_TEXT                    0xF0    /* No layer 3 protocol impl.  */
 
 /* AX.25 Segment control values */
 #define        AX25_SEG_REM                    0x7F
 /* Define Link State constants. */
 
 enum { 
-       AX25_STATE_0,
-       AX25_STATE_1,
-       AX25_STATE_2,
-       AX25_STATE_3,
-       AX25_STATE_4
+       AX25_STATE_0,                   /* Listening */
+       AX25_STATE_1,                   /* SABM sent */
+       AX25_STATE_2,                   /* DISC sent */
+       AX25_STATE_3,                   /* Established */
+       AX25_STATE_4                    /* Recovery */
 };
 
 #define AX25_MODULUS           8       /*  Standard AX.25 modulus */
@@ -319,7 +328,7 @@ extern int  ax25_rx_iframe(ax25_cb *, struct sk_buff *);
 extern int  ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
 /* ax25_ip.c */
-extern int  ax25_encapsulate(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
+extern int  ax25_hard_header(struct sk_buff *, struct net_device *, unsigned short, void *, void *, unsigned int);
 extern int  ax25_rebuild_header(struct sk_buff *);
 
 /* ax25_out.c */
index 45f2c7616d8b8566e690aedbdecb66db9ccea9d3..a6bf6e0f606aed23ac8a8b4a2583bc5d7d6a8d19 100644 (file)
@@ -6,6 +6,7 @@
 
 #ifndef _NETROM_H
 #define _NETROM_H 
+
 #include <linux/netrom.h>
 #include <linux/list.h>
 #include <net/sock.h>
@@ -22,6 +23,7 @@
 #define        NR_DISCACK                      0x04
 #define        NR_INFO                         0x05
 #define        NR_INFOACK                      0x06
+#define        NR_RESET                        0x07
 
 #define        NR_CHOKE_FLAG                   0x80
 #define        NR_NAK_FLAG                     0x40
@@ -51,11 +53,16 @@ enum {
 #define        NR_DEFAULT_TTL                  16              /* Default Time To Live - 16 */
 #define        NR_DEFAULT_ROUTING              1               /* Is routing enabled ? */
 #define        NR_DEFAULT_FAILS                2               /* Link fails until route fails */
+#define        NR_DEFAULT_RESET                0               /* Sent / accept reset cmds? */
 
 #define NR_MODULUS                     256
 #define NR_MAX_WINDOW_SIZE             127                     /* Maximum Window Allowable - 127 */
 #define        NR_MAX_PACKET_SIZE              236                     /* Maximum Packet Length - 236 */
 
+struct nr_private {
+       struct net_device_stats stats;
+};
+
 struct nr_sock {
        struct sock             sock;
        ax25_address            user_addr, source_addr, dest_addr;
@@ -176,6 +183,8 @@ extern int  sysctl_netrom_transport_requested_window_size;
 extern int  sysctl_netrom_transport_no_activity_timeout;
 extern int  sysctl_netrom_routing_control;
 extern int  sysctl_netrom_link_fails_count;
+extern int  sysctl_netrom_reset_circuit;
+
 extern int  nr_rx_frame(struct sk_buff *, struct net_device *);
 extern void nr_destroy_socket(struct sock *);
 
@@ -218,7 +227,28 @@ extern void nr_requeue_frames(struct sock *);
 extern int  nr_validate_nr(struct sock *, unsigned short);
 extern int  nr_in_rx_window(struct sock *, unsigned short);
 extern void nr_write_internal(struct sock *, int);
-extern void nr_transmit_refusal(struct sk_buff *, int);
+
+extern void __nr_transmit_reply(struct sk_buff *skb, int mine,
+       unsigned char cmdflags);
+
+/*
+ * This routine is called when a Connect Acknowledge with the Choke Flag
+ * set is needed to refuse a connection.
+ */
+#define nr_transmit_refusal(skb, mine)                                 \
+do {                                                                   \
+       __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \
+} while (0)
+
+/*
+ * This routine is called when we don't have a circuit matching an incoming
+ * NET/ROM packet.  This is an G8PZT Xrouter extension.
+ */
+#define nr_transmit_reset(skb, mine)                                   \
+do {                                                                   \
+       __nr_transmit_reply((skb), (mine), NR_RESET);                   \
+} while (0)
+
 extern void nr_disconnect(struct sock *, int);
 
 /* nr_timer.c */
index ed705ddad56be0e9bb6b69580b681b1e5c91f6d0..8e37e71e34ff1929aef5a8b8efb2ef362dec6b54 100644 (file)
@@ -1695,16 +1695,12 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                /* These two are safe on a single CPU system as only user tasks fiddle here */
                if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                        amount = skb->len;
-               res = put_user(amount, (int __user *)argp);
+               res = put_user(amount, (int __user *) argp);
                break;
        }
 
        case SIOCGSTAMP:
-               if (sk != NULL) {
-                       res = sock_get_timestamp(sk, argp);
-                       break;
-               }
-               res = -EINVAL;
+               res = sock_get_timestamp(sk, argp);
                break;
 
        case SIOCAX25ADDUID:    /* Add a uid to the uid/call map table */
@@ -1951,24 +1947,24 @@ static struct net_proto_family ax25_family_ops = {
 };
 
 static struct proto_ops ax25_proto_ops = {
-       .family =       PF_AX25,
-       .owner =        THIS_MODULE,
-       .release =      ax25_release,
-       .bind =         ax25_bind,
-       .connect =      ax25_connect,
-       .socketpair =   sock_no_socketpair,
-       .accept =       ax25_accept,
-       .getname =      ax25_getname,
-       .poll =         datagram_poll,
-       .ioctl =        ax25_ioctl,
-       .listen =       ax25_listen,
-       .shutdown =     ax25_shutdown,
-       .setsockopt =   ax25_setsockopt,
-       .getsockopt =   ax25_getsockopt,
-       .sendmsg =      ax25_sendmsg,
-       .recvmsg =      ax25_recvmsg,
-       .mmap =         sock_no_mmap,
-       .sendpage =     sock_no_sendpage,
+       .family         = PF_AX25,
+       .owner          = THIS_MODULE,
+       .release        = ax25_release,
+       .bind           = ax25_bind,
+       .connect        = ax25_connect,
+       .socketpair     = sock_no_socketpair,
+       .accept         = ax25_accept,
+       .getname        = ax25_getname,
+       .poll           = datagram_poll,
+       .ioctl          = ax25_ioctl,
+       .listen         = ax25_listen,
+       .shutdown       = ax25_shutdown,
+       .setsockopt     = ax25_setsockopt,
+       .getsockopt     = ax25_getsockopt,
+       .sendmsg        = ax25_sendmsg,
+       .recvmsg        = ax25_recvmsg,
+       .mmap           = sock_no_mmap,
+       .sendpage       = sock_no_sendpage,
 };
 
 /*
@@ -1984,7 +1980,7 @@ static struct notifier_block ax25_dev_notifier = {
        .notifier_call =ax25_device_event,
 };
 
-EXPORT_SYMBOL(ax25_encapsulate);
+EXPORT_SYMBOL(ax25_hard_header);
 EXPORT_SYMBOL(ax25_rebuild_header);
 EXPORT_SYMBOL(ax25_findbyuid);
 EXPORT_SYMBOL(ax25_find_cb);
index bba0173e2d6500a44954871389fc5e35396dffa2..d643dac3eccc6981b8d56b1a9c1ba20fa3b5bcf4 100644 (file)
@@ -47,7 +47,7 @@
 
 #ifdef CONFIG_INET
 
-int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
 {
        unsigned char *buff;
 
@@ -88,7 +88,7 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
                *buff++ = AX25_P_ARP;
                break;
        default:
-               printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
+               printk(KERN_ERR "AX.25: ax25_hard_header - wrong protocol type 0x%2.2x\n", type);
                *buff++ = 0;
                break;
        }
@@ -209,7 +209,7 @@ put:
 
 #else  /* INET */
 
-int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
+int ax25_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len)
 {
        return -AX25_HEADER_LEN;
 }
index b3ad49fa7d787ad7d8a01feb7a1a62f3faaa0bd9..ef430b1e8e42acc87af3d12fb4c95544c8996570 100644 (file)
@@ -1452,8 +1452,7 @@ static int proc_thread_write(struct file *file, const char __user *user_buffer,
                thread_lock();
                t->control |= T_REMDEV;
                thread_unlock();
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(HZ/8);  /* Propagate thread->control  */
+               schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
                ret = count;
                 sprintf(pg_result, "OK: rem_device_all");
                goto out;
@@ -1716,10 +1715,9 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
        while (now < spin_until_us) {
                /* TODO: optimise sleeping behavior */
-               if (spin_until_us - now > (1000000/HZ)+1) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(1);
-               } else if (spin_until_us - now > 100) {
+               if (spin_until_us - now > jiffies_to_usecs(1)+1)
+                       schedule_timeout_interruptible(1);
+               else if (spin_until_us - now > 100) {
                        do_softirq();
                        if (!pkt_dev->running)
                                return;
@@ -2449,8 +2447,7 @@ static void pktgen_run_all_threads(void)
        }
        thread_unlock();
 
-       current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(HZ/8);  /* Propagate thread->control  */
+       schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
                        
        pktgen_wait_all_threads_run();
 }
index e05f4f955eeee8d0bd68eae5ccfab3bc674bec8b..38aa84986118564379043c462b19e832f8342933 100644 (file)
@@ -1095,6 +1095,10 @@ static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
 
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return;
+
        BUG_ON(hcrx == NULL);
 
        info->tcpi_ca_state     = hcrx->ccid3hcrx_state;
@@ -1106,6 +1110,10 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
 {
        const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
 
+       /* Listen socks doesn't have a private CCID block */
+       if (sk->sk_state == DCCP_LISTEN)
+               return;
+
        BUG_ON(hctx == NULL);
 
        info->tcpi_rto = hctx->ccid3hctx_t_rto;
index 953129d392d21cc97f551f93c519b491cb0190cc..e8674baaa8d99034ee0d56a7fdbdfc66d205abf6 100644 (file)
@@ -1103,10 +1103,8 @@ static int __init ic_dynamic(void)
 #endif
 
                jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
-               while (time_before(jiffies, jiff) && !ic_got_reply) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
-               }
+               while (time_before(jiffies, jiff) && !ic_got_reply)
+                       schedule_timeout_uninterruptible(1);
 #ifdef IPCONFIG_DHCP
                /* DHCP isn't done until we get a DHCPACK. */
                if ((ic_got_reply & IC_BOOTP)
index 5d1e61168eb72d77c18f9fa278fa8a92516577f0..6f20b4206e08a56bc3b79902b9fededeac826cd9 100644 (file)
@@ -567,10 +567,8 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
        self->tty = NULL;
 
        if (self->blocked_open) {
-               if (self->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(self->close_delay);
-               }
+               if (self->close_delay)
+                       schedule_timeout_interruptible(self->close_delay);
                wake_up_interruptible(&self->open_wait);
        }
 
@@ -863,8 +861,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
        spin_lock_irqsave(&self->spinlock, flags);
        while (self->tx_skb && self->tx_skb->len) {
                spin_unlock_irqrestore(&self->spinlock, flags);
-               current->state = TASK_INTERRUPTIBLE;
-               schedule_timeout(poll_time);
+               schedule_timeout_interruptible(poll_time);
                spin_lock_irqsave(&self->spinlock, flags);
                if (signal_pending(current))
                        break;
index f4578c759ffcc3350ebbd708c7f0a2ffef52c587..e5d82d711cae2ea36e1e36e652fdeebd0b5db591 100644 (file)
@@ -56,6 +56,7 @@ int sysctl_netrom_transport_requested_window_size = NR_DEFAULT_WINDOW;
 int sysctl_netrom_transport_no_activity_timeout   = NR_DEFAULT_IDLE;
 int sysctl_netrom_routing_control                 = NR_DEFAULT_ROUTING;
 int sysctl_netrom_link_fails_count                = NR_DEFAULT_FAILS;
+int sysctl_netrom_reset_circuit                   = NR_DEFAULT_RESET;
 
 static unsigned short circuit = 0x101;
 
@@ -908,17 +909,17 @@ int nr_rx_frame(struct sk_buff *skb, struct net_device *dev)
        if (frametype != NR_CONNREQ) {
                /*
                 * Here it would be nice to be able to send a reset but
-                * NET/ROM doesn't have one. The following hack would
-                * have been a way to extend the protocol but apparently
-                * it kills BPQ boxes... :-(
+                * NET/ROM doesn't have one.  We've tried to extend the protocol
+                * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that
+                * apparently kills BPQ boxes... :-(
+                * So now we try to follow the established behaviour of
+                * G8PZT's Xrouter which is sending packets with command type 7
+                * as an extension of the protocol.
                 */
-#if 0
-               /*
-                * Never reply to a CONNACK/CHOKE.
-                */
-               if (frametype != NR_CONNACK || flags != NR_CHOKE_FLAG)
-                       nr_transmit_refusal(skb, 1);
-#endif
+               if (sysctl_netrom_reset_circuit &&
+                   (frametype != NR_RESET || flags != 0))
+                       nr_transmit_reset(skb, 1);
+
                return 0;
        }
 
@@ -1187,9 +1188,7 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
        }
 
        case SIOCGSTAMP:
-               ret = -EINVAL;
-               if (sk != NULL)
-                       ret = sock_get_timestamp(sk, argp);
+               ret = sock_get_timestamp(sk, argp);
                release_sock(sk);
                return ret;
 
@@ -1393,8 +1392,7 @@ static int __init nr_proto_init(void)
                struct net_device *dev;
 
                sprintf(name, "nr%d", i);
-               dev = alloc_netdev(sizeof(struct net_device_stats), name,
-                                         nr_setup);
+               dev = alloc_netdev(sizeof(struct nr_private), name, nr_setup);
                if (!dev) {
                        printk(KERN_ERR "NET/ROM: nr_proto_init - unable to allocate device structure\n");
                        goto fail;
index 263da4c26494cb2cf875d22b75ca773be770c8b8..4e66eef9a03479f0ead803fabdfb3d1f73e0b18f 100644 (file)
@@ -47,7 +47,7 @@ int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
        struct net_device_stats *stats = netdev_priv(dev);
 
        if (!netif_running(dev)) {
-               stats->rx_errors++;
+               stats->rx_dropped++;
                return 0;
        }
 
@@ -71,15 +71,10 @@ int nr_rx_ip(struct sk_buff *skb, struct net_device *dev)
 
 static int nr_rebuild_header(struct sk_buff *skb)
 {
-       struct net_device *dev = skb->dev;
-       struct net_device_stats *stats = netdev_priv(dev);
-       struct sk_buff *skbn;
        unsigned char *bp = skb->data;
-       int len;
 
-       if (arp_find(bp + 7, skb)) {
+       if (arp_find(bp + 7, skb))
                return 1;
-       }
 
        bp[6] &= ~AX25_CBIT;
        bp[6] &= ~AX25_EBIT;
@@ -90,27 +85,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
        bp[6] |= AX25_EBIT;
        bp[6] |= AX25_SSSID_SPARE;
 
-       if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-               kfree_skb(skb);
-               return 1;
-       }
-
-       if (skb->sk != NULL)
-               skb_set_owner_w(skbn, skb->sk);
-
-       kfree_skb(skb);
-
-       len = skbn->len;
-
-       if (!nr_route_frame(skbn, NULL)) {
-               kfree_skb(skbn);
-               stats->tx_errors++;
-       }
-
-       stats->tx_packets++;
-       stats->tx_bytes += len;
-
-       return 1;
+       return 0;
 }
 
 #else
@@ -185,15 +160,27 @@ static int nr_close(struct net_device *dev)
 
 static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       struct net_device_stats *stats = netdev_priv(dev);
-       dev_kfree_skb(skb);
-       stats->tx_errors++;
+       struct nr_private *nr = netdev_priv(dev);
+       struct net_device_stats *stats = &nr->stats;
+       unsigned int len = skb->len;
+
+       if (!nr_route_frame(skb, NULL)) {
+               kfree_skb(skb);
+               stats->tx_errors++;
+               return 0;
+       }
+
+       stats->tx_packets++;
+       stats->tx_bytes += len;
+
        return 0;
 }
 
 static struct net_device_stats *nr_get_stats(struct net_device *dev)
 {
-       return netdev_priv(dev);
+       struct nr_private *nr = netdev_priv(dev);
+
+       return &nr->stats;
 }
 
 void nr_setup(struct net_device *dev)
@@ -208,12 +195,11 @@ void nr_setup(struct net_device *dev)
        dev->hard_header_len    = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
        dev->addr_len           = AX25_ADDR_LEN;
        dev->type               = ARPHRD_NETROM;
-       dev->tx_queue_len       = 40;
        dev->rebuild_header     = nr_rebuild_header;
        dev->set_mac_address    = nr_set_mac_address;
 
        /* New-style flags. */
-       dev->flags              = 0;
+       dev->flags              = IFF_NOARP;
 
        dev->get_stats          = nr_get_stats;
 }
index 64b81a7969077c706353e76309a67698380f2095..004e8599b8fe595f5b72c92b0b51bb203b99a44d 100644 (file)
@@ -98,6 +98,11 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
                nr_disconnect(sk, ECONNREFUSED);
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
@@ -124,6 +129,11 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
                nr_disconnect(sk, 0);
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
@@ -254,6 +264,11 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
                }
                break;
 
+       case NR_RESET:
+               if (sysctl_netrom_reset_circuit);
+                       nr_disconnect(sk, ECONNRESET);
+               break;
+
        default:
                break;
        }
index 587bed2674bfb4dcb09e40f13ae0d33b8342e053..bcb9946b4f5628f59276cfed1082c33135d95119 100644 (file)
@@ -210,10 +210,9 @@ void nr_write_internal(struct sock *sk, int frametype)
 }
 
 /*
- * This routine is called when a Connect Acknowledge with the Choke Flag
- * set is needed to refuse a connection.
+ * This routine is called to send an error reply.
  */
-void nr_transmit_refusal(struct sk_buff *skb, int mine)
+void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags)
 {
        struct sk_buff *skbn;
        unsigned char *dptr;
@@ -254,7 +253,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
                *dptr++ = 0;
        }
 
-       *dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
+       *dptr++ = cmdflags;
        *dptr++ = 0;
 
        if (!nr_route_frame(skbn, NULL))
index c9ed50382ea7bb067766173207bafbade894f984..6bb8dda849dc71d1de1bd13ca8942eb6d607316f 100644 (file)
@@ -30,6 +30,7 @@ static int min_idle[]    = {0 * HZ};
 static int max_idle[]    = {65535 * HZ};
 static int min_route[]   = {0}, max_route[]   = {1};
 static int min_fails[]   = {1}, max_fails[]   = {10};
+static int min_reset[]   = {0}, max_reset[]   = {1};
 
 static struct ctl_table_header *nr_table_header;
 
@@ -155,6 +156,17 @@ static ctl_table nr_table[] = {
                .extra1         = &min_fails,
                .extra2         = &max_fails
        },
+        {
+               .ctl_name       = NET_NETROM_RESET,
+               .procname       = "reset",
+               .data           = &sysctl_netrom_reset_circuit,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &min_reset,
+               .extra2         = &max_reset
+       },
        { .ctl_name = 0 }
 };
 
index 3077878ed4f09fdc1a9a1bcf0b1303084f098641..5acb1680524ab5a3ae381b2a741fabd0219f8bc1 100644 (file)
@@ -1243,7 +1243,7 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
                if (amount < 0)
                        amount = 0;
-               return put_user(amount, (unsigned int __user *)argp);
+               return put_user(amount, (unsigned int __user *) argp);
        }
 
        case TIOCINQ: {
@@ -1252,13 +1252,11 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
                /* These two are safe on a single CPU system as only user tasks fiddle here */
                if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                        amount = skb->len;
-               return put_user(amount, (unsigned int __user *)argp);
+               return put_user(amount, (unsigned int __user *) argp);
        }
 
        case SIOCGSTAMP:
-               if (sk != NULL) 
-                       return sock_get_timestamp(sk, (struct timeval __user *)argp);
-               return -EINVAL;
+               return sock_get_timestamp(sk, (struct timeval __user *) argp);
 
        case SIOCGIFADDR:
        case SIOCSIFADDR:
index a8ed9a1d09f9efe2dee89d08893bad4d892bd836..d297af737d1023a41c88f028a8628d91e52bc3eb 100644 (file)
@@ -149,6 +149,6 @@ void rose_setup(struct net_device *dev)
        dev->set_mac_address    = rose_set_mac_address;
 
        /* New-style flags. */
-       dev->flags              = 0;
+       dev->flags              = IFF_NOARP;
        dev->get_stats = rose_get_stats;
 }
index 05fe2e735538e15999a5b018f19b5c8474573dc7..51885b5f744e938eaa71ffcb8617759469a68f7b 100644 (file)
@@ -1170,8 +1170,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
        while (rqstp->rq_arghi < pages) {
                struct page *p = alloc_page(GFP_KERNEL);
                if (!p) {
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(HZ/2);
+                       schedule_timeout_uninterruptible(msecs_to_jiffies(500));
                        continue;
                }
                rqstp->rq_argpages[rqstp->rq_arghi++] = p;