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

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (22 commits)
  [IPCONFIG]: The kernel gets no IP from some DHCP servers
  b43legacy: Fix module init message
  rndis_wlan: fix broken data copy
  libertas: compare the current command with response
  libertas: fix sanity check on sequence number in command response
  p54: fix eeprom parser length sanity checks
  p54: fix EEPROM structure endianness
  ssb: Add pcibios_enable_device() return value check
  rc80211-pid: fix rate adjustment
  [ESP]: Add select on AUTHENC
  [TCP]: Improve ipv4 established hash function.
  [NETPOLL]: Revert two bogus cleanups that broke netconsole.
  [PPPOL2TP]: Add missing sock_put() in pppol2tp_tunnel_closeall()
  Subject: [PPPOL2TP] add missing sock_put() in pppol2tp_recv_dequeue()
  [BLUETOOTH]: l2cap info_timer delete fix in hci_conn_del
  [NET]: Fix race in generic address resolution.
  iucv: fix build error on !SMP
  [TCP]: Must count fack_count also when skipping
  [TUN]: Fix RTNL-locking in tun/tap driver
  [SCTP]: Use proc_create to setup de->proc_fops.
  ...
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index e0b072d..86e5dba 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -455,6 +455,7 @@
 			       skb_queue_len(&session->reorder_q));
 			__skb_unlink(skb, &session->reorder_q);
 			kfree_skb(skb);
+			sock_put(session->sock);
 			continue;
 		}
 
@@ -1110,6 +1111,8 @@
 	for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) {
 again:
 		hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+			struct sk_buff *skb;
+
 			session = hlist_entry(walk, struct pppol2tp_session, hlist);
 
 			sk = session->sock;
@@ -1138,7 +1141,10 @@
 			/* Purge any queued data */
 			skb_queue_purge(&sk->sk_receive_queue);
 			skb_queue_purge(&sk->sk_write_queue);
-			skb_queue_purge(&session->reorder_q);
+			while ((skb = skb_dequeue(&session->reorder_q))) {
+				kfree_skb(skb);
+				sock_put(sk);
+			}
 
 			release_sock(sk);
 			sock_put(sk);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 038c1ef..7b816a0 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -663,7 +663,11 @@
 	case SIOCSIFHWADDR:
 	{
 		/* try to set the actual net device's hw address */
-		int ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
+		int ret;
+
+		rtnl_lock();
+		ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr);
+		rtnl_unlock();
 
 		if (ret == 0) {
 			/** Set the character device's hardware address. This is used when
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c39de42..5f3f34e 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3829,7 +3829,7 @@
 #ifdef CONFIG_B43LEGACY_DMA
 	feat_dma = "D";
 #endif
-	printk(KERN_INFO "Broadcom 43xx driver loaded "
+	printk(KERN_INFO "Broadcom 43xx-legacy driver loaded "
 	       "[ Features: %s%s%s%s%s, Firmware-ID: "
 	       B43legacy_SUPPORTED_FIRMWARE_ID " ]\n",
 	       feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 159216a..bdc6a1c 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -562,9 +562,7 @@
 	}
 
 	resp = (void *)priv->upld_buf;
-
-	curcmd = le16_to_cpu(resp->command);
-
+	curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
 	respcmd = le16_to_cpu(resp->command);
 	result = le16_to_cpu(resp->result);
 
@@ -572,9 +570,9 @@
 		     respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
 	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
 
-	if (resp->seqnum != resp->seqnum) {
+	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
 		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
-			    le16_to_cpu(resp->seqnum), le16_to_cpu(resp->seqnum));
+			    le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
 		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		ret = -1;
 		goto done;
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
index 5cda49a..d191e05 100644
--- a/drivers/net/wireless/p54common.c
+++ b/drivers/net/wireless/p54common.c
@@ -166,18 +166,23 @@
 	struct p54_common *priv = dev->priv;
 	struct eeprom_pda_wrap *wrap = NULL;
 	struct pda_entry *entry;
-	int i = 0;
 	unsigned int data_len, entry_len;
 	void *tmp;
 	int err;
+	u8 *end = (u8 *)eeprom + len;
 
 	wrap = (struct eeprom_pda_wrap *) eeprom;
-	entry = (void *)wrap->data + wrap->len;
-	i += 2;
-	i += le16_to_cpu(entry->len)*2;
-	while (i < len) {
+	entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+	/* verify that at least the entry length/code fits */
+	while ((u8 *)entry <= end - sizeof(*entry)) {
 		entry_len = le16_to_cpu(entry->len);
 		data_len = ((entry_len - 1) << 1);
+
+		/* abort if entry exceeds whole structure */
+		if ((u8 *)entry + sizeof(*entry) + data_len > end)
+			break;
+
 		switch (le16_to_cpu(entry->code)) {
 		case PDR_MAC_ADDRESS:
 			SET_IEEE80211_PERM_ADDR(dev, entry->data);
@@ -249,13 +254,12 @@
 			priv->version = *(u8 *)(entry->data + 1);
 			break;
 		case PDR_END:
-			i = len;
+			/* make it overrun */
+			entry_len = len;
 			break;
 		}
 
 		entry = (void *)entry + (entry_len + 1)*2;
-		i += 2;
-		i += entry_len*2;
 	}
 
 	if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h
index a721334..b67ff34 100644
--- a/drivers/net/wireless/p54common.h
+++ b/drivers/net/wireless/p54common.h
@@ -53,10 +53,10 @@
 } __attribute__ ((packed));
 
 struct eeprom_pda_wrap {
-	u32 magic;
-	u16 pad;
-	u16 len;
-	u32 arm_opcode;
+	__le32 magic;
+	__le16 pad;
+	__le16 len;
+	__le32 arm_opcode;
 	u8 data[0];
 } __attribute__ ((packed));
 
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index d9460ae..10b776c 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -260,7 +260,7 @@
 	__le32 KeyLength;
 	u8 Bssid[6];
 	u8 Padding[6];
-	__le64 KeyRSC;
+	u8 KeyRSC[8];
 	u8 KeyMaterial[32];
 } __attribute__((packed));
 
