summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/atm/clip.c2
-rw-r--r--net/ax25/af_ax25.c93
-rw-r--r--net/ax25/ax25_addr.c9
-rw-r--r--net/ax25/ax25_ds_timer.c3
-rw-r--r--net/ax25/ax25_iface.c13
-rw-r--r--net/ax25/ax25_ip.c3
-rw-r--r--net/ax25/ax25_out.c3
-rw-r--r--net/ax25/ax25_route.c2
-rw-r--r--net/ax25/ax25_timer.c3
-rw-r--r--net/ax25/ax25_uid.c4
-rw-r--r--net/ax25/sysctl_net_ax25.c10
-rw-r--r--net/bridge/br_if.c21
-rw-r--r--net/bridge/br_input.c1
-rw-r--r--net/core/dev.c99
-rw-r--r--net/core/link_watch.c10
-rw-r--r--net/core/neighbour.c21
-rw-r--r--net/core/net-sysfs.c49
-rw-r--r--net/dccp/proto.c13
-rw-r--r--net/decnet/dn_neigh.c5
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c17
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c16
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c4
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c8
-rw-r--r--net/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c10
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c6
-rw-r--r--net/ipv4/tcp.c13
-rw-r--r--net/ipv4/tcp_highspeed.c2
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/irda/irias_object.c3
-rw-r--r--net/netfilter/x_tables.c4
-rw-r--r--net/netrom/af_netrom.c18
-rw-r--r--net/netrom/nr_dev.c1
-rw-r--r--net/rose/af_rose.c13
-rw-r--r--net/rose/rose_dev.c1
-rw-r--r--net/rose/rose_link.c6
-rw-r--r--net/rose/rose_route.c7
-rw-r--r--net/sched/sch_hfsc.c6
-rw-r--r--net/sctp/inqueue.c1
-rw-r--r--net/sctp/sm_statefuns.c59
-rw-r--r--net/sctp/sm_statetable.c10
-rw-r--r--net/sctp/ulpqueue.c27
45 files changed, 352 insertions, 254 deletions
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 1a786bfaa416..72d852982664 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -963,7 +963,7 @@ static struct file_operations arp_seq_fops = {
static int __init atm_clip_init(void)
{
struct proc_dir_entry *p;
- neigh_table_init(&clip_tbl);
+ neigh_table_init_no_netlink(&clip_tbl);
clip_tbl_hook = &clip_tbl;
register_atm_ioctl(&clip_ioctl_ops);
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index dbf9b47681f7..a2e0dd047e9f 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -228,6 +228,8 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
return NULL;
}
+EXPORT_SYMBOL(ax25_find_cb);
+
void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
{
ax25_cb *s;
@@ -424,6 +426,26 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
return 0;
}
+static void ax25_fillin_cb_from_dev(ax25_cb *ax25, ax25_dev *ax25_dev)
+{
+ ax25->rtt = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]) / 2;
+ ax25->t1 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T1]);
+ ax25->t2 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T2]);
+ ax25->t3 = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_T3]);
+ ax25->n2 = ax25_dev->values[AX25_VALUES_N2];
+ ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN];
+ ax25->idle = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_IDLE]);
+ ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF];
+
+ if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) {
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
+ } else {
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
+ }
+}
+
/*
* Fill in a created AX.25 created control block with the default
* values for a particular device.
@@ -433,39 +455,28 @@ void ax25_fillin_cb(ax25_cb *ax25, ax25_dev *ax25_dev)
ax25->ax25_dev = ax25_dev;
if (ax25->ax25_dev != NULL) {
- ax25->rtt = ax25_dev->values[AX25_VALUES_T1] / 2;
- ax25->t1 = ax25_dev->values[AX25_VALUES_T1];
- ax25->t2 = ax25_dev->values[AX25_VALUES_T2];
- ax25->t3 = ax25_dev->values[AX25_VALUES_T3];
- ax25->n2 = ax25_dev->values[AX25_VALUES_N2];
- ax25->paclen = ax25_dev->values[AX25_VALUES_PACLEN];
- ax25->idle = ax25_dev->values[AX25_VALUES_IDLE];
- ax25->backoff = ax25_dev->values[AX25_VALUES_BACKOFF];
-
- if (ax25_dev->values[AX25_VALUES_AXDEFMODE]) {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_EWINDOW];
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25_dev->values[AX25_VALUES_WINDOW];
- }
+ ax25_fillin_cb_from_dev(ax25, ax25_dev);
+ return;
+ }
+
+ /*
+ * No device, use kernel / AX.25 spec default values
+ */
+ ax25->rtt = msecs_to_jiffies(AX25_DEF_T1) / 2;
+ ax25->t1 = msecs_to_jiffies(AX25_DEF_T1);
+ ax25->t2 = msecs_to_jiffies(AX25_DEF_T2);
+ ax25->t3 = msecs_to_jiffies(AX25_DEF_T3);
+ ax25->n2 = AX25_DEF_N2;
+ ax25->paclen = AX25_DEF_PACLEN;
+ ax25->idle = msecs_to_jiffies(AX25_DEF_IDLE);
+ ax25->backoff = AX25_DEF_BACKOFF;
+
+ if (AX25_DEF_AXDEFMODE) {
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = AX25_DEF_EWINDOW;
} else {
- ax25->rtt = AX25_DEF_T1 / 2;
- ax25->t1 = AX25_DEF_T1;
- ax25->t2 = AX25_DEF_T2;
- ax25->t3 = AX25_DEF_T3;
- ax25->n2 = AX25_DEF_N2;
- ax25->paclen = AX25_DEF_PACLEN;
- ax25->idle = AX25_DEF_IDLE;
- ax25->backoff = AX25_DEF_BACKOFF;
-
- if (AX25_DEF_AXDEFMODE) {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = AX25_DEF_EWINDOW;
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = AX25_DEF_WINDOW;
- }
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = AX25_DEF_WINDOW;
}
}
@@ -1979,24 +1990,6 @@ static struct notifier_block ax25_dev_notifier = {
.notifier_call =ax25_device_event,
};
-EXPORT_SYMBOL(ax25_hard_header);
-EXPORT_SYMBOL(ax25_rebuild_header);
-EXPORT_SYMBOL(ax25_findbyuid);
-EXPORT_SYMBOL(ax25_find_cb);
-EXPORT_SYMBOL(ax25_linkfail_register);
-EXPORT_SYMBOL(ax25_linkfail_release);
-EXPORT_SYMBOL(ax25_listen_register);
-EXPORT_SYMBOL(ax25_listen_release);
-EXPORT_SYMBOL(ax25_protocol_register);
-EXPORT_SYMBOL(ax25_protocol_release);
-EXPORT_SYMBOL(ax25_send_frame);
-EXPORT_SYMBOL(ax25_uid_policy);
-EXPORT_SYMBOL(ax25cmp);
-EXPORT_SYMBOL(ax2asc);
-EXPORT_SYMBOL(asc2ax);
-EXPORT_SYMBOL(null_ax25_address);
-EXPORT_SYMBOL(ax25_display_timer);
-
static int __init ax25_init(void)
{
int rc = proto_register(&ax25_proto, 0);
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 0164a155b8c4..5f0896ad0042 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -11,6 +11,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
@@ -33,6 +34,8 @@
*/
ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
+EXPORT_SYMBOL(null_ax25_address);
+
/*
* ax25 -> ascii conversion
*/
@@ -64,6 +67,8 @@ char *ax2asc(char *buf, ax25_address *a)
}
+EXPORT_SYMBOL(ax2asc);
+
/*
* ascii -> ax25 conversion
*/
@@ -97,6 +102,8 @@ void asc2ax(ax25_address *addr, char *callsign)
addr->ax25_call[6] &= 0x1E;
}
+EXPORT_SYMBOL(asc2ax);
+
/*
* Compare two ax.25 addresses
*/
@@ -116,6 +123,8 @@ int ax25cmp(ax25_address *a, ax25_address *b)
return 2; /* Partial match */
}
+EXPORT_SYMBOL(ax25cmp);
+
/*
* Compare two AX.25 digipeater paths.
*/
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
index 061083efc1dc..5961459935eb 100644
--- a/net/ax25/ax25_ds_timer.c
+++ b/net/ax25/ax25_ds_timer.c
@@ -61,7 +61,8 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev)
return;
del_timer(&ax25_dev->dama.slave_timer);
- ax25_dev->dama.slave_timeout = ax25_dev->values[AX25_VALUES_DS_TIMEOUT] / 10;
+ ax25_dev->dama.slave_timeout =
+ msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10;
ax25_ds_add_timer(ax25_dev);
}
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index d68aff100729..3bb152710b77 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -12,6 +12,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
@@ -74,6 +75,8 @@ int ax25_protocol_register(unsigned int pid,
return 1;
}
+EXPORT_SYMBOL(ax25_protocol_register);
+
void ax25_protocol_release(unsigned int pid)
{
struct protocol_struct *s, *protocol;
@@ -106,6 +109,8 @@ void ax25_protocol_release(unsigned int pid)
write_unlock(&protocol_list_lock);
}
+EXPORT_SYMBOL(ax25_protocol_release);
+
int ax25_linkfail_register(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *linkfail;
@@ -123,6 +128,8 @@ int ax25_linkfail_register(void (*func)(ax25_cb *, int))
return 1;
}
+EXPORT_SYMBOL(ax25_linkfail_register);
+
void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *s, *linkfail;
@@ -155,6 +162,8 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
spin_unlock_bh(&linkfail_lock);
}
+EXPORT_SYMBOL(ax25_linkfail_release);
+
int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
{
struct listen_struct *listen;
@@ -176,6 +185,8 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
return 1;
}
+EXPORT_SYMBOL(ax25_listen_register);
+
void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
{
struct listen_struct *s, *listen;
@@ -208,6 +219,8 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
spin_unlock_bh(&listen_lock);
}
+EXPORT_SYMBOL(ax25_listen_release);
+
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{
int (*res)(struct sk_buff *, ax25_cb *) = NULL;
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index d643dac3eccc..a0b534f80f17 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -12,6 +12,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
@@ -221,3 +222,5 @@ int ax25_rebuild_header(struct sk_buff *skb)
#endif
+EXPORT_SYMBOL(ax25_hard_header);
+EXPORT_SYMBOL(ax25_rebuild_header);
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index 5fc048dcd39a..5d99852b239c 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -14,6 +14,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
@@ -104,6 +105,8 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
return ax25; /* We had to create it */
}
+EXPORT_SYMBOL(ax25_send_frame);
+
/*
* All outgoing AX.25 I frames pass via this routine. Therefore this is
* where the fragmentation of frames takes place. If fragment is set to
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index f04f8630fd28..5ac98250797b 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -360,7 +360,7 @@ struct file_operations ax25_route_fops = {
/*
* Find AX.25 route
*
- * Only routes with a refernce rout of zero can be destroyed.
+ * Only routes with a reference count of zero can be destroyed.
*/
static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
index 7a6b50a14554..ec254057f212 100644
--- a/net/ax25/ax25_timer.c
+++ b/net/ax25/ax25_timer.c
@@ -18,6 +18,7 @@
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#include <linux/string.h>
@@ -137,6 +138,8 @@ unsigned long ax25_display_timer(struct timer_list *timer)
return timer->expires - jiffies;
}
+EXPORT_SYMBOL(ax25_display_timer);
+
static void ax25_heartbeat_expiry(unsigned long param)
{
int proto = AX25_PROTO_STD_SIMPLEX;
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index b8b5854bce9a..5e9a81e8b214 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -49,6 +49,8 @@ static DEFINE_RWLOCK(ax25_uid_lock);
int ax25_uid_policy = 0;
+EXPORT_SYMBOL(ax25_uid_policy);
+
ax25_uid_assoc *ax25_findbyuid(uid_t uid)
{
ax25_uid_assoc *ax25_uid, *res = NULL;
@@ -67,6 +69,8 @@ ax25_uid_assoc *ax25_findbyuid(uid_t uid)
return res;
}
+EXPORT_SYMBOL(ax25_findbyuid);
+
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{
ax25_uid_assoc *ax25_uid;
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index 894a22558d9d..bdb64c36df12 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -18,14 +18,14 @@ static int min_backoff[1], max_backoff[] = {2};
static int min_conmode[1], max_conmode[] = {2};
static int min_window[] = {1}, max_window[] = {7};
static int min_ewindow[] = {1}, max_ewindow[] = {63};
-static int min_t1[] = {1}, max_t1[] = {30 * HZ};
-static int min_t2[] = {1}, max_t2[] = {20 * HZ};
-static int min_t3[1], max_t3[] = {3600 * HZ};
-static int min_idle[1], max_idle[] = {65535 * HZ};
+static int min_t1[] = {1}, max_t1[] = {30000};
+static int min_t2[] = {1}, max_t2[] = {20000};
+static int min_t3[1], max_t3[] = {3600000};
+static int min_idle[1], max_idle[] = {65535000};
static int min_n2[] = {1}, max_n2[] = {31};
static int min_paclen[] = {1}, max_paclen[] = {512};
static int min_proto[1], max_proto[] = { AX25_PROTO_MAX };
-static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ};
+static int min_ds_timeout[1], max_ds_timeout[] = {65535000};
static struct ctl_table_header *ax25_table_header;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 59eef42d4a42..ad1c7af65ec8 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -308,26 +308,19 @@ int br_add_bridge(const char *name)
if (ret)
goto err2;
- /* network device kobject is not setup until
- * after rtnl_unlock does it's hotplug magic.
- * so hold reference to avoid race.
- */
- dev_hold(dev);
- rtnl_unlock();
-
ret = br_sysfs_addbr(dev);
- dev_put(dev);
-
- if (ret)
- unregister_netdev(dev);
- out:
- return ret;
+ if (ret)
+ goto err3;
+ rtnl_unlock();
+ return 0;
+ err3:
+ unregister_netdev(dev);
err2:
free_netdev(dev);
err1:
rtnl_unlock();
- goto out;
+ return ret;
}
int br_del_bridge(const char *name)
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index b0b7f55c1edd..bfa4d8c333f7 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -66,6 +66,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
}
if (is_multicast_ether_addr(dest)) {
+ br->statistics.multicast++;
br_flood_forward(br, skb, !passedup);
if (!passedup)
br_pass_frame_up(br, skb);
diff --git a/net/core/dev.c b/net/core/dev.c
index 3bad1afc89fa..2dce673a039b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -193,7 +193,7 @@ static inline struct hlist_head *dev_index_hash(int ifindex)
* Our notifier list
*/
-static BLOCKING_NOTIFIER_HEAD(netdev_chain);
+static RAW_NOTIFIER_HEAD(netdev_chain);
/*
* Device drivers call our routines to queue packets here. We empty the
@@ -736,7 +736,7 @@ int dev_change_name(struct net_device *dev, char *newname)
if (!err) {
hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGENAME, dev);
}
@@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname)
*/
void netdev_features_change(struct net_device *dev)
{
- blocking_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev);
}
EXPORT_SYMBOL(netdev_features_change);
@@ -766,7 +766,7 @@ EXPORT_SYMBOL(netdev_features_change);
void netdev_state_change(struct net_device *dev)
{
if (dev->flags & IFF_UP) {
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGE, dev);
rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
}
@@ -864,7 +864,7 @@ int dev_open(struct net_device *dev)
/*
* ... and announce new interface.
*/
- blocking_notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
}
return ret;
}
@@ -887,7 +887,7 @@ int dev_close(struct net_device *dev)
* Tell people we are going down, so that they can
* prepare to death, when device is still operating.
*/
- blocking_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_GOING_DOWN, dev);
dev_deactivate(dev);
@@ -924,7 +924,7 @@ int dev_close(struct net_device *dev)
/*
* Tell people we are down
*/
- blocking_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
return 0;
}
@@ -955,7 +955,7 @@ int register_netdevice_notifier(struct notifier_block *nb)
int err;
rtnl_lock();
- err = blocking_notifier_chain_register(&netdev_chain, nb);
+ err = raw_notifier_chain_register(&netdev_chain, nb);
if (!err) {
for (dev = dev_base; dev; dev = dev->next) {
nb->notifier_call(nb, NETDEV_REGISTER, dev);
@@ -983,7 +983,7 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
int err;
rtnl_lock();
- err = blocking_notifier_chain_unregister(&netdev_chain, nb);
+ err = raw_notifier_chain_unregister(&netdev_chain, nb);
rtnl_unlock();
return err;
}
@@ -994,12 +994,12 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
* @v: pointer passed unmodified to notifier function
*
* Call all network notifier blocks. Parameters and return value
- * are as for blocking_notifier_call_chain().
+ * are as for raw_notifier_call_chain().
*/
int call_netdevice_notifiers(unsigned long val, void *v)
{
- return blocking_notifier_call_chain(&netdev_chain, val, v);
+ return raw_notifier_call_chain(&netdev_chain, val, v);
}
/* When > 0 there are consumers of rx skb time stamps */
@@ -2308,7 +2308,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
if (dev->flags & IFF_UP &&
((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
IFF_VOLATILE)))
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGE, dev);
if ((flags ^ dev->gflags) & IFF_PROMISC) {
@@ -2353,7 +2353,7 @@ int dev_set_mtu(struct net_device *dev, int new_mtu)
else
dev->mtu = new_mtu;
if (!err && dev->flags & IFF_UP)
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGEMTU, dev);
return err;
}
@@ -2370,7 +2370,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
return -ENODEV;
err = dev->set_mac_address(dev, sa);
if (!err)
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGEADDR, dev);
return err;
}
@@ -2427,7 +2427,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
return -EINVAL;
memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len));
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_CHANGEADDR, dev);
return 0;
@@ -2777,6 +2777,8 @@ int register_netdevice(struct net_device *dev)
BUG_ON(dev_boot_phase);
ASSERT_RTNL();
+ might_sleep();
+
/* When net_device's are persistent, this will be fatal. */
BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
@@ -2863,6 +2865,11 @@ int register_netdevice(struct net_device *dev)
if (!dev->rebuild_header)
dev->rebuild_header = default_rebuild_header;
+ ret = netdev_register_sysfs(dev);
+ if (ret)
+ goto out_err;
+ dev->reg_state = NETREG_REGISTERED;
+
/*
* Default initial state at registry is that the
* device is present.
@@ -2878,14 +2885,11 @@ int register_netdevice(struct net_device *dev)
hlist_add_head(&dev->name_hlist, head);
hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
dev_hold(dev);
- dev->reg_state = NETREG_REGISTERING;
write_unlock_bh(&dev_base_lock);
/* Notify protocols, that a new device appeared. */
- blocking_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
- /* Finish registration after unlock */
- net_set_todo(dev);
ret = 0;
out:
@@ -2961,7 +2965,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
rtnl_lock();
/* Rebroadcast unregister notification */
- blocking_notifier_call_chain(&netdev_chain,
+ raw_notifier_call_chain(&netdev_chain,
NETDEV_UNREGISTER, dev);
if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
@@ -3008,7 +3012,7 @@ static void netdev_wait_allrefs(struct net_device *dev)
*
* We are invoked by rtnl_unlock() after it drops the semaphore.
* This allows us to deal with problems:
- * 1) We can create/delete sysfs objects which invoke hotplug
+ * 1) We can delete sysfs objects which invoke hotplug
* without deadlocking with linkwatch via keventd.
* 2) Since we run with the RTNL semaphore not held, we can sleep
* safely in order to wait for the netdev refcnt to drop to zero.
@@ -3017,8 +3021,6 @@ static DEFINE_MUTEX(net_todo_run_mutex);
void netdev_run_todo(void)
{
struct list_head list = LIST_HEAD_INIT(list);
- int err;
-
/* Need to guard against multiple cpu's getting out of order. */
mutex_lock(&net_todo_run_mutex);
@@ -3041,40 +3043,29 @@ void netdev_run_todo(void)
= list_entry(list.next, struct net_device, todo_list);
list_del(&dev->todo_list);
- switch(dev->reg_state) {
- case NETREG_REGISTERING:
- dev->reg_state = NETREG_REGISTERED;
- err = netdev_register_sysfs(dev);
- if (err)
- printk(KERN_ERR "%s: failed sysfs registration (%d)\n",
- dev->name, err);
- break;
-
- case NETREG_UNREGISTERING:
- netdev_unregister_sysfs(dev);
- dev->reg_state = NETREG_UNREGISTERED;
-
- netdev_wait_allrefs(dev);
+ if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) {
+ printk(KERN_ERR "network todo '%s' but state %d\n",
+ dev->name, dev->reg_state);
+ dump_stack();
+ continue;
+ }
- /* paranoia */
- BUG_ON(atomic_read(&dev->refcnt));
- BUG_TRAP(!dev->ip_ptr);
- BUG_TRAP(!dev->ip6_ptr);
- BUG_TRAP(!dev->dn_ptr);
+ netdev_unregister_sysfs(dev);
+ dev->reg_state = NETREG_UNREGISTERED;
+ netdev_wait_allrefs(dev);
- /* It must be the very last action,
- * after this 'dev' may point to freed up memory.
- */
- if (dev->destructor)
- dev->destructor(dev);
- break;
+ /* paranoia */
+ BUG_ON(atomic_read(&dev->refcnt));
+ BUG_TRAP(!dev->ip_ptr);
+ BUG_TRAP(!dev->ip6_ptr);
+ BUG_TRAP(!dev->dn_ptr);
- default:
- printk(KERN_ERR "network todo '%s' but state %d\n",
- dev->name, dev->reg_state);
- break;
- }
+ /* It must be the very last action,
+ * after this 'dev' may point to freed up memory.
+ */
+ if (dev->destructor)
+ dev->destructor(dev);
}
out:
@@ -3216,7 +3207,7 @@ int unregister_netdevice(struct net_device *dev)
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
*/
- blocking_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+ raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
/*
* Flush the multicast chain
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index 341de44c7ed1..646937cc2d84 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -170,13 +170,13 @@ void linkwatch_fire_event(struct net_device *dev)
spin_unlock_irqrestore(&lweventlist_lock, flags);
if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) {
- unsigned long thisevent = jiffies;
+ unsigned long delay = linkwatch_nextevent - jiffies;
- if (thisevent >= linkwatch_nextevent) {
+ /* If we wrap around we'll delay it by at most HZ. */
+ if (!delay || delay > HZ)
schedule_work(&linkwatch_work);
- } else {
- schedule_delayed_work(&linkwatch_work, linkwatch_nextevent - thisevent);
- }
+ else
+ schedule_delayed_work(&linkwatch_work, delay);
}
}
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 4cf878efdb49..50a8c73caf97 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1326,8 +1326,7 @@ void neigh_parms_destroy(struct neigh_parms *parms)
kfree(parms);
}
-
-void neigh_table_init(struct neigh_table *tbl)
+void neigh_table_init_no_netlink(struct neigh_table *tbl)
{
unsigned long now = jiffies;
unsigned long phsize;
@@ -1383,10 +1382,27 @@ void neigh_table_init(struct neigh_table *tbl)
tbl->last_flush = now;
tbl->last_rand = now + tbl->parms.reachable_time * 20;
+}
+
+void neigh_table_init(struct neigh_table *tbl)
+{
+ struct neigh_table *tmp;
+
+ neigh_table_init_no_netlink(tbl);
write_lock(&neigh_tbl_lock);
+ for (tmp = neigh_tables; tmp; tmp = tmp->next) {
+ if (tmp->family == tbl->family)
+ break;
+ }
tbl->next = neigh_tables;
neigh_tables = tbl;
write_unlock(&neigh_tbl_lock);
+
+ if (unlikely(tmp)) {
+ printk(KERN_ERR "NEIGH: Registering multiple tables for "
+ "family %d\n", tbl->family);
+ dump_stack();
+ }
}
int neigh_table_clear(struct neigh_table *tbl)
@@ -2657,6 +2673,7 @@ EXPORT_SYMBOL(neigh_rand_reach_time);
EXPORT_SYMBOL(neigh_resolve_output);
EXPORT_SYMBOL(neigh_table_clear);
EXPORT_SYMBOL(neigh_table_init);
+EXPORT_SYMBOL(neigh_table_init_no_netlink);
EXPORT_SYMBOL(neigh_update);
EXPORT_SYMBOL(neigh_update_hhs);
EXPORT_SYMBOL(pneigh_enqueue);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index c12990c9c603..47a6fceb6771 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -29,7 +29,7 @@ static const char fmt_ulong[] = "%lu\n";
static inline int dev_isalive(const struct net_device *dev)
{
- return dev->reg_state == NETREG_REGISTERED;
+ return dev->reg_state <= NETREG_REGISTERED;
}
/* use same locking rules as GIF* ioctl's */
@@ -445,58 +445,33 @@ static struct class net_class = {
void netdev_unregister_sysfs(struct net_device * net)
{
- struct class_device * class_dev = &(net->class_dev);
-
- if (net->get_stats)
- sysfs_remove_group(&class_dev->kobj, &netstat_group);
-
-#ifdef WIRELESS_EXT
- if (net->get_wireless_stats || (net->wireless_handlers &&
- net->wireless_handlers->get_wireless_stats))
- sysfs_remove_group(&class_dev->kobj, &wireless_group);
-#endif
- class_device_del(class_dev);
-
+ class_device_del(&(net->class_dev));
}
/* Create sysfs entries for network device. */
int netdev_register_sysfs(struct net_device *net)
{
struct class_device *class_dev = &(net->class_dev);
- int ret;
+ struct attribute_group **groups = net->sysfs_groups;
+ class_device_initialize(class_dev);
class_dev->class = &net_class;
class_dev->class_data = net;
+ class_dev->groups = groups;
+ BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
- if ((ret = class_device_register(class_dev)))
- goto out;
- if (net->get_stats &&
- (ret = sysfs_create_group(&class_dev->kobj, &netstat_group)))
- goto out_unreg;
+ if (net->get_stats)
+ *groups++ = &netstat_group;
#ifdef WIRELESS_EXT
- if (net->get_wireless_stats || (net->wireless_handlers &&
- net->wireless_handlers->get_wireless_stats)) {
- ret = sysfs_create_group(&class_dev->kobj, &wireless_group);
- if (ret)
- goto out_cleanup;
- }
- return 0;
-out_cleanup:
- if (net->get_stats)
- sysfs_remove_group(&class_dev->kobj, &netstat_group);
-#else
- return 0;
+ if (net->get_wireless_stats
+ || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats))
+ *groups++ = &wireless_group;
#endif
-out_unreg:
- printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n",
- net->name, ret);
- class_device_unregister(class_dev);
-out:
- return ret;
+ return class_device_add(class_dev);
}
int netdev_sysfs_init(void)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 1ff7328b0e17..2e0ee8355c41 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -848,6 +848,7 @@ static int dccp_close_state(struct sock *sk)
void dccp_close(struct sock *sk, long timeout)
{
struct sk_buff *skb;
+ int state;
lock_sock(sk);
@@ -882,6 +883,11 @@ void dccp_close(struct sock *sk, long timeout)
sk_stream_wait_close(sk, timeout);
adjudge_to_death:
+ state = sk->sk_state;
+ sock_hold(sk);
+ sock_orphan(sk);
+ atomic_inc(sk->sk_prot->orphan_count);
+
/*
* It is the last release_sock in its life. It will remove backlog.
*/
@@ -894,8 +900,9 @@ adjudge_to_death:
bh_lock_sock(sk);
BUG_TRAP(!sock_owned_by_user(sk));
- sock_hold(sk);
- sock_orphan(sk);
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != DCCP_CLOSED && sk->sk_state == DCCP_CLOSED)
+ goto out;
/*
* The last release_sock may have processed the CLOSE or RESET
@@ -915,12 +922,12 @@ adjudge_to_death:
#endif
}
- atomic_inc(sk->sk_prot->orphan_count);
if (sk->sk_state == DCCP_CLOSED)
inet_csk_destroy_sock(sk);
/* Otherwise, socket is reprieved until protocol close. */
+out:
bh_unlock_sock(sk);
local_bh_enable();
sock_put(sk);
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 7c8692c26bfe..66e230c3b328 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -493,7 +493,6 @@ struct elist_cb_state {
static void neigh_elist_cb(struct neighbour *neigh, void *_info)
{
struct elist_cb_state *s = _info;
- struct dn_dev *dn_db;
struct dn_neigh *dn;
if (neigh->dev != s->dev)
@@ -503,10 +502,6 @@ static void neigh_elist_cb(struct neighbour *neigh, void *_info)
if (!(dn->flags & (DN_NDFLAG_R1|DN_NDFLAG_R2)))
return;
- dn_db = (struct dn_dev *) s->dev->dn_ptr;
- if (dn_db->parms.forwarding == 1 && (dn->flags & DN_NDFLAG_R2))
- return;
-
if (s->t == s->n)
s->rs = dn_find_slot(s->ptr, s->n, dn->priority);
else
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index fb79ce7d6439..57ea9f6f465c 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -51,11 +51,12 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 1;
mac->associated = 0; /* just to make sure */
- spin_unlock_irqrestore(&mac->lock, flags);
/* Set a timer for timeout */
/* FIXME: make timeout configurable */
- schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ);
+ if (likely(mac->running))
+ schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ);
+ spin_unlock_irqrestore(&mac->lock, flags);
}
void
@@ -319,6 +320,9 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
u16 status = le16_to_cpup(&resp->status);
struct ieee80211softmac_network *network = NULL;
unsigned long flags;
+
+ if (unlikely(!mac->running))
+ return -ENODEV;
spin_lock_irqsave(&mac->lock, flags);
@@ -377,10 +381,16 @@ ieee80211softmac_handle_disassoc(struct net_device * dev,
{
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
unsigned long flags;
+
+ if (unlikely(!mac->running))
+ return -ENODEV;
+
if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
return 0;
+
if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
return 0;
+
dprintk(KERN_INFO PFX "got disassoc frame\n");
netif_carrier_off(dev);
spin_lock_irqsave(&mac->lock, flags);
@@ -400,6 +410,9 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211softmac_network *network;
+ if (unlikely(!mac->running))
+ return -ENODEV;
+
network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
if (!network) {
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 9a0eac6c61eb..06e332624665 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -86,6 +86,11 @@ ieee80211softmac_auth_queue(void *data)
/* Lock and set flags */
spin_lock_irqsave(&mac->lock, flags);
+ if (unlikely(!mac->running)) {
+ /* Prevent reschedule on workqueue flush */
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return;
+ }
net->authenticated = 0;
net->authenticating = 1;
/* add a timeout call so we eventually give up waiting for an auth reply */
@@ -124,6 +129,9 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
unsigned long flags;
u8 * data;
+ if (unlikely(!mac->running))
+ return -ENODEV;
+
/* Find correct auth queue item */
spin_lock_irqsave(&mac->lock, flags);
list_for_each(list_ptr, &mac->auth_queue) {
@@ -298,8 +306,6 @@ ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
/* can't transmit data right now... */
netif_carrier_off(mac->dev);
- /* let's try to re-associate */
- schedule_work(&mac->associnfo.work);
spin_unlock_irqrestore(&mac->lock, flags);
}
@@ -338,6 +344,9 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de
struct ieee80211softmac_network *net = NULL;
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+ if (unlikely(!mac->running))
+ return -ENODEV;
+
if (!deauth) {
dprintk("deauth without deauth packet. eek!\n");
return 0;
@@ -360,5 +369,8 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de
}
ieee80211softmac_deauth_from_net(mac, net);
+
+ /* let's try to re-associate */
+ schedule_work(&mac->associnfo.work);
return 0;
}
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index be83bdc1644a..6252be2c0db9 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -89,6 +89,8 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
ieee80211softmac_wait_for_scan(sm);
spin_lock_irqsave(&sm->lock, flags);
+ sm->running = 0;
+
/* Free all pending assoc work items */
cancel_delayed_work(&sm->associnfo.work);
@@ -204,6 +206,8 @@ void ieee80211softmac_start(struct net_device *dev)
assert(0);
if (mac->txrates_change)
mac->txrates_change(dev, change, &oldrates);
+
+ mac->running = 1;
}
EXPORT_SYMBOL_GPL(ieee80211softmac_start);
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c
index 2b9e7edfa3ce..d31cf77498c4 100644
--- a/net/ieee80211/softmac/ieee80211softmac_scan.c
+++ b/net/ieee80211/softmac/ieee80211softmac_scan.c
@@ -115,7 +115,15 @@ void ieee80211softmac_scan(void *d)
// TODO: is this if correct, or should we do this only if scanning from assoc request?
if (sm->associnfo.req_essid.len)
ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
+
+ spin_lock_irqsave(&sm->lock, flags);
+ if (unlikely(!sm->running)) {
+ /* Prevent reschedule on workqueue flush */
+ spin_unlock_irqrestore(&sm->lock, flags);
+ break;
+ }
schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
+ spin_unlock_irqrestore(&sm->lock, flags);
return;
} else {
dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 18d7fad474d7..c9026dbf4c93 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -337,7 +337,7 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
* Initialise the virtual path cache for the packet. It describes
* how the packet travels inside Linux networking.
*/
- if (likely(skb->dst == NULL)) {
+ if (skb->dst == NULL) {
int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
skb->dev);
if (unlikely(err)) {
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 9bebad07bf2e..cbcae6544622 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -209,7 +209,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
void ip_options_fragment(struct sk_buff * skb)
{
- unsigned char * optptr = skb->nh.raw;
+ unsigned char * optptr = skb->nh.raw + sizeof(struct iphdr);
struct ip_options * opt = &(IPCB(skb)->opt);
int l = opt->optlen;
int optlen;
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 2c2fb700d835..518f581d39ec 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -162,6 +162,8 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
/* Validate TPKT length */
tpktlen = tpkt[2] * 256 + tpkt[3];
+ if (tpktlen < 4)
+ goto clear_out;
if (tpktlen > tcpdatalen) {
if (tcpdatalen == 4) { /* Separate TPKT header */
/* Netmeeting sends TPKT header and data separately */
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
index 48078002e450..355a53a5b6cd 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323_asn1.c
@@ -2,7 +2,7 @@
* ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
* conntrack/NAT module.
*
- * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@hotmail.com>
+ * Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
*
* This source code is licensed under General Public License version 2.
*
@@ -703,6 +703,10 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
type = get_bits(bs, f->sz);
}
+ /* Write Type */
+ if (base)
+ *(unsigned *) base = type;
+
/* Check Range */
if (type >= f->ub) { /* Newer version? */
BYTE_ALIGN(bs);
@@ -712,10 +716,6 @@ int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
return H323_ERROR_NONE;
}
- /* Write Type */
- if (base)
- *(unsigned *) base = type;
-
/* Transfer to son level */
son = &f->fields[type];
if (son->attr & STOP) {
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 8f760b28617e..67e676783da9 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -219,8 +219,10 @@ ip_nat_out(unsigned int hooknum,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+#ifdef CONFIG_XFRM
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
+#endif
unsigned int ret;
/* root is playing with raw sockets. */
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 6d1c11563943..cee3397ec277 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1441,7 +1441,7 @@ static int compat_copy_entry_to_user(struct ipt_entry *e,
ret = -EFAULT;
origsize = *size;
ce = (struct compat_ipt_entry __user *)*dstptr;
- if (__copy_to_user(ce, e, sizeof(struct ipt_entry)))
+ if (copy_to_user(ce, e, sizeof(struct ipt_entry)))
goto out;
*dstptr += sizeof(struct compat_ipt_entry);
@@ -1459,9 +1459,9 @@ static int compat_copy_entry_to_user(struct ipt_entry *e,
goto out;
ret = -EFAULT;
next_offset = e->next_offset - (origsize - *size);
- if (__put_user(target_offset, &ce->target_offset))
+ if (put_user(target_offset, &ce->target_offset))
goto out;
- if (__put_user(next_offset, &ce->next_offset))
+ if (put_user(next_offset, &ce->next_offset))
goto out;
return 0;
out:
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 87f68e787d0c..e2b7b8055037 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1468,6 +1468,7 @@ void tcp_close(struct sock *sk, long timeout)
{
struct sk_buff *skb;
int data_was_unread = 0;
+ int state;
lock_sock(sk);
sk->sk_shutdown = SHUTDOWN_MASK;
@@ -1544,6 +1545,11 @@ void tcp_close(struct sock *sk, long timeout)
sk_stream_wait_close(sk, timeout);
adjudge_to_death:
+ state = sk->sk_state;
+ sock_hold(sk);
+ sock_orphan(sk);
+ atomic_inc(sk->sk_prot->orphan_count);
+
/* It is the last release_sock in its life. It will remove backlog. */
release_sock(sk);
@@ -1555,8 +1561,9 @@ adjudge_to_death:
bh_lock_sock(sk);
BUG_TRAP(!sock_owned_by_user(sk));
- sock_hold(sk);
- sock_orphan(sk);
+ /* Have we already been destroyed by a softirq or backlog? */
+ if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE)
+ goto out;
/* This is a (useful) BSD violating of the RFC. There is a
* problem with TCP as specified in that the other end could
@@ -1584,7 +1591,6 @@ adjudge_to_death:
if (tmo > TCP_TIMEWAIT_LEN) {
inet_csk_reset_keepalive_timer(sk, tcp_fin_time(sk));
} else {
- atomic_inc(sk->sk_prot->orphan_count);
tcp_time_wait(sk, TCP_FIN_WAIT2, tmo);
goto out;
}
@@ -1603,7 +1609,6 @@ adjudge_to_death:
NET_INC_STATS_BH(LINUX_MIB_TCPABORTONMEMORY);
}
}
- atomic_inc(sk->sk_prot->orphan_count);
if (sk->sk_state == TCP_CLOSE)
inet_csk_destroy_sock(sk);
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index e0e9d1383c7c..b72fa55dfb84 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -137,8 +137,8 @@ static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
if (tp->snd_cwnd < tp->snd_cwnd_clamp) {
tp->snd_cwnd_cnt += ca->ai;
if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
- tp->snd_cwnd++;
tp->snd_cwnd_cnt -= tp->snd_cwnd;
+ tp->snd_cwnd++;
}
}
}
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index f8f3a37a1494..eb2865d5ae28 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -173,6 +173,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
if (err) {
sk->sk_err_soft = -err;
+ kfree_skb(skb);
return err;
}
@@ -181,6 +182,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) {
sk->sk_route_caps = 0;
+ kfree_skb(skb);
return err;
}
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index c6d169fbdceb..82e665c79991 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -257,7 +257,6 @@ struct ias_attrib *irias_find_attrib(struct ias_object *obj, char *name)
/* Unsafe (locking), attrib might change */
return attrib;
}
-EXPORT_SYMBOL(irias_find_attrib);
/*
* Function irias_add_attribute (obj, attrib)
@@ -484,7 +483,6 @@ struct ias_value *irias_new_string_value(char *string)
return value;
}
-EXPORT_SYMBOL(irias_new_string_value);
/*
* Function irias_new_octseq_value (octets, len)
@@ -519,7 +517,6 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
memcpy(value->t.oct_seq, octseq , len);
return value;
}
-EXPORT_SYMBOL(irias_new_octseq_value);
struct ias_value *irias_new_missing_value(void)
{
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 17abf60f9570..99293c63ff73 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -289,7 +289,7 @@ int xt_compat_match(void *match, void **dstptr, int *size, int convert)
case COMPAT_TO_USER:
pm = (struct xt_entry_match *)match;
msize = pm->u.user.match_size;
- if (__copy_to_user(*dstptr, pm, msize)) {
+ if (copy_to_user(*dstptr, pm, msize)) {
ret = -EFAULT;
break;
}
@@ -366,7 +366,7 @@ int xt_compat_target(void *target, void **dstptr, int *size, int convert)
case COMPAT_TO_USER:
pt = (struct xt_entry_target *)target;
tsize = pt->u.user.target_size;
- if (__copy_to_user(*dstptr, pt, tsize)) {
+ if (copy_to_user(*dstptr, pt, tsize)) {
ret = -EFAULT;
break;
}
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index d44981f5a619..3669cb953e6e 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -425,11 +425,16 @@ static int nr_create(struct socket *sock, int protocol)
nr_init_timers(sk);
- nr->t1 = sysctl_netrom_transport_timeout;
- nr->t2 = sysctl_netrom_transport_acknowledge_delay;
- nr->n2 = sysctl_netrom_transport_maximum_tries;
- nr->t4 = sysctl_netrom_transport_busy_delay;
- nr->idle = sysctl_netrom_transport_no_activity_timeout;
+ nr->t1 =
+ msecs_to_jiffies(sysctl_netrom_transport_timeout);
+ nr->t2 =
+ msecs_to_jiffies(sysctl_netrom_transport_acknowledge_delay);
+ nr->n2 =
+ msecs_to_jiffies(sysctl_netrom_transport_maximum_tries);
+ nr->t4 =
+ msecs_to_jiffies(sysctl_netrom_transport_busy_delay);
+ nr->idle =
+ msecs_to_jiffies(sysctl_netrom_transport_no_activity_timeout);
nr->window = sysctl_netrom_transport_requested_window_size;
nr->bpqext = 1;
@@ -1365,8 +1370,6 @@ static struct notifier_block nr_dev_notifier = {
static struct net_device **dev_nr;
-static char banner[] __initdata = KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n";
-
static int __init nr_proto_init(void)
{
int i;
@@ -1414,7 +1417,6 @@ static int __init nr_proto_init(void)
}
register_netdevice_notifier(&nr_dev_notifier);
- printk(banner);
ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
ax25_linkfail_register(nr_link_failed);
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 509afddae569..621e5586ab03 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -185,7 +185,6 @@ static struct net_device_stats *nr_get_stats(struct net_device *dev)
void nr_setup(struct net_device *dev)
{
- SET_MODULE_OWNER(dev);
dev->mtu = NR_MAX_PACKET_SIZE;
dev->hard_start_xmit = nr_xmit;
dev->open = nr_open;
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index ea65396d1619..55564efccf11 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -518,11 +518,11 @@ static int rose_create(struct socket *sock, int protocol)
init_timer(&rose->timer);
init_timer(&rose->idletimer);
- rose->t1 = sysctl_rose_call_request_timeout;
- rose->t2 = sysctl_rose_reset_request_timeout;
- rose->t3 = sysctl_rose_clear_request_timeout;
- rose->hb = sysctl_rose_ack_hold_back_timeout;
- rose->idle = sysctl_rose_no_activity_timeout;
+ rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout);
+ rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout);
+ rose->t3 = msecs_to_jiffies(sysctl_rose_clear_request_timeout);
+ rose->hb = msecs_to_jiffies(sysctl_rose_ack_hold_back_timeout);
+ rose->idle = msecs_to_jiffies(sysctl_rose_no_activity_timeout);
rose->state = ROSE_STATE_0;
@@ -1469,8 +1469,6 @@ static struct notifier_block rose_dev_notifier = {
static struct net_device **dev_rose;
-static const char banner[] = KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n";
-
static int __init rose_proto_init(void)
{
int i;
@@ -1519,7 +1517,6 @@ static int __init rose_proto_init(void)
sock_register(&rose_family_ops);
register_netdevice_notifier(&rose_dev_notifier);
- printk(banner);
ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
ax25_linkfail_register(rose_link_failed);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index d297af737d10..2a1bf8e119e5 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -135,7 +135,6 @@ static struct net_device_stats *rose_get_stats(struct net_device *dev)
void rose_setup(struct net_device *dev)
{
- SET_MODULE_OWNER(dev);
dev->mtu = ROSE_MAX_PACKET_SIZE - 2;
dev->hard_start_xmit = rose_xmit;
dev->open = rose_open;
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 09e9e9d04d92..bd86a63960ce 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -40,7 +40,8 @@ void rose_start_ftimer(struct rose_neigh *neigh)
neigh->ftimer.data = (unsigned long)neigh;
neigh->ftimer.function = &rose_ftimer_expiry;
- neigh->ftimer.expires = jiffies + sysctl_rose_link_fail_timeout;
+ neigh->ftimer.expires =
+ jiffies + msecs_to_jiffies(sysctl_rose_link_fail_timeout);
add_timer(&neigh->ftimer);
}
@@ -51,7 +52,8 @@ static void rose_start_t0timer(struct rose_neigh *neigh)
neigh->t0timer.data = (unsigned long)neigh;
neigh->t0timer.function = &rose_t0timer_expiry;
- neigh->t0timer.expires = jiffies + sysctl_rose_restart_request_timeout;
+ neigh->t0timer.expires =
+ jiffies + msecs_to_jiffies(sysctl_rose_restart_request_timeout);
add_timer(&neigh->t0timer);
}
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 8631b65a7312..a22542fa1bc8 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -48,8 +48,6 @@ static DEFINE_SPINLOCK(rose_route_list_lock);
struct rose_neigh *rose_loopback_neigh;
-static void rose_remove_neigh(struct rose_neigh *);
-
/*
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
@@ -235,11 +233,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge(&rose_neigh->queue);
- spin_lock_bh(&rose_neigh_list_lock);
-
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
- spin_unlock_bh(&rose_neigh_list_lock);
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
return;
@@ -248,7 +243,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
while (s != NULL && s->next != NULL) {
if (s->next == rose_neigh) {
s->next = rose_neigh->next;
- spin_unlock_bh(&rose_neigh_list_lock);
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
return;
@@ -256,7 +250,6 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
s = s->next;
}
- spin_unlock_bh(&rose_neigh_list_lock);
}
/*
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 91132f6871d7..f1c7bd29f2cd 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -974,10 +974,10 @@ hfsc_adjust_levels(struct hfsc_class *cl)
do {
level = 0;
list_for_each_entry(p, &cl->children, siblings) {
- if (p->level > level)
- level = p->level;
+ if (p->level >= level)
+ level = p->level + 1;
}
- cl->level = level + 1;
+ cl->level = level;
} while ((cl = cl->cl_parent) != NULL);
}
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 297b8951463e..cf0c767d43ae 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -149,6 +149,7 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
/* This is the first chunk in the packet. */
chunk->singleton = 1;
ch = (sctp_chunkhdr_t *) chunk->skb->data;
+ chunk->data_accepted = 0;
}
chunk->chunk_hdr = ch;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 2b9a832b29a7..8cdba51ec076 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -636,8 +636,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
*/
chunk->subh.cookie_hdr =
(struct sctp_signed_cookie *)chunk->skb->data;
- skb_pull(chunk->skb,
- ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t));
+ if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
+ sizeof(sctp_chunkhdr_t)))
+ goto nomem;
/* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint
* "Z" will reply with a COOKIE ACK chunk after building a TCB
@@ -965,7 +966,8 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
*/
chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data;
paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
- skb_pull(chunk->skb, paylen);
+ if (!pskb_pull(chunk->skb, paylen))
+ goto nomem;
reply = sctp_make_heartbeat_ack(asoc, chunk,
chunk->subh.hb_hdr, paylen);
@@ -1860,8 +1862,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
* are in good shape.
*/
chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data;
- skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
- sizeof(sctp_chunkhdr_t));
+ if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
+ sizeof(sctp_chunkhdr_t)))
+ goto nomem;
/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
* of a duplicate COOKIE ECHO match the Verification Tags of the
@@ -5151,7 +5154,9 @@ static int sctp_eat_data(const struct sctp_association *asoc,
int tmp;
__u32 tsn;
int account_value;
+ struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
struct sock *sk = asoc->base.sk;
+ int rcvbuf_over = 0;
data_hdr = chunk->subh.data_hdr = (sctp_datahdr_t *)chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
@@ -5162,10 +5167,16 @@ static int sctp_eat_data(const struct sctp_association *asoc,
/* ASSERT: Now skb->data is really the user data. */
/*
- * if we are established, and we have used up our receive
- * buffer memory, drop the frame
- */
- if (asoc->state == SCTP_STATE_ESTABLISHED) {
+ * If we are established, and we have used up our receive buffer
+ * memory, think about droping the frame.
+ * Note that we have an opportunity to improve performance here.
+ * If we accept one chunk from an skbuff, we have to keep all the
+ * memory of that skbuff around until the chunk is read into user
+ * space. Therefore, once we accept 1 chunk we may as well accept all
+ * remaining chunks in the skbuff. The data_accepted flag helps us do
+ * that.
+ */
+ if ((asoc->state == SCTP_STATE_ESTABLISHED) && (!chunk->data_accepted)) {
/*
* If the receive buffer policy is 1, then each
* association can allocate up to sk_rcvbuf bytes
@@ -5176,9 +5187,25 @@ static int sctp_eat_data(const struct sctp_association *asoc,
account_value = atomic_read(&asoc->rmem_alloc);
else
account_value = atomic_read(&sk->sk_rmem_alloc);
-
- if (account_value > sk->sk_rcvbuf)
- return SCTP_IERROR_IGNORE_TSN;
+ if (account_value > sk->sk_rcvbuf) {
+ /*
+ * We need to make forward progress, even when we are
+ * under memory pressure, so we always allow the
+ * next tsn after the ctsn ack point to be accepted.
+ * This lets us avoid deadlocks in which we have to
+ * drop frames that would otherwise let us drain the
+ * receive queue.
+ */
+ if ((sctp_tsnmap_get_ctsn(map) + 1) != tsn)
+ return SCTP_IERROR_IGNORE_TSN;
+
+ /*
+ * We're going to accept the frame but we should renege
+ * to make space for it. This will send us down that
+ * path later in this function.
+ */
+ rcvbuf_over = 1;
+ }
}
/* Process ECN based congestion.
@@ -5226,6 +5253,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
datalen -= sizeof(sctp_data_chunk_t);
deliver = SCTP_CMD_CHUNK_ULP;
+ chunk->data_accepted = 1;
/* Think about partial delivery. */
if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) {
@@ -5242,7 +5270,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* large spill over.
*/
if (!asoc->rwnd || asoc->rwnd_over ||
- (datalen > asoc->rwnd + asoc->frag_point)) {
+ (datalen > asoc->rwnd + asoc->frag_point) ||
+ rcvbuf_over) {
/* If this is the next TSN, consider reneging to make
* room. Note: Playing nice with a confused sender. A
@@ -5250,8 +5279,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
* space and in the future we may want to detect and
* do more drastic reneging.
*/
- if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) &&
- (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) {
+ if (sctp_tsnmap_has_gap(map) &&
+ (sctp_tsnmap_get_ctsn(map) + 1) == tsn) {
SCTP_DEBUG_PRINTK("Reneging for tsn:%u\n", tsn);
deliver = SCTP_CMD_RENEGE;
} else {
diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c
index 75ef10408764..8bcca5676151 100644
--- a/net/sctp/sm_statetable.c
+++ b/net/sctp/sm_statetable.c
@@ -366,9 +366,9 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \
/* SCTP_STATE_CLOSED */ \
- {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_WAIT */ \
- {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \
{.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_ESTABLISHED */ \
@@ -380,7 +380,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
- {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_ECN_ECNE */
#define TYPE_SCTP_ECN_CWR { \
@@ -401,7 +401,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
- {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \
} /* TYPE_SCTP_ECN_CWR */
#define TYPE_SCTP_SHUTDOWN_COMPLETE { \
@@ -647,7 +647,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \
- {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
+ {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \
/* SCTP_STATE_COOKIE_WAIT */ \
{.fn = sctp_sf_do_prm_requestheartbeat, \
.name = "sctp_sf_do_prm_requestheartbeat"}, \
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 2080b2d28c98..575e556aeb3e 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -279,6 +279,7 @@ static inline void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag)
{
struct sk_buff *pos;
+ struct sk_buff *new = NULL;
struct sctp_ulpevent *event;
struct sk_buff *pnext, *last;
struct sk_buff *list = skb_shinfo(f_frag)->frag_list;
@@ -297,11 +298,33 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu
*/
if (last)
last->next = pos;
- else
- skb_shinfo(f_frag)->frag_list = pos;
+ else {
+ if (skb_cloned(f_frag)) {
+ /* This is a cloned skb, we can't just modify
+ * the frag_list. We need a new skb to do that.
+ * Instead of calling skb_unshare(), we'll do it
+ * ourselves since we need to delay the free.
+ */
+ new = skb_copy(f_frag, GFP_ATOMIC);
+ if (!new)
+ return NULL; /* try again later */
+
+ new->sk = f_frag->sk;
+
+ skb_shinfo(new)->frag_list = pos;
+ } else
+ skb_shinfo(f_frag)->frag_list = pos;
+ }
/* Remove the first fragment from the reassembly queue. */
__skb_unlink(f_frag, queue);
+
+ /* if we did unshare, then free the old skb and re-assign */
+ if (new) {
+ kfree_skb(f_frag);
+ f_frag = new;
+ }
+
while (pos) {
pnext = pos->next;