aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohn W. Linville <linville@tuxdriver.com>2006-05-17 14:51:24 -0400
committerJohn W. Linville <linville@tuxdriver.com>2006-05-17 14:51:24 -0400
commit5dd8816aeb1f068ade0349a22009ff7a66f25413 (patch)
treec56ff327b1dfa8868b4208aea9ac4158e3bfe308 /net
parent[PATCH] bcm43xx: add PCI ID for bcm4319 (diff)
parentMerge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/spi-2.6 (diff)
downloadlinux-dev-5dd8816aeb1f068ade0349a22009ff7a66f25413.tar.xz
linux-dev-5dd8816aeb1f068ade0349a22009ff7a66f25413.zip
Merge branch 'from-linus' into upstream
Diffstat (limited to 'net')
-rw-r--r--net/atm/clip.c2
-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/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ip_options.c2
-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/netrom/af_netrom.c3
-rw-r--r--net/rose/af_rose.c3
-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
20 files changed, 183 insertions, 153 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/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/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/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/netrom/af_netrom.c b/net/netrom/af_netrom.c
index ecd288beca7c..3669cb953e6e 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1370,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;
@@ -1419,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/rose/af_rose.c b/net/rose/af_rose.c
index ef4538ac84f0..55564efccf11 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -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/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;