@@ -1508,7 +1508,7 @@
 	struct usbnet *usbdev = dev->priv;
 	struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev);
 	struct NDIS_802_11_KEY ndis_key;
-	int i, keyidx, ret;
+	int keyidx, ret;
 	u8 *addr;
 
 	keyidx = wrqu->encoding.flags & IW_ENCODE_INDEX;
@@ -1543,9 +1543,7 @@
 	ndis_key.KeyIndex = cpu_to_le32(keyidx);
 
 	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
-		for (i = 0; i < 6; i++)
-			ndis_key.KeyRSC |=
-				cpu_to_le64(ext->rx_seq[i] << (i * 8));
+		memcpy(ndis_key.KeyRSC, ext->rx_seq, 6);
 		ndis_key.KeyIndex |= cpu_to_le32(1 << 29);
 	}
 
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 07ab48d..74b9a8a 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -111,7 +111,10 @@
 
 	/* Enable PCI bridge bus mastering and memory space */
 	pci_set_master(dev);
-	pcibios_enable_device(dev, ~0);
+	if (pcibios_enable_device(dev, ~0) < 0) {
+		ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+		return;
+	}
 
 	/* Enable PCI bridge BAR1 prefetch and burst */
 	pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index a0525a1..e3d7959 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -25,6 +25,7 @@
 
 struct netpoll_info {
 	atomic_t refcnt;
+	int rx_flags;
 	spinlock_t rx_lock;
 	struct netpoll *rx_np; /* netpoll that registered an rx_hook */
 	struct sk_buff_head arp_tx; /* list of arp requests to reply to */
@@ -50,12 +51,12 @@
 	unsigned long flags;
 	int ret = 0;
 
-	if (!npinfo || !npinfo->rx_np)
+	if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags))
 		return 0;
 
 	spin_lock_irqsave(&npinfo->rx_lock, flags);
-	/* check rx_np again with the lock held */
-	if (npinfo->rx_np && __netpoll_rx(skb))
+	/* check rx_flags again with the lock held */
+	if (npinfo->rx_flags && __netpoll_rx(skb))
 		ret = 1;
 	spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 70013c5..89cd011 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -175,7 +175,8 @@
 static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
 					const __be32 faddr, const __be16 fport)
 {
-	return jhash_2words((__force __u32) laddr ^ (__force __u32) faddr,
+	return jhash_3words((__force __u32) laddr,
+			    (__force __u32) faddr,
 			    ((__u32) lport) << 16 | (__force __u32)fport,
 			    inet_ehash_secret);
 }
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 7c5459c8..34f8bf9 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -417,7 +417,8 @@
 		l2cap_sock_kill(sk);
 	}
 
-	del_timer_sync(&conn->info_timer);
+	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
+		del_timer_sync(&conn->info_timer);
 
 	hcon->l2cap_data = NULL;
 	kfree(conn);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index aef0153..d9a02b2 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -839,7 +839,7 @@
 		struct sk_buff *skb = skb_peek(&neigh->arp_queue);
 		/* keep skb alive even if arp_queue overflows */
 		if (skb)
