提交 61b22e69 编写于 作者: L Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

/*
* 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");
/*****************************************/
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.
......@@ -4,6 +4,8 @@ menu "Device Drivers"
source "drivers/base/Kconfig"
source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -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/
......
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
obj-$(CONFIG_CONNECTOR) += cn.o
cn-y += cn_queue.o connector.o
/*
* 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;
}
/*
* 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);
......@@ -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, ",
......
......@@ -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;
}
......
......@@ -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>
......@@ -48,18 +48,12 @@
#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 */
......
......@@ -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
......
......@@ -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;
}
......
......@@ -42,7 +42,6 @@
/*****************************************************************************/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/net.h>
......@@ -52,20 +51,14 @@
#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 */
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -60,15 +60,7 @@
#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)
......
......@@ -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;
}
......
/*
* 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 */
......@@ -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 */
......
......@@ -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 */
......
......@@ -26,11 +26,20 @@
/* 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
......@@ -88,11 +97,11 @@
/* 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 */
......
......@@ -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 */
......
......@@ -1695,17 +1695,13 @@ 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;
break;
case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
......@@ -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);
......
......@@ -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 @@ int ax25_rebuild_header(struct sk_buff *skb)
#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;
}
......
......@@ -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();
}
......
......@@ -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;
......
......@@ -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)
......
......@@ -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;
......
......@@ -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,8 +1188,6 @@ 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);
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;
......
......@@ -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);
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;
}
......@@ -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;
}
......
......@@ -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))
......
......@@ -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 }
};
......
......@@ -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:
......
......@@ -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;
}
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册