-			skb_get(skb);
+			skb = skb_copy(skb, GFP_ATOMIC);
 		write_unlock(&neigh->lock);
 		neigh->ops->solicit(neigh, skb);
 		atomic_inc(&neigh->probes);
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 6faa128..4b7e756 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -39,6 +39,8 @@
 static atomic_t trapped;
 
 #define USEC_PER_POLL	50
+#define NETPOLL_RX_ENABLED  1
+#define NETPOLL_RX_DROP     2
 
 #define MAX_SKB_SIZE \
 		(MAX_UDP_CHUNK + sizeof(struct udphdr) + \
@@ -126,11 +128,13 @@
 	if (!test_bit(NAPI_STATE_SCHED, &napi->state))
 		return budget;
 
+	npinfo->rx_flags |= NETPOLL_RX_DROP;
 	atomic_inc(&trapped);
 
 	work = napi->poll(napi, budget);
 
 	atomic_dec(&trapped);
+	npinfo->rx_flags &= ~NETPOLL_RX_DROP;
 
 	return budget - work;
 }
@@ -472,7 +476,7 @@
 	if (skb->dev->type != ARPHRD_ETHER)
 		goto out;
 
-	/* if receive ARP during middle of NAPI poll, then queue */
+	/* check if netpoll clients need ARP */
 	if (skb->protocol == htons(ETH_P_ARP) &&
 	    atomic_read(&trapped)) {
 		skb_queue_tail(&npi->arp_tx, skb);
@@ -534,9 +538,6 @@
 	return 1;
 
 out:
-	/* If packet received while already in poll then just
-	 * silently drop.
-	 */
 	if (atomic_read(&trapped)) {
 		kfree_skb(skb);
 		return 1;
@@ -675,6 +676,7 @@
 			goto release;
 		}
 
+		npinfo->rx_flags = 0;
 		npinfo->rx_np = NULL;
 
 		spin_lock_init(&npinfo->rx_lock);
@@ -756,6 +758,7 @@
 
 	if (np->rx_hook) {
 		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		npinfo->rx_flags |= NETPOLL_RX_ENABLED;
 		npinfo->rx_np = np;
 		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 	}
@@ -797,6 +800,7 @@
 			if (npinfo->rx_np == np) {
 				spin_lock_irqsave(&npinfo->rx_lock, flags);
 				npinfo->rx_np = NULL;
+				npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
 				spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 			}
 
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 19880b0..9c7e5ff 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -343,7 +343,7 @@
 	tristate "IP: ESP transformation"
 	select XFRM
 	select CRYPTO
-	select CRYPTO_AEAD
+	select CRYPTO_AUTHENC
 	select CRYPTO_HMAC
 	select CRYPTO_MD5
 	select CRYPTO_CBC
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 10013cc..5dd9385 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -753,9 +753,9 @@
 		printk("Unknown ARP type 0x%04x for device %s\n", dev->type, dev->name);
 		b->htype = dev->type; /* can cause undefined behavior */
 	}
+
+	/* server_ip and your_ip address are both already zero per RFC2131 */
 	b->hlen = dev->addr_len;
-	b->your_ip = NONE;
-	b->server_ip = NONE;
 	memcpy(b->hw_addr, dev->dev_addr, dev->addr_len);
 	b->secs = htons(jiffies_diff / HZ);
 	b->xid = d->xid;
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index 5212ed9..7eb7636 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -1,12 +1,13 @@
 /*
  * Binary Increase Congestion control for TCP
- *
+ * Home page:
+ *      http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC
  * This is from the implementation of BICTCP in
  * Lison-Xu, Kahaled Harfoush, and Injong Rhee.
  *  "Binary Increase Congestion Control for Fast, Long Distance
  *  Networks" in InfoComm 2004
  * Available from:
- *  http://www.csc.ncsu.edu/faculty/rhee/export/bitcp.pdf
+ *  http://netsrv.csc.ncsu.edu/export/bitcp.pdf
  *
  * Unless BIC is enabled and congestion window is large
  * this behaves the same as the original Reno.
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 19c449f..7facdb0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1367,7 +1367,7 @@
  * a normal way
  */
 static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk,
-					u32 skip_to_seq)
+					u32 skip_to_seq, int *fack_count)
 {
 	tcp_for_write_queue_from(skb, sk) {
 		if (skb == tcp_send_head(sk))
@@ -1375,6 +1375,8 @@
 
 		if (!before(TCP_SKB_CB(skb)->end_seq, skip_to_seq))
 			break;
+
+		*fack_count += tcp_skb_pcount(skb);
 	}
 	return skb;
 }
@@ -1390,7 +1392,7 @@
 		return skb;
 
 	if (before(next_dup->start_seq, skip_to_seq)) {
-		skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq);
+		skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq, fack_count);
 		tcp_sacktag_walk(skb, sk, NULL,
 				 next_dup->start_seq, next_dup->end_seq,
 				 1, fack_count, reord, flag);
@@ -1537,7 +1539,8 @@
 
 			/* Head todo? */
 			if (before(start_seq, cache->start_seq)) {
-				skb = tcp_sacktag_skip(skb, sk, start_seq);
+				skb = tcp_sacktag_skip(skb, sk, start_seq,
+						       &fack_count);
 				skb = tcp_sacktag_walk(skb, sk, next_dup,
 						       start_seq,
 						       cache->start_seq,
@@ -1565,7 +1568,8 @@
 				goto walk;
 			}
 
-			skb = tcp_sacktag_skip(skb, sk, cache->end_seq);
+			skb = tcp_sacktag_skip(skb, sk, cache->end_seq,
+					       &fack_count);
 			/* Check overlap against next cached too (past this one already) */
 			cache++;
 			continue;
@@ -1577,7 +1581,7 @@
 				break;
 			fack_count = tp->fackets_out;
 		}
-		skb = tcp_sacktag_skip(skb, sk, start_seq);
+		skb = tcp_sacktag_skip(skb, sk, start_seq, &fack_count);
 
 walk:
 		skb = tcp_sacktag_walk(skb, sk, next_dup, start_seq, end_seq,
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 3ffb032..58219df 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -85,7 +85,7 @@
 	depends on IPV6
 	select XFRM
 	select CRYPTO
-	select CRYPTO_AEAD
+	select CRYPTO_AUTHENC
 	select CRYPTO_HMAC
 	select CRYPTO_MD5
 	select CRYPTO_CBC
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index b825399..6eef1f2 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -76,9 +76,11 @@
 
 #ifdef CONFIG_PROC_FS
 	{ struct proc_dir_entry *ent;
-	ent = create_proc_entry("ircomm", 0, proc_irda);
-	if (ent)
-		ent->proc_fops = &ircomm_proc_fops;
+	ent = proc_create("ircomm", 0, proc_irda, &ircomm_proc_fops);
+	if (!ent) {
+		printk(KERN_ERR "ircomm_init: can't create /proc entry!\n");
+		return -ENODEV;
+	}
 	}
 #endif /* CONFIG_PROC_FS */
 
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index a4b56e2..1eb4bbc 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -128,13 +128,11 @@
 
 #ifdef CONFIG_PROC_FS
 	{ struct proc_dir_entry *proc;
-	proc = create_proc_entry("irlan", 0, proc_irda);
+	proc = proc_create("irlan", 0, proc_irda, &irlan_fops);
 	if (!proc) {
 		printk(KERN_ERR "irlan_init: can't create /proc entry!\n");
 		return -ENODEV;
 	}
-
-	proc->proc_fops = &irlan_fops;
 	}
 #endif /* CONFIG_PROC_FS */
 
diff --git a/net/irda/irproc.c b/net/irda/irproc.c
index cae24fb..88e80a3 100644
--- a/net/irda/irproc.c
+++ b/net/irda/irproc.c
@@ -72,11 +72,9 @@
 		return;
 	proc_irda->owner = THIS_MODULE;
 
-	for (i=0; i<ARRAY_SIZE(irda_dirs); i++) {
-		d = create_proc_entry(irda_dirs[i].name, 0, proc_irda);
-		if (d)
-			d->proc_fops = irda_dirs[i].fops;
-	}
+	for (i = 0; i < ARRAY_SIZE(irda_dirs); i++)
+		d = proc_create(irda_dirs[i].name, 0, proc_irda,
+				irda_dirs[i].fops);
 }
 
 /*
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 2753b0c..d764f4c 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -621,7 +621,6 @@
 	return iucv_call_b2f0(IUCV_SEVER, parm);
 }
 
-#ifdef CONFIG_SMP
 /**
  * __iucv_cleanup_queue
  * @dummy: unused dummy argument
@@ -632,7 +631,6 @@
 static void __iucv_cleanup_queue(void *dummy)
 {
 }
-#endif
 
 /**
  * iucv_cleanup_queue
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index c339571..3b77410 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -2,7 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2005, Devicescape Software, Inc.
  * Copyright 2007, Mattias Nissler <mattias.nissler@gmx.de>
- * Copyright 2007, Stefano Brivio <stefano.brivio@polimi.it>
+ * Copyright 2007-2008, Stefano Brivio <stefano.brivio@polimi.it>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -63,72 +63,66 @@
  * RC_PID_ARITH_SHIFT.
  */
 
-
-/* Shift the adjustment so that we won't switch to a lower rate if it exhibited
- * a worse failed frames behaviour and we'll choose the highest rate whose
- * failed frames behaviour is not worse than the one of the original rate
- * target. While at it, check that the adjustment is within the ranges. Then,
- * provide the new rate index. */
-static int rate_control_pid_shift_adjust(struct rc_pid_rateinfo *r,
-					 int adj, int cur, int l)
-{
-	int i, j, k, tmp;
-
-	j = r[cur].rev_index;
-	i = j + adj;
-
-	if (i < 0)
-		return r[0].index;
-	if (i >= l - 1)
-		return r[l - 1].index;
-
-	tmp = i;
-
-	if (adj < 0) {
-		for (k = j; k >= i; k--)
-			if (r[k].diff <= r[j].diff)
-				tmp = k;
-	} else {
-		for (k = i + 1; k + i < l; k++)
-			if (r[k].diff <= r[i].diff)
-				tmp = k;
-	}
-
-	return r[tmp].index;
-}
-
+/* Adjust the rate while ensuring that we won't switch to a lower rate if it
+ * exhibited a worse failed frames behaviour and we'll choose the highest rate
+ * whose failed frames behaviour is not worse than the one of the original rate
+ * target. While at it, check that the new rate is valid. */
 static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
 					 struct sta_info *sta, int adj,
 					 struct rc_pid_rateinfo *rinfo)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_hw_mode *mode;
-	int newidx;
-	int maxrate;
-	int back = (adj > 0) ? 1 : -1;
+	int cur_sorted, new_sorted, probe, tmp, n_bitrates;
+	int cur = sta->txrate;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
 
 	mode = local->oper_hw_mode;
-	maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+	n_bitrates = mode->num_rates;
 
-	newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate,
-					       mode->num_rates);
+	/* Map passed arguments to sorted values. */
+	cur_sorted = rinfo[cur].rev_index;
+	new_sorted = cur_sorted + adj;
 
-	while (newidx != sta->txrate) {
-		if (rate_supported(sta, mode, newidx) &&
-		    (maxrate < 0 || newidx <= maxrate)) {
-			sta->txrate = newidx;
+	/* Check limits. */
+	if (new_sorted < 0)
+		new_sorted = rinfo[0].rev_index;
+	else if (new_sorted >= n_bitrates)
+		new_sorted = rinfo[n_bitrates - 1].rev_index;
+
+	tmp = new_sorted;
+
+	if (adj < 0) {
+		/* Ensure that the rate decrease isn't disadvantageous. */
+		for (probe = cur_sorted; probe >= new_sorted; probe--)
+			if (rinfo[probe].diff <= rinfo[cur_sorted].diff &&
+			    rate_supported(sta, mode, rinfo[probe].index))
+				tmp = probe;
+	} else {
+		/* Look for rate increase with zero (or below) cost. */
+		for (probe = new_sorted + 1; probe < n_bitrates; probe++)
+			if (rinfo[probe].diff <= rinfo[new_sorted].diff &&
+			    rate_supported(sta, mode, rinfo[probe].index))
+				tmp = probe;
+	}
+
+	/* Fit the rate found to the nearest supported rate. */
+	do {
+		if (rate_supported(sta, mode, rinfo[tmp].index)) {
+			sta->txrate = rinfo[tmp].index;
 			break;
 		}
-
-		newidx += back;
-	}
+		if (adj < 0)
+			tmp--;
+		else
+			tmp++;
+	} while (tmp < n_bitrates && tmp >= 0);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_rate_change(
 		&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
-		newidx, mode->rates[newidx].rate);
+		cur, mode->rates[cur].rate);
 #endif
 }
 
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 9e214da..973f1db 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -256,12 +256,10 @@
 {
 	struct proc_dir_entry *p;
 
-	p = create_proc_entry("eps", S_IRUGO, proc_net_sctp);
+	p = proc_create("eps", S_IRUGO, proc_net_sctp, &sctp_eps_seq_fops);
 	if (!p)
 		return -ENOMEM;
 
-	p->proc_fops = &sctp_eps_seq_fops;
-
 	return 0;
 }
 
@@ -367,12 +365,11 @@
 {
 	struct proc_dir_entry *p;
 
-	p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp);
+	p = proc_create("assocs", S_IRUGO, proc_net_sctp,
+			&sctp_assocs_seq_fops);
 	if (!p)
 		return -ENOMEM;
 
-	p->proc_fops = &sctp_assocs_seq_fops;
-
 	return 0;
 }