summary refs log tree commit diff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan.c38
-rw-r--r--net/8021q/vlan_dev.c14
-rw-r--r--net/8021q/vlanproc.c2
-rw-r--r--net/9p/error.c2
-rw-r--r--net/Kconfig2
-rw-r--r--net/appletalk/aarp.c25
-rw-r--r--net/appletalk/ddp.c6
-rw-r--r--net/atm/clip.c6
-rw-r--r--net/atm/lec.c29
-rw-r--r--net/atm/mpc.c2
-rw-r--r--net/atm/proc.c32
-rw-r--r--net/atm/svc.c2
-rw-r--r--net/ax25/af_ax25.c4
-rw-r--r--net/ax25/ax25_in.c2
-rw-r--r--net/bluetooth/l2cap.c2
-rw-r--r--net/bluetooth/rfcomm/sock.c2
-rw-r--r--net/bluetooth/sco.c2
-rw-r--r--net/bridge/br_netfilter.c14
-rw-r--r--net/bridge/br_netlink.c4
-rw-r--r--net/bridge/br_notify.c2
-rw-r--r--net/bridge/br_stp_bpdu.c2
-rw-r--r--net/bridge/br_sysfs_br.c6
-rw-r--r--net/can/af_can.c4
-rw-r--r--net/can/bcm.c2
-rw-r--r--net/can/raw.c2
-rw-r--r--net/core/dev.c28
-rw-r--r--net/core/dev_mcast.c37
-rw-r--r--net/core/dst.c15
-rw-r--r--net/core/fib_rules.c8
-rw-r--r--net/core/neighbour.c171
-rw-r--r--net/core/netpoll.c6
-rw-r--r--net/core/pktgen.c2
-rw-r--r--net/core/rtnetlink.c16
-rw-r--r--net/core/skbuff.c94
-rw-r--r--net/core/sock.c150
-rw-r--r--net/core/sysctl_net_core.c12
-rw-r--r--net/dccp/dccp.h6
-rw-r--r--net/dccp/ipv4.c23
-rw-r--r--net/dccp/ipv6.c43
-rw-r--r--net/dccp/minisocks.c2
-rw-r--r--net/decnet/af_decnet.c25
-rw-r--r--net/decnet/dn_dev.c6
-rw-r--r--net/decnet/dn_fib.c4
-rw-r--r--net/decnet/dn_route.c6
-rw-r--r--net/decnet/dn_table.c2
-rw-r--r--net/econet/af_econet.c4
-rw-r--r--net/ieee80211/Kconfig1
-rw-r--r--net/ieee80211/Makefile1
-rw-r--r--net/ieee80211/softmac/Kconfig12
-rw-r--r--net/ieee80211/softmac/Makefile9
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c489
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c413
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_event.c189
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c488
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c568
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h244
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_scan.c254
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c508
-rw-r--r--net/ipv4/af_inet.c45
-rw-r--r--net/ipv4/arp.c58
-rw-r--r--net/ipv4/cipso_ipv4.c1
-rw-r--r--net/ipv4/devinet.c35
-rw-r--r--net/ipv4/fib_frontend.c20
-rw-r--r--net/ipv4/fib_hash.c5
-rw-r--r--net/ipv4/fib_rules.c2
-rw-r--r--net/ipv4/fib_trie.c184
-rw-r--r--net/ipv4/icmp.c188
-rw-r--r--net/ipv4/igmp.c45
-rw-r--r--net/ipv4/inet_connection_sock.c17
-rw-r--r--net/ipv4/inet_fragment.c10
-rw-r--r--net/ipv4/inet_hashtables.c24
-rw-r--r--net/ipv4/inet_timewait_sock.c3
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_fragment.c24
-rw-r--r--net/ipv4/ip_gre.c6
-rw-r--r--net/ipv4/ip_input.c19
-rw-r--r--net/ipv4/ip_options.c63
-rw-r--r--net/ipv4/ip_output.c28
-rw-r--r--net/ipv4/ip_sockglue.c13
-rw-r--r--net/ipv4/ipconfig.c11
-rw-r--r--net/ipv4/ipip.c2
-rw-r--r--net/ipv4/ipmr.c12
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c4
-rw-r--r--net/ipv4/netfilter/arp_tables.c23
-rw-r--r--net/ipv4/netfilter/ip_queue.c2
-rw-r--r--net/ipv4/netfilter/ip_tables.c18
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c2
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c18
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c556
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c12
-rw-r--r--net/ipv4/proc.c71
-rw-r--r--net/ipv4/raw.c47
-rw-r--r--net/ipv4/route.c174
-rw-r--r--net/ipv4/syncookies.c13
-rw-r--r--net/ipv4/sysctl_net_ipv4.c162
-rw-r--r--net/ipv4/tcp.c18
-rw-r--r--net/ipv4/tcp_cubic.c35
-rw-r--r--net/ipv4/tcp_input.c49
-rw-r--r--net/ipv4/tcp_ipv4.c127
-rw-r--r--net/ipv4/tcp_minisocks.c36
-rw-r--r--net/ipv4/tcp_output.c5
-rw-r--r--net/ipv4/tcp_timer.c5
-rw-r--r--net/ipv4/udp.c134
-rw-r--r--net/ipv4/udp_impl.h6
-rw-r--r--net/ipv4/udplite.c62
-rw-r--r--net/ipv4/xfrm4_policy.c2
-rw-r--r--net/ipv6/Makefile1
-rw-r--r--net/ipv6/addrconf.c647
-rw-r--r--net/ipv6/addrlabel.c25
-rw-r--r--net/ipv6/af_inet6.c221
-rw-r--r--net/ipv6/anycast.c38
-rw-r--r--net/ipv6/fib6_rules.c113
-rw-r--r--net/ipv6/icmp.c141
-rw-r--r--net/ipv6/inet6_hashtables.c10
-rw-r--r--net/ipv6/ip6_fib.c294
-rw-r--r--net/ipv6/ip6_flowlabel.c101
-rw-r--r--net/ipv6/ip6_input.c5
-rw-r--r--net/ipv6/ip6_output.c32
-rw-r--r--net/ipv6/ip6_tunnel.c8
-rw-r--r--net/ipv6/ipv6_sockglue.c217
-rw-r--r--net/ipv6/mcast.c207
-rw-r--r--net/ipv6/mip6.c20
-rw-r--r--net/ipv6/ndisc.c166
-rw-r--r--net/ipv6/netfilter.c4
-rw-r--r--net/ipv6/netfilter/ip6_queue.c2
-rw-r--r--net/ipv6/netfilter/ip6_tables.c18
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c4
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c15
-rw-r--r--net/ipv6/proc.c73
-rw-r--r--net/ipv6/raw.c40
-rw-r--r--net/ipv6/reassembly.c19
-rw-r--r--net/ipv6/route.c606
-rw-r--r--net/ipv6/sit.c6
-rw-r--r--net/ipv6/syncookies.c267
-rw-r--r--net/ipv6/sysctl_net_ipv6.c15
-rw-r--r--net/ipv6/tcp_ipv6.c192
-rw-r--r--net/ipv6/udp.c39
-rw-r--r--net/ipv6/udp_impl.h2
-rw-r--r--net/ipv6/udplite.c40
-rw-r--r--net/ipv6/xfrm6_input.c55
-rw-r--r--net/ipv6/xfrm6_policy.c9
-rw-r--r--net/ipv6/xfrm6_state.c171
-rw-r--r--net/ipv6/xfrm6_tunnel.c45
-rw-r--r--net/ipx/af_ipx.c4
-rw-r--r--net/irda/af_irda.c180
-rw-r--r--net/irda/discovery.c4
-rw-r--r--net/irda/ircomm/ircomm_core.c46
-rw-r--r--net/irda/ircomm/ircomm_event.c12
-rw-r--r--net/irda/ircomm/ircomm_lmp.c30
-rw-r--r--net/irda/ircomm/ircomm_param.c32
-rw-r--r--net/irda/ircomm/ircomm_ttp.c26
-rw-r--r--net/irda/ircomm/ircomm_tty.c90
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c78
-rw-r--r--net/irda/ircomm/ircomm_tty_ioctl.c18
-rw-r--r--net/irda/irda_device.c18
-rw-r--r--net/irda/iriap.c76
-rw-r--r--net/irda/iriap_event.c38
-rw-r--r--net/irda/irias_object.c44
-rw-r--r--net/irda/irlan/irlan_client.c48
-rw-r--r--net/irda/irlan/irlan_client_event.c64
-rw-r--r--net/irda/irlan/irlan_common.c72
-rw-r--r--net/irda/irlan/irlan_eth.c18
-rw-r--r--net/irda/irlan/irlan_event.c4
-rw-r--r--net/irda/irlan/irlan_filter.c4
-rw-r--r--net/irda/irlan/irlan_provider.c30
-rw-r--r--net/irda/irlan/irlan_provider_event.c16
-rw-r--r--net/irda/irlap.c56
-rw-r--r--net/irda/irlap_event.c122
-rw-r--r--net/irda/irlap_frame.c76
-rw-r--r--net/irda/irlmp.c112
-rw-r--r--net/irda/irlmp_event.c94
-rw-r--r--net/irda/irlmp_frame.c36
-rw-r--r--net/irda/irmod.c2
-rw-r--r--net/irda/irnet/irnet.h10
-rw-r--r--net/irda/irnetlink.c4
-rw-r--r--net/irda/irqueue.c8
-rw-r--r--net/irda/irttp.c108
-rw-r--r--net/irda/parameters.c42
-rw-r--r--net/irda/qos.c24
-rw-r--r--net/irda/wrapper.c18
-rw-r--r--net/key/af_key.c120
-rw-r--r--net/llc/af_llc.c16
-rw-r--r--net/llc/llc_c_ac.c2
-rw-r--r--net/llc/llc_c_ev.c8
-rw-r--r--net/llc/llc_conn.c26
-rw-r--r--net/llc/llc_input.c6
-rw-r--r--net/mac80211/Kconfig33
-rw-r--r--net/mac80211/Makefile9
-rw-r--r--net/mac80211/cfg.c396
-rw-r--r--net/mac80211/debugfs.c47
-rw-r--r--net/mac80211/debugfs_netdev.c214
-rw-r--r--net/mac80211/debugfs_sta.c179
-rw-r--r--net/mac80211/debugfs_sta.h2
-rw-r--r--net/mac80211/ieee80211.c984
-rw-r--r--net/mac80211/ieee80211_i.h513
-rw-r--r--net/mac80211/ieee80211_iface.c48
-rw-r--r--net/mac80211/ieee80211_ioctl.c232
-rw-r--r--net/mac80211/ieee80211_key.h26
-rw-r--r--net/mac80211/ieee80211_rate.c23
-rw-r--r--net/mac80211/ieee80211_rate.h44
-rw-r--r--net/mac80211/ieee80211_sta.c1682
-rw-r--r--net/mac80211/key.c192
-rw-r--r--net/mac80211/mesh.c445
-rw-r--r--net/mac80211/mesh.h300
-rw-r--r--net/mac80211/mesh_hwmp.c857
-rw-r--r--net/mac80211/mesh_pathtbl.c516
-rw-r--r--net/mac80211/mesh_plink.c763
-rw-r--r--net/mac80211/rc80211_pid_algo.c122
-rw-r--r--net/mac80211/rc80211_simple.c400
-rw-r--r--net/mac80211/regdomain.c152
-rw-r--r--net/mac80211/rx.c867
-rw-r--r--net/mac80211/sta_info.c681
-rw-r--r--net/mac80211/sta_info.h354
-rw-r--r--net/mac80211/tkip.c68
-rw-r--r--net/mac80211/tkip.h2
-rw-r--r--net/mac80211/tx.c727
-rw-r--r--net/mac80211/util.c170
-rw-r--r--net/mac80211/wep.c40
-rw-r--r--net/mac80211/wep.h8
-rw-r--r--net/mac80211/wme.c139
-rw-r--r--net/mac80211/wme.h23
-rw-r--r--net/mac80211/wpa.c152
-rw-r--r--net/mac80211/wpa.h24
-rw-r--r--net/netfilter/core.c8
-rw-r--r--net/netfilter/nf_conntrack_amanda.c14
-rw-r--r--net/netfilter/nf_conntrack_expect.c81
-rw-r--r--net/netfilter/nf_conntrack_ftp.c10
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c66
-rw-r--r--net/netfilter/nf_conntrack_helper.c3
-rw-r--r--net/netfilter/nf_conntrack_irc.c10
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c11
-rw-r--r--net/netfilter/nf_conntrack_pptp.c14
-rw-r--r--net/netfilter/nf_conntrack_sane.c11
-rw-r--r--net/netfilter/nf_conntrack_sip.c1386
-rw-r--r--net/netfilter/nf_conntrack_standalone.c2
-rw-r--r--net/netfilter/nf_conntrack_tftp.c11
-rw-r--r--net/netfilter/nf_sockopt.c2
-rw-r--r--net/netfilter/nfnetlink_queue.c2
-rw-r--r--net/netfilter/x_tables.c4
-rw-r--r--net/netlabel/netlabel_unlabeled.c2
-rw-r--r--net/netlink/af_netlink.c83
-rw-r--r--net/netrom/af_netrom.c4
-rw-r--r--net/packet/af_packet.c33
-rw-r--r--net/rose/af_rose.c4
-rw-r--r--net/rxrpc/ar-internal.h8
-rw-r--r--net/rxrpc/ar-proc.c4
-rw-r--r--net/sched/act_api.c4
-rw-r--r--net/sched/cls_api.c4
-rw-r--r--net/sched/em_meta.c4
-rw-r--r--net/sched/sch_api.c10
-rw-r--r--net/sctp/associola.c8
-rw-r--r--net/sctp/chunk.c18
-rw-r--r--net/sctp/command.c10
-rw-r--r--net/sctp/input.c2
-rw-r--r--net/sctp/ipv6.c17
-rw-r--r--net/sctp/output.c14
-rw-r--r--net/sctp/outqueue.c17
-rw-r--r--net/sctp/proc.c20
-rw-r--r--net/sctp/protocol.c17
-rw-r--r--net/sctp/sm_make_chunk.c2
-rw-r--r--net/sctp/sm_sideeffect.c6
-rw-r--r--net/sctp/sm_statefuns.c28
-rw-r--r--net/sctp/socket.c23
-rw-r--r--net/sctp/transport.c10
-rw-r--r--net/socket.c4
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/clnt.c44
-rw-r--r--net/sunrpc/rpc_pipe.c12
-rw-r--r--net/sunrpc/rpcb_clnt.c20
-rw-r--r--net/sunrpc/xprtsock.c2
-rw-r--r--net/tipc/core.c11
-rw-r--r--net/tipc/core.h6
-rw-r--r--net/tipc/eth_media.c4
-rw-r--r--net/tipc/link.c16
-rw-r--r--net/tipc/msg.c16
-rw-r--r--net/tipc/msg.h50
-rw-r--r--net/tipc/port.c12
-rw-r--r--net/tipc/socket.c141
-rw-r--r--net/unix/af_unix.c28
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c41
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c552
-rw-r--r--net/wireless/reg.c159
-rw-r--r--net/wireless/util.c121
-rw-r--r--net/wireless/wext.c2
-rw-r--r--net/x25/af_x25.c4
-rw-r--r--net/x25/x25_dev.c2
-rw-r--r--net/xfrm/xfrm_policy.c132
-rw-r--r--net/xfrm/xfrm_state.c53
-rw-r--r--net/xfrm/xfrm_user.c71
295 files changed, 16223 insertions, 10870 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index b33410abfd6b..5975ec3be7f3 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -106,29 +106,35 @@ static void vlan_group_free(struct vlan_group *grp)
 static struct vlan_group *vlan_group_alloc(int ifindex)
 {
 	struct vlan_group *grp;
-	unsigned int size;
-	unsigned int i;
 
 	grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
 	if (!grp)
 		return NULL;
 
-	size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
-
-	for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
-		grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);
-		if (!grp->vlan_devices_arrays[i])
-			goto err;
-	}
-
 	grp->real_dev_ifindex = ifindex;
 	hlist_add_head_rcu(&grp->hlist,
 			   &vlan_group_hash[vlan_grp_hashfn(ifindex)]);
 	return grp;
+}
 
-err:
-	vlan_group_free(grp);
-	return NULL;
+static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid)
+{
+	struct net_device **array;
+	unsigned int size;
+
+	ASSERT_RTNL();
+
+	array = vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN];
+	if (array != NULL)
+		return 0;
+
+	size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
+	array = kzalloc(size, GFP_KERNEL);
+	if (array == NULL)
+		return -ENOBUFS;
+
+	vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN] = array;
+	return 0;
 }
 
 static void vlan_rcu_free(struct rcu_head *rcu)
@@ -247,6 +253,10 @@ int register_vlan_dev(struct net_device *dev)
 			return -ENOBUFS;
 	}
 
+	err = vlan_group_prealloc_vid(grp, vlan_id);
+	if (err < 0)
+		goto out_free_group;
+
 	err = register_netdevice(dev);
 	if (err < 0)
 		goto out_free_group;
@@ -394,7 +404,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
 	int i, flgs;
 	struct net_device *vlandev;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (is_vlan_dev(dev)) {
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 480ea90e7dcd..0e3b2d3e2339 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -153,7 +153,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 	struct net_device_stats *stats;
 	unsigned short vlan_TCI;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto err_free;
 
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -171,7 +171,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 	skb->dev = __find_vlan_dev(dev, vid);
 	if (!skb->dev) {
 		pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n",
-			 __FUNCTION__, (unsigned int)vid, dev->name);
+			 __func__, (unsigned int)vid, dev->name);
 		goto err_unlock;
 	}
 
@@ -187,7 +187,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev,
 						  ntohs(vhdr->h_vlan_TCI));
 
 	pr_debug("%s: priority: %u for TCI: %hu\n",
-		 __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI));
+		 __func__, skb->priority, ntohs(vhdr->h_vlan_TCI));
 
 	switch (skb->pkt_type) {
 	case PACKET_BROADCAST: /* Yeah, stats collect these together.. */
@@ -268,7 +268,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 	struct net_device *vdev = dev;
 
 	pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n",
-		 __FUNCTION__, skb, type, len, vlan_dev_info(dev)->vlan_id,
+		 __func__, skb, type, len, vlan_dev_info(dev)->vlan_id,
 		 daddr);
 
 	/* build vlan header only if re_order_header flag is NOT set.  This
@@ -340,7 +340,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
 			return -ENOMEM;
 		}
 		vlan_dev_info(vdev)->cnt_inc_headroom_on_tx++;
-		pr_debug("%s: %s: had to grow skb\n", __FUNCTION__, vdev->name);
+		pr_debug("%s: %s: had to grow skb\n", __func__, vdev->name);
 	}
 
 	if (build_vlan_header) {
@@ -382,7 +382,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		vlan_dev_info(dev)->cnt_encap_on_xmit++;
 
 		pr_debug("%s: proto to encap: 0x%hx\n",
-			 __FUNCTION__, ntohs(veth->h_vlan_proto));
+			 __func__, ntohs(veth->h_vlan_proto));
 		/* Construct the second two bytes. This field looks something
 		 * like:
 		 * usr_priority: 3 bits	 (high bits)
@@ -403,7 +403,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 
 	pr_debug("%s: about to send skb: %p to dev: %s\n",
-		__FUNCTION__, skb, skb->dev->name);
+		__func__, skb, skb->dev->name);
 	pr_debug("  " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n",
 		 veth->h_dest[0], veth->h_dest[1], veth->h_dest[2],
 		 veth->h_dest[3], veth->h_dest[4], veth->h_dest[5],
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index 9671aa51af2c..24cd96ee8109 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -168,7 +168,7 @@ int __init vlan_proc_init(void)
 	return 0;
 
 err:
-	pr_err("%s: can't create entry in proc filesystem!\n", __FUNCTION__);
+	pr_err("%s: can't create entry in proc filesystem!\n", __func__);
 	vlan_proc_cleanup();
 	return -ENOBUFS;
 }
diff --git a/net/9p/error.c b/net/9p/error.c
index ab2458b6c903..64104b9cb422 100644
--- a/net/9p/error.c
+++ b/net/9p/error.c
@@ -230,7 +230,7 @@ int p9_errstr2errno(char *errstr, int len)
 	if (errno == 0) {
 		/* TODO: if error isn't found, add it dynamically */
 		errstr[len] = 0;
-		printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
+		printk(KERN_ERR "%s: errstr :%s: not found\n", __func__,
 		       errstr);
 		errno = 1;
 	}
diff --git a/net/Kconfig b/net/Kconfig
index 6627c6ae5db6..acbf7c60e89b 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -45,7 +45,7 @@ config INET
 	---help---
 	  These are the protocols used on the Internet and on most local
 	  Ethernets. It is highly recommended to say Y here (this will enlarge
-	  your kernel by about 144 KB), since some programs (e.g. the X window
+	  your kernel by about 400 KB), since some programs (e.g. the X window
 	  system) use TCP/IP even if your machine is not connected to any
 	  other computer. You will get the so-called loopback device which
 	  allows you to ping yourself (great fun, that!).
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 18058bbc7962..25aa37ce9430 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -333,7 +333,7 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event,
 	struct net_device *dev = ptr;
 	int ct;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event == NETDEV_DOWN) {
@@ -716,7 +716,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev,
 	struct atalk_addr sa, *ma, da;
 	struct atalk_iface *ifa;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto out0;
 
 	/* We only do Ethernet SNAP AARP. */
@@ -1033,25 +1033,8 @@ static const struct seq_operations aarp_seq_ops = {
 
 static int aarp_seq_open(struct inode *inode, struct file *file)
 {
-	struct seq_file *seq;
-	int rc = -ENOMEM;
-	struct aarp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
-	if (!s)
-		goto out;
-
-	rc = seq_open(file, &aarp_seq_ops);
-	if (rc)
-		goto out_kfree;
-
-	seq	     = file->private_data;
-	seq->private = s;
-	memset(s, 0, sizeof(*s));
-out:
-	return rc;
-out_kfree:
-	kfree(s);
-	goto out;
+	return seq_open_private(file, &aarp_seq_ops,
+			sizeof(struct aarp_iter_state));
 }
 
 const struct file_operations atalk_seq_arp_fops = {
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 3be55c8ca4ef..44cd42f7786b 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -648,7 +648,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event,
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event == NETDEV_DOWN)
@@ -1405,7 +1405,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
 	int origlen;
 	__u16 len_hops;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto freeit;
 
 	/* Don't mangle buffer if shared */
@@ -1493,7 +1493,7 @@ freeit:
 static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
 		     struct packet_type *pt, struct net_device *orig_dev)
 {
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto freeit;
 
 	/* Expand any short form frames */
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 2ab1e36098fd..6f8223ebf551 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -612,7 +612,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
 {
 	struct net_device *dev = arg;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event == NETDEV_UNREGISTER) {
@@ -648,10 +648,6 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event,
 	struct in_device *in_dev;
 
 	in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;
-	if (!in_dev || !in_dev->dev) {
-		printk(KERN_WARNING "clip_inet_event: no device\n");
-		return NOTIFY_DONE;
-	}
 	/*
 	 * Transitions are of the down-change-up type, so it's sufficient to
 	 * handle the change on up.
diff --git a/net/atm/lec.c b/net/atm/lec.c
index a2efa7ff41f1..aa3785ebf6d1 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1169,32 +1169,7 @@ static const struct seq_operations lec_seq_ops = {
 
 static int lec_seq_open(struct inode *inode, struct file *file)
 {
-	struct lec_state *state;
-	struct seq_file *seq;
-	int rc = -EAGAIN;
-
-	state = kmalloc(sizeof(*state), GFP_KERNEL);
-	if (!state) {
-		rc = -ENOMEM;
-		goto out;
-	}
-
-	rc = seq_open(file, &lec_seq_ops);
-	if (rc)
-		goto out_kfree;
-	seq = file->private_data;
-	seq->private = state;
-out:
-	return rc;
-
-out_kfree:
-	kfree(state);
-	goto out;
-}
-
-static int lec_seq_release(struct inode *inode, struct file *file)
-{
-	return seq_release_private(inode, file);
+	return seq_open_private(file, &lec_seq_ops, sizeof(struct lec_state));
 }
 
 static const struct file_operations lec_seq_fops = {
@@ -1202,7 +1177,7 @@ static const struct file_operations lec_seq_fops = {
 	.open = lec_seq_open,
 	.read = seq_read,
 	.llseek = seq_lseek,
-	.release = lec_seq_release,
+	.release = seq_release_private,
 };
 #endif
 
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index 9c7f712fc7e9..9db332e7a6c0 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -964,7 +964,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo
 
 	dev = (struct net_device *)dev_ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (dev->name == NULL || strncmp(dev->name, "lec", 3))
diff --git a/net/atm/proc.c b/net/atm/proc.c
index e9693aed7ef8..b995b66b5585 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -114,31 +114,13 @@ static int __vcc_seq_open(struct inode *inode, struct file *file,
 	int family, const struct seq_operations *ops)
 {
 	struct vcc_state *state;
-	struct seq_file *seq;
-	int rc = -ENOMEM;
 
-	state = kmalloc(sizeof(*state), GFP_KERNEL);
-	if (!state)
-		goto out;
-
-	rc = seq_open(file, ops);
-	if (rc)
-		goto out_kfree;
+	state = __seq_open_private(file, ops, sizeof(*state));
+	if (state == NULL)
+		return -ENOMEM;
 
 	state->family = family;
-
-	seq = file->private_data;
-	seq->private = state;
-out:
-	return rc;
-out_kfree:
-	kfree(state);
-	goto out;
-}
-
-static int vcc_seq_release(struct inode *inode, struct file *file)
-{
-	return seq_release_private(inode, file);
+	return 0;
 }
 
 static void *vcc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -314,7 +296,7 @@ static const struct file_operations pvc_seq_fops = {
 	.open		= pvc_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= vcc_seq_release,
+	.release	= seq_release_private,
 };
 
 static int vcc_seq_show(struct seq_file *seq, void *v)
@@ -348,7 +330,7 @@ static const struct file_operations vcc_seq_fops = {
 	.open		= vcc_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= vcc_seq_release,
+	.release	= seq_release_private,
 };
 
 static int svc_seq_show(struct seq_file *seq, void *v)
@@ -383,7 +365,7 @@ static const struct file_operations svc_seq_fops = {
 	.open		= svc_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= vcc_seq_release,
+	.release	= seq_release_private,
 };
 
 static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
diff --git a/net/atm/svc.c b/net/atm/svc.c
index daf9a48a7db0..de1e4f2f3a43 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -326,7 +326,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
 
 	lock_sock(sk);
 
-	error = svc_create(sk->sk_net, newsock,0);
+	error = svc_create(sock_net(sk), newsock,0);
 	if (error)
 		goto out;
 
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 48bfcc741f25..2712544cf0ca 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -116,7 +116,7 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event,
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* Reject non AX.25 devices */
@@ -869,7 +869,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
 	struct sock *sk;
 	ax25_cb *ax25, *oax25;
 
-	sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC,	osk->sk_prot);
+	sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC,	osk->sk_prot);
 	if (sk == NULL)
 		return NULL;
 
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index d1be080dcb25..33790a8efbc8 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -451,7 +451,7 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
 	skb->sk = NULL;		/* Initially we don't know who it's for */
 	skb->destructor = NULL;	/* Who initializes this, dammit?! */
 
-	if (dev->nd_net != &init_net) {
+	if (dev_net(dev) != &init_net) {
 		kfree_skb(skb);
 		return 0;
 	}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 2957df4b6c0b..a4849f2c1d81 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -1499,7 +1499,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 		goto response;
 	}
 
-	sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC);
+	sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
 	if (!sk)
 		goto response;
 
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index af4e3934ee84..5083adcbfae5 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -868,7 +868,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 		goto done;
 	}
 
-	sk = rfcomm_sock_alloc(parent->sk_net, NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
+	sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
 	if (!sk)
 		goto done;
 
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index cd887cdca426..b0d487e2db20 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -803,7 +803,7 @@ static void sco_conn_ready(struct sco_conn *conn)
 
 		bh_lock_sock(parent);
 
-		sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC);
+		sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC);
 		if (!sk) {
 			bh_unlock_sock(parent);
 			goto done;
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 1c0efd8ad9f3..0278a069c6f1 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -223,8 +223,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
 	}
 	nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING;
 
-	skb->dst = (struct dst_entry *)&__fake_rtable;
-	dst_hold(skb->dst);
+	skb->rtable = &__fake_rtable;
+	dst_hold(&__fake_rtable.u.dst);
 
 	skb->dev = nf_bridge->physindev;
 	nf_bridge_push_encap_header(skb);
@@ -388,8 +388,8 @@ bridged_dnat:
 			skb->pkt_type = PACKET_HOST;
 		}
 	} else {
-		skb->dst = (struct dst_entry *)&__fake_rtable;
-		dst_hold(skb->dst);
+		skb->rtable = &__fake_rtable;
+		dst_hold(&__fake_rtable.u.dst);
 	}
 
 	skb->dev = nf_bridge->physindev;
@@ -608,9 +608,9 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb,
 				   const struct net_device *out,
 				   int (*okfn)(struct sk_buff *))
 {
-	if (skb->dst == (struct dst_entry *)&__fake_rtable) {
-		dst_release(skb->dst);
-		skb->dst = NULL;
+	if (skb->rtable == &__fake_rtable) {
+		dst_release(&__fake_rtable.u.dst);
+		skb->rtable = NULL;
 	}
 
 	return NF_ACCEPT;
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index f5d69336d97b..f155e6ce8a21 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -108,7 +108,7 @@ errout:
  */
 static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct net_device *dev;
 	int idx;
 
@@ -140,7 +140,7 @@ skip:
  */
 static int br_rtm_setlink(struct sk_buff *skb,  struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifinfomsg *ifm;
 	struct nlattr *protinfo;
 	struct net_device *dev;
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 07ac3ae68d8f..00644a544e3c 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -37,7 +37,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
 	struct net_bridge_port *p = dev->br_port;
 	struct net_bridge *br;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* not a port of a bridge */
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index 0edbd2a1c3f3..8deab645ef75 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -142,7 +142,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
 	struct net_bridge *br;
 	const unsigned char *buf;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto err;
 
 	if (!p)
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 9cf0538d1717..27d6a511c8c1 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -415,21 +415,21 @@ int br_sysfs_addbr(struct net_device *dev)
 	err = sysfs_create_group(brobj, &bridge_group);
 	if (err) {
 		pr_info("%s: can't create group %s/%s\n",
-			__FUNCTION__, dev->name, bridge_group.name);
+			__func__, dev->name, bridge_group.name);
 		goto out1;
 	}
 
 	err = sysfs_create_bin_file(brobj, &bridge_forward);
 	if (err) {
 		pr_info("%s: can't create attribute file %s/%s\n",
-			__FUNCTION__, dev->name, bridge_forward.attr.name);
+			__func__, dev->name, bridge_forward.attr.name);
 		goto out2;
 	}
 
 	br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj);
 	if (!br->ifobj) {
 		pr_info("%s: can't add kobject (directory) %s/%s\n",
-			__FUNCTION__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
+			__func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR);
 		goto out3;
 	}
 	return 0;
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 36b9f22ed83a..2759b76f731c 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -599,7 +599,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev,
 	struct dev_rcv_lists *d;
 	int matches;
 
-	if (dev->type != ARPHRD_CAN || dev->nd_net != &init_net) {
+	if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) {
 		kfree_skb(skb);
 		return 0;
 	}
@@ -710,7 +710,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
 	struct net_device *dev = (struct net_device *)data;
 	struct dev_rcv_lists *d;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (dev->type != ARPHRD_CAN)
diff --git a/net/can/bcm.c b/net/can/bcm.c
index bd4282dae754..e9f99b2c6bc9 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1285,7 +1285,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
 	struct bcm_op *op;
 	int notify_enodev = 0;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (dev->type != ARPHRD_CAN)
diff --git a/net/can/raw.c b/net/can/raw.c
index 94cd7f27c444..ead50c7c0d40 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -210,7 +210,7 @@ static int raw_notifier(struct notifier_block *nb,
 	struct raw_sock *ro = container_of(nb, struct raw_sock, notifier);
 	struct sock *sk = &ro->sk;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (dev->type != ARPHRD_CAN)
diff --git a/net/core/dev.c b/net/core/dev.c
index 460e7f99ce3e..7aa01125287e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -216,7 +216,7 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
 /* Device list insertion */
 static int list_netdevice(struct net_device *dev)
 {
-	struct net *net = dev->nd_net;
+	struct net *net = dev_net(dev);
 
 	ASSERT_RTNL();
 
@@ -852,8 +852,8 @@ int dev_alloc_name(struct net_device *dev, const char *name)
 	struct net *net;
 	int ret;
 
-	BUG_ON(!dev->nd_net);
-	net = dev->nd_net;
+	BUG_ON(!dev_net(dev));
+	net = dev_net(dev);
 	ret = __dev_alloc_name(net, name, buf);
 	if (ret >= 0)
 		strlcpy(dev->name, buf, IFNAMSIZ);
@@ -877,9 +877,9 @@ int dev_change_name(struct net_device *dev, char *newname)
 	struct net *net;
 
 	ASSERT_RTNL();
-	BUG_ON(!dev->nd_net);
+	BUG_ON(!dev_net(dev));
 
-	net = dev->nd_net;
+	net = dev_net(dev);
 	if (dev->flags & IFF_UP)
 		return -EBUSY;
 
@@ -2615,7 +2615,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v)
 
 	if (v == SEQ_START_TOKEN)
 		seq_puts(seq, "Type Device      Function\n");
-	else {
+	else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
 		if (pt->type == htons(ETH_P_ALL))
 			seq_puts(seq, "ALL ");
 		else
@@ -2639,7 +2639,8 @@ static const struct seq_operations ptype_seq_ops = {
 
 static int ptype_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open(file, &ptype_seq_ops);
+	return seq_open_net(inode, file, &ptype_seq_ops,
+			sizeof(struct seq_net_private));
 }
 
 static const struct file_operations ptype_seq_fops = {
@@ -2647,7 +2648,7 @@ static const struct file_operations ptype_seq_fops = {
 	.open    = ptype_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release,
+	.release = seq_release_net,
 };
 
 
@@ -3688,8 +3689,8 @@ int register_netdevice(struct net_device *dev)
 
 	/* When net_device's are persistent, this will be fatal. */
 	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
-	BUG_ON(!dev->nd_net);
-	net = dev->nd_net;
+	BUG_ON(!dev_net(dev));
+	net = dev_net(dev);
 
 	spin_lock_init(&dev->queue_lock);
 	spin_lock_init(&dev->_xmit_lock);
@@ -4010,7 +4011,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 	dev = (struct net_device *)
 		(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
 	dev->padded = (char *)dev - (char *)p;
-	dev->nd_net = &init_net;
+	dev_net_set(dev, &init_net);
 
 	if (sizeof_priv) {
 		dev->priv = ((char *)dev +
@@ -4021,6 +4022,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
 	}
 
 	dev->egress_subqueue_count = queue_count;
+	dev->gso_max_size = GSO_MAX_SIZE;
 
 	dev->get_stats = internal_stats;
 	netpoll_netdev_init(dev);
@@ -4134,7 +4136,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 
 	/* Get out if there is nothing todo */
 	err = 0;
-	if (dev->nd_net == net)
+	if (net_eq(dev_net(dev), net))
 		goto out;
 
 	/* Pick the destination device name, and ensure
@@ -4185,7 +4187,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
 	dev_addr_discard(dev);
 
 	/* Actually switch the network namespace */
-	dev->nd_net = net;
+	dev_net_set(dev, net);
 
 	/* Assign the new device name */
 	if (destname != dev->name)
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index cec582563e0d..f8a3455f4493 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -156,39 +156,14 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from)
 EXPORT_SYMBOL(dev_mc_unsync);
 
 #ifdef CONFIG_PROC_FS
-static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
-	__acquires(dev_base_lock)
-{
-	struct net *net = seq_file_net(seq);
-	struct net_device *dev;
-	loff_t off = 0;
-
-	read_lock(&dev_base_lock);
-	for_each_netdev(net, dev) {
-		if (off++ == *pos)
-			return dev;
-	}
-	return NULL;
-}
-
-static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
-{
-	++*pos;
-	return next_net_device((struct net_device *)v);
-}
-
-static void dev_mc_seq_stop(struct seq_file *seq, void *v)
-	__releases(dev_base_lock)
-{
-	read_unlock(&dev_base_lock);
-}
-
-
 static int dev_mc_seq_show(struct seq_file *seq, void *v)
 {
 	struct dev_addr_list *m;
 	struct net_device *dev = v;
 
+	if (v == SEQ_START_TOKEN)
+		return 0;
+
 	netif_tx_lock_bh(dev);
 	for (m = dev->mc_list; m; m = m->next) {
 		int i;
@@ -206,9 +181,9 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v)
 }
 
 static const struct seq_operations dev_mc_seq_ops = {
-	.start = dev_mc_seq_start,
-	.next  = dev_mc_seq_next,
-	.stop  = dev_mc_seq_stop,
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
 	.show  = dev_mc_seq_show,
 };
 
diff --git a/net/core/dst.c b/net/core/dst.c
index 7deef483c79f..fe03266130b6 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -259,6 +259,16 @@ again:
 	return NULL;
 }
 
+void dst_release(struct dst_entry *dst)
+{
+	if (dst) {
+		WARN_ON(atomic_read(&dst->__refcnt) < 1);
+		smp_mb__before_atomic_dec();
+		atomic_dec(&dst->__refcnt);
+	}
+}
+EXPORT_SYMBOL(dst_release);
+
 /* Dirty hack. We did it in 2.2 (in __dst_free),
  * we have _very_ good reasons not to repeat
  * this mistake in 2.3, but we have no choice
@@ -279,7 +289,7 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 	if (!unregister) {
 		dst->input = dst->output = dst_discard;
 	} else {
-		dst->dev = dst->dev->nd_net->loopback_dev;
+		dst->dev = dev_net(dst->dev)->loopback_dev;
 		dev_hold(dst->dev);
 		dev_put(dev);
 		if (dst->neighbour && dst->neighbour->dev == dev) {
@@ -295,9 +305,6 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void
 	struct net_device *dev = ptr;
 	struct dst_entry *dst, *last = NULL;
 
-	if (dev->nd_net != &init_net)
-		return NOTIFY_DONE;
-
 	switch (event) {
 	case NETDEV_UNREGISTER:
 	case NETDEV_DOWN:
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 42ccaf5b8509..540c07283e31 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -214,7 +214,7 @@ errout:
 
 static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct fib_rule_hdr *frh = nlmsg_data(nlh);
 	struct fib_rules_ops *ops = NULL;
 	struct fib_rule *rule, *r, *last = NULL;
@@ -352,7 +352,7 @@ errout:
 
 static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct fib_rule_hdr *frh = nlmsg_data(nlh);
 	struct fib_rules_ops *ops = NULL;
 	struct fib_rule *rule, *tmp;
@@ -534,7 +534,7 @@ skip:
 
 static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct fib_rules_ops *ops;
 	int idx = 0, family;
 
@@ -618,7 +618,7 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
 			    void *ptr)
 {
 	struct net_device *dev = ptr;
-	struct net *net = dev->nd_net;
+	struct net *net = dev_net(dev);
 	struct fib_rules_ops *ops;
 
 	ASSERT_RTNL();
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 19b8e003f150..75075c303c44 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -123,6 +123,7 @@ unsigned long neigh_rand_reach_time(unsigned long base)
 {
 	return (base ? (net_random() % base) + (base >> 1) : 0);
 }
+EXPORT_SYMBOL(neigh_rand_reach_time);
 
 
 static int neigh_forced_gc(struct neigh_table *tbl)
@@ -241,6 +242,7 @@ void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
 	neigh_flush_dev(tbl, dev);
 	write_unlock_bh(&tbl->lock);
 }
+EXPORT_SYMBOL(neigh_changeaddr);
 
 int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
 {
@@ -253,6 +255,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
 	pneigh_queue_purge(&tbl->proxy_queue);
 	return 0;
 }
+EXPORT_SYMBOL(neigh_ifdown);
 
 static struct neighbour *neigh_alloc(struct neigh_table *tbl)
 {
@@ -374,6 +377,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
 	read_unlock_bh(&tbl->lock);
 	return n;
 }
+EXPORT_SYMBOL(neigh_lookup);
 
 struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
 				     const void *pkey)
@@ -388,7 +392,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
 	hash_val = tbl->hash(pkey, NULL);
 	for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
 		if (!memcmp(n->primary_key, pkey, key_len) &&
-		    (net == n->dev->nd_net)) {
+		    net_eq(dev_net(n->dev), net)) {
 			neigh_hold(n);
 			NEIGH_CACHE_STAT_INC(tbl, hits);
 			break;
@@ -397,6 +401,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
 	read_unlock_bh(&tbl->lock);
 	return n;
 }
+EXPORT_SYMBOL(neigh_lookup_nodev);
 
 struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey,
 			       struct net_device *dev)
@@ -465,28 +470,44 @@ out_neigh_release:
 	neigh_release(n);
 	goto out;
 }
+EXPORT_SYMBOL(neigh_create);
 
-struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
-		struct net *net, const void *pkey, struct net_device *dev)
+static u32 pneigh_hash(const void *pkey, int key_len)
 {
-	struct pneigh_entry *n;
-	int key_len = tbl->key_len;
 	u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
 	hash_val ^= (hash_val >> 16);
 	hash_val ^= hash_val >> 8;
 	hash_val ^= hash_val >> 4;
 	hash_val &= PNEIGH_HASHMASK;
+	return hash_val;
+}
 
-	for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
+static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n,
+					      struct net *net,
+					      const void *pkey,
+					      int key_len,
+					      struct net_device *dev)
+{
+	while (n) {
 		if (!memcmp(n->key, pkey, key_len) &&
-		    (n->net == net) &&
+		    net_eq(pneigh_net(n), net) &&
 		    (n->dev == dev || !n->dev))
-			break;
+			return n;
+		n = n->next;
 	}
+	return NULL;
+}
 
-	return n;
+struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl,
+		struct net *net, const void *pkey, struct net_device *dev)
+{
+	int key_len = tbl->key_len;
+	u32 hash_val = pneigh_hash(pkey, key_len);
+
+	return __pneigh_lookup_1(tbl->phash_buckets[hash_val],
+				 net, pkey, key_len, dev);
 }
+EXPORT_SYMBOL_GPL(__pneigh_lookup);
 
 struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 				    struct net *net, const void *pkey,
@@ -494,26 +515,14 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 {
 	struct pneigh_entry *n;
 	int key_len = tbl->key_len;
-	u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
-	hash_val ^= (hash_val >> 16);
-	hash_val ^= hash_val >> 8;
-	hash_val ^= hash_val >> 4;
-	hash_val &= PNEIGH_HASHMASK;
+	u32 hash_val = pneigh_hash(pkey, key_len);
 
 	read_lock_bh(&tbl->lock);
-
-	for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
-		if (!memcmp(n->key, pkey, key_len) &&
-		    (n->net == net) &&
-		    (n->dev == dev || !n->dev)) {
-			read_unlock_bh(&tbl->lock);
-			goto out;
-		}
-	}
+	n = __pneigh_lookup_1(tbl->phash_buckets[hash_val],
+			      net, pkey, key_len, dev);
 	read_unlock_bh(&tbl->lock);
-	n = NULL;
-	if (!creat)
+
+	if (n || !creat)
 		goto out;
 
 	ASSERT_RTNL();
@@ -522,7 +531,9 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 	if (!n)
 		goto out;
 
+#ifdef CONFIG_NET_NS
 	n->net = hold_net(net);
+#endif
 	memcpy(n->key, pkey, key_len);
 	n->dev = dev;
 	if (dev)
@@ -544,6 +555,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
 out:
 	return n;
 }
+EXPORT_SYMBOL(pneigh_lookup);
 
 
 int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
@@ -551,25 +563,20 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey,
 {
 	struct pneigh_entry *n, **np;
 	int key_len = tbl->key_len;
-	u32 hash_val = *(u32 *)(pkey + key_len - 4);
-
-	hash_val ^= (hash_val >> 16);
-	hash_val ^= hash_val >> 8;
-	hash_val ^= hash_val >> 4;
-	hash_val &= PNEIGH_HASHMASK;
+	u32 hash_val = pneigh_hash(pkey, key_len);
 
 	write_lock_bh(&tbl->lock);
 	for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
 	     np = &n->next) {
 		if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
-		    (n->net == net)) {
+		    net_eq(pneigh_net(n), net)) {
 			*np = n->next;
 			write_unlock_bh(&tbl->lock);
 			if (tbl->pdestructor)
 				tbl->pdestructor(n);
 			if (n->dev)
 				dev_put(n->dev);
-			release_net(n->net);
+			release_net(pneigh_net(n));
 			kfree(n);
 			return 0;
 		}
@@ -592,7 +599,7 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
 					tbl->pdestructor(n);
 				if (n->dev)
 					dev_put(n->dev);
-				release_net(n->net);
+				release_net(pneigh_net(n));
 				kfree(n);
 				continue;
 			}
@@ -651,6 +658,7 @@ void neigh_destroy(struct neighbour *neigh)
 	atomic_dec(&neigh->tbl->entries);
 	kmem_cache_free(neigh->tbl->kmem_cachep, neigh);
 }
+EXPORT_SYMBOL(neigh_destroy);
 
 /* Neighbour state is suspicious;
    disable fast path.
@@ -931,6 +939,7 @@ out_unlock_bh:
 	write_unlock_bh(&neigh->lock);
 	return rc;
 }
+EXPORT_SYMBOL(__neigh_event_send);
 
 static void neigh_update_hhs(struct neighbour *neigh)
 {
@@ -1103,6 +1112,7 @@ out:
 
 	return err;
 }
+EXPORT_SYMBOL(neigh_update);
 
 struct neighbour *neigh_event_ns(struct neigh_table *tbl,
 				 u8 *lladdr, void *saddr,
@@ -1115,6 +1125,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
 			     NEIGH_UPDATE_F_OVERRIDE);
 	return neigh;
 }
+EXPORT_SYMBOL(neigh_event_ns);
 
 static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
 			  __be16 protocol)
@@ -1169,6 +1180,7 @@ int neigh_compat_output(struct sk_buff *skb)
 
 	return dev_queue_xmit(skb);
 }
+EXPORT_SYMBOL(neigh_compat_output);
 
 /* Slow and careful. */
 
@@ -1214,6 +1226,7 @@ out_kfree_skb:
 	kfree_skb(skb);
 	goto out;
 }
+EXPORT_SYMBOL(neigh_resolve_output);
 
 /* As fast as possible without hh cache */
 
@@ -1238,6 +1251,7 @@ int neigh_connected_output(struct sk_buff *skb)
 	}
 	return err;
 }
+EXPORT_SYMBOL(neigh_connected_output);
 
 static void neigh_proxy_process(unsigned long arg)
 {
@@ -1299,6 +1313,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
 	mod_timer(&tbl->proxy_timer, sched_next);
 	spin_unlock(&tbl->proxy_queue.lock);
 }
+EXPORT_SYMBOL(pneigh_enqueue);
 
 static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
 						      struct net *net, int ifindex)
@@ -1306,9 +1321,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
 	struct neigh_parms *p;
 
 	for (p = &tbl->parms; p; p = p->next) {
-		if (p->net != net)
-			continue;
-		if ((p->dev && p->dev->ifindex == ifindex) ||
+		if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) ||
 		    (!p->dev && !ifindex))
 			return p;
 	}
@@ -1322,7 +1335,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
 	struct neigh_parms *p, *ref;
 	struct net *net;
 
-	net = dev->nd_net;
+	net = dev_net(dev);
 	ref = lookup_neigh_params(tbl, net, 0);
 	if (!ref)
 		return NULL;
@@ -1342,7 +1355,9 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
 
 		dev_hold(dev);
 		p->dev = dev;
+#ifdef CONFIG_NET_NS
 		p->net = hold_net(net);
+#endif
 		p->sysctl_table = NULL;
 		write_lock_bh(&tbl->lock);
 		p->next		= tbl->parms.next;
@@ -1351,6 +1366,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
 	}
 	return p;
 }
+EXPORT_SYMBOL(neigh_parms_alloc);
 
 static void neigh_rcu_free_parms(struct rcu_head *head)
 {
@@ -1381,10 +1397,11 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms)
 	write_unlock_bh(&tbl->lock);
 	NEIGH_PRINTK1("neigh_parms_release: not found\n");
 }
+EXPORT_SYMBOL(neigh_parms_release);
 
 static void neigh_parms_destroy(struct neigh_parms *parms)
 {
-	release_net(parms->net);
+	release_net(neigh_parms_net(parms));
 	kfree(parms);
 }
 
@@ -1395,7 +1412,9 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
 	unsigned long now = jiffies;
 	unsigned long phsize;
 
+#ifdef CONFIG_NET_NS
 	tbl->parms.net = &init_net;
+#endif
 	atomic_set(&tbl->parms.refcnt, 1);
 	INIT_RCU_HEAD(&tbl->parms.rcu_head);
 	tbl->parms.reachable_time =
@@ -1441,6 +1460,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
 	tbl->last_flush = now;
 	tbl->last_rand	= now + tbl->parms.reachable_time * 20;
 }
+EXPORT_SYMBOL(neigh_table_init_no_netlink);
 
 void neigh_table_init(struct neigh_table *tbl)
 {
@@ -1462,6 +1482,7 @@ void neigh_table_init(struct neigh_table *tbl)
 		dump_stack();
 	}
 }
+EXPORT_SYMBOL(neigh_table_init);
 
 int neigh_table_clear(struct neigh_table *tbl)
 {
@@ -1499,10 +1520,11 @@ int neigh_table_clear(struct neigh_table *tbl)
 
 	return 0;
 }
+EXPORT_SYMBOL(neigh_table_clear);
 
 static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ndmsg *ndm;
 	struct nlattr *dst_attr;
 	struct neigh_table *tbl;
@@ -1568,7 +1590,7 @@ out:
 
 static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ndmsg *ndm;
 	struct nlattr *tb[NDA_MAX+1];
 	struct neigh_table *tbl;
@@ -1836,7 +1858,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = {
 
 static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct neigh_table *tbl;
 	struct ndtmsg *ndtmsg;
 	struct nlattr *tb[NDTA_MAX+1];
@@ -1961,7 +1983,7 @@ errout:
 
 static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int family, tidx, nidx = 0;
 	int tbl_skip = cb->args[0];
 	int neigh_skip = cb->args[1];
@@ -1982,7 +2004,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 			break;
 
 		for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
-			if (net != p->net)
+			if (!net_eq(neigh_parms_net(p), net))
 				continue;
 
 			if (nidx++ < neigh_skip)
@@ -2061,7 +2083,7 @@ static void neigh_update_notify(struct neighbour *neigh)
 static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 			    struct netlink_callback *cb)
 {
-	struct net * net = skb->sk->sk_net;
+	struct net * net = sock_net(skb->sk);
 	struct neighbour *n;
 	int rc, h, s_h = cb->args[1];
 	int idx, s_idx = idx = cb->args[2];
@@ -2074,7 +2096,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
 			s_idx = 0;
 		for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
 			int lidx;
-			if (n->dev->nd_net != net)
+			if (dev_net(n->dev) != net)
 				continue;
 			lidx = idx++;
 			if (lidx < s_idx)
@@ -2169,7 +2191,7 @@ EXPORT_SYMBOL(__neigh_for_each_release);
 static struct neighbour *neigh_get_first(struct seq_file *seq)
 {
 	struct neigh_seq_state *state = seq->private;
-	struct net *net = state->p.net;
+	struct net *net = seq_file_net(seq);
 	struct neigh_table *tbl = state->tbl;
 	struct neighbour *n = NULL;
 	int bucket = state->bucket;
@@ -2179,7 +2201,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq)
 		n = tbl->hash_buckets[bucket];
 
 		while (n) {
-			if (n->dev->nd_net != net)
+			if (!net_eq(dev_net(n->dev), net))
 				goto next;
 			if (state->neigh_sub_iter) {
 				loff_t fakep = 0;
@@ -2210,7 +2232,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
 					loff_t *pos)
 {
 	struct neigh_seq_state *state = seq->private;
-	struct net *net = state->p.net;
+	struct net *net = seq_file_net(seq);
 	struct neigh_table *tbl = state->tbl;
 
 	if (state->neigh_sub_iter) {
@@ -2222,7 +2244,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq,
 
 	while (1) {
 		while (n) {
-			if (n->dev->nd_net != net)
+			if (!net_eq(dev_net(n->dev), net))
 				goto next;
 			if (state->neigh_sub_iter) {
 				void *v = state->neigh_sub_iter(state, n, pos);
@@ -2270,7 +2292,7 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
 static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
 {
 	struct neigh_seq_state *state = seq->private;
-	struct net * net = state->p.net;
+	struct net *net = seq_file_net(seq);
 	struct neigh_table *tbl = state->tbl;
 	struct pneigh_entry *pn = NULL;
 	int bucket = state->bucket;
@@ -2278,7 +2300,7 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
 	state->flags |= NEIGH_SEQ_IS_PNEIGH;
 	for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
 		pn = tbl->phash_buckets[bucket];
-		while (pn && (pn->net != net))
+		while (pn && !net_eq(pneigh_net(pn), net))
 			pn = pn->next;
 		if (pn)
 			break;
@@ -2293,7 +2315,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
 					    loff_t *pos)
 {
 	struct neigh_seq_state *state = seq->private;
-	struct net * net = state->p.net;
+	struct net *net = seq_file_net(seq);
 	struct neigh_table *tbl = state->tbl;
 
 	pn = pn->next;
@@ -2301,7 +2323,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
 		if (++state->bucket > PNEIGH_HASHMASK)
 			break;
 		pn = tbl->phash_buckets[state->bucket];
-		while (pn && (pn->net != net))
+		while (pn && !net_eq(pneigh_net(pn), net))
 			pn = pn->next;
 		if (pn)
 			break;
@@ -2506,7 +2528,7 @@ static inline size_t neigh_nlmsg_size(void)
 
 static void __neigh_notify(struct neighbour *n, int type, int flags)
 {
-	struct net *net = n->dev->nd_net;
+	struct net *net = dev_net(n->dev);
 	struct sk_buff *skb;
 	int err = -ENOBUFS;
 
@@ -2532,6 +2554,7 @@ void neigh_app_ns(struct neighbour *n)
 {
 	__neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
 }
+EXPORT_SYMBOL(neigh_app_ns);
 #endif /* CONFIG_ARPD */
 
 #ifdef CONFIG_SYSCTL
@@ -2763,7 +2786,8 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
 	neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name;
 	neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id;
 
-	t->sysctl_header = register_sysctl_paths(neigh_path, t->neigh_vars);
+	t->sysctl_header =
+		register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars);
 	if (!t->sysctl_header)
 		goto free_procname;
 
@@ -2777,6 +2801,7 @@ free:
 err:
 	return -ENOBUFS;
 }
+EXPORT_SYMBOL(neigh_sysctl_register);
 
 void neigh_sysctl_unregister(struct neigh_parms *p)
 {
@@ -2788,6 +2813,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p)
 		kfree(t);
 	}
 }
+EXPORT_SYMBOL(neigh_sysctl_unregister);
 
 #endif	/* CONFIG_SYSCTL */
 
@@ -2805,32 +2831,3 @@ static int __init neigh_init(void)
 
 subsys_initcall(neigh_init);
 
-EXPORT_SYMBOL(__neigh_event_send);
-EXPORT_SYMBOL(neigh_changeaddr);
-EXPORT_SYMBOL(neigh_compat_output);
-EXPORT_SYMBOL(neigh_connected_output);
-EXPORT_SYMBOL(neigh_create);
-EXPORT_SYMBOL(neigh_destroy);
-EXPORT_SYMBOL(neigh_event_ns);
-EXPORT_SYMBOL(neigh_ifdown);
-EXPORT_SYMBOL(neigh_lookup);
-EXPORT_SYMBOL(neigh_lookup_nodev);
-EXPORT_SYMBOL(neigh_parms_alloc);
-EXPORT_SYMBOL(neigh_parms_release);
-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(pneigh_enqueue);
-EXPORT_SYMBOL(pneigh_lookup);
-EXPORT_SYMBOL_GPL(__pneigh_lookup);
-
-#ifdef CONFIG_ARPD
-EXPORT_SYMBOL(neigh_app_ns);
-#endif
-#ifdef CONFIG_SYSCTL
-EXPORT_SYMBOL(neigh_sysctl_register);
-EXPORT_SYMBOL(neigh_sysctl_unregister);
-#endif
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index c635de52526c..b04d643fc3c7 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -390,9 +390,7 @@ static void arp_reply(struct sk_buff *skb)
 	if (skb->dev->flags & IFF_NOARP)
 		return;
 
-	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
-				 (2 * skb->dev->addr_len) +
-				 (2 * sizeof(u32)))))
+	if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
 		return;
 
 	skb_reset_network_header(skb);
@@ -420,7 +418,7 @@ static void arp_reply(struct sk_buff *skb)
 	    ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
 		return;
 
-	size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4);
+	size = arp_hdr_len(skb->dev);
 	send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev),
 			    LL_RESERVED_SPACE(np->dev));
 
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 20e63b302ba6..a803b442234c 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1874,7 +1874,7 @@ static int pktgen_device_event(struct notifier_block *unused,
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* It is OK that we do not hold the group lock right now,
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 2bd9c5f7627d..da99ac0871bf 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -662,7 +662,7 @@ nla_put_failure:
 
 static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int idx;
 	int s_idx = cb->args[0];
 	struct net_device *dev;
@@ -879,7 +879,7 @@ errout:
 
 static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifinfomsg *ifm;
 	struct net_device *dev;
 	int err;
@@ -921,7 +921,7 @@ errout:
 
 static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	const struct rtnl_link_ops *ops;
 	struct net_device *dev;
 	struct ifinfomsg *ifm;
@@ -972,7 +972,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname,
 			goto err_free;
 	}
 
-	dev->nd_net = net;
+	dev_net_set(dev, net);
 	dev->rtnl_link_ops = ops;
 
 	if (tb[IFLA_MTU])
@@ -1000,7 +1000,7 @@ err:
 
 static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	const struct rtnl_link_ops *ops;
 	struct net_device *dev;
 	struct ifinfomsg *ifm;
@@ -1132,7 +1132,7 @@ replay:
 
 static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifinfomsg *ifm;
 	struct nlattr *tb[IFLA_MAX+1];
 	struct net_device *dev = NULL;
@@ -1198,7 +1198,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
 
 void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
 {
-	struct net *net = dev->nd_net;
+	struct net *net = dev_net(dev);
 	struct sk_buff *skb;
 	int err = -ENOBUFS;
 
@@ -1227,7 +1227,7 @@ static int rtattr_max;
 
 static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	rtnl_doit_func doit;
 	int sz_idx, kind;
 	int min_len;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 0d0fd28a9041..e4259215607f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -263,6 +263,28 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
 	return skb;
 }
 
+/**
+ *	dev_alloc_skb - allocate an skbuff for receiving
+ *	@length: length to allocate
+ *
+ *	Allocate a new &sk_buff and assign it a usage count of one. The
+ *	buffer has unspecified headroom built in. Users should allocate
+ *	the headroom they think they need without accounting for the
+ *	built in space. The built in space is used for optimisations.
+ *
+ *	%NULL is returned if there is no free memory. Although this function
+ *	allocates memory it can be called from an interrupt.
+ */
+struct sk_buff *dev_alloc_skb(unsigned int length)
+{
+	/*
+	 * There is more code here than it seems:
+	 * __dev_alloc_skb is an inline
+	 */
+	return __dev_alloc_skb(length, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(dev_alloc_skb);
+
 static void skb_drop_list(struct sk_buff **listp)
 {
 	struct sk_buff *list = *listp;
@@ -857,6 +879,78 @@ free_skb:
 	return err;
 }
 
+/**
+ *	skb_put - add data to a buffer
+ *	@skb: buffer to use
+ *	@len: amount of data to add
+ *
+ *	This function extends the used data area of the buffer. If this would
+ *	exceed the total buffer size the kernel will panic. A pointer to the
+ *	first byte of the extra data is returned.
+ */
+unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
+{
+	unsigned char *tmp = skb_tail_pointer(skb);
+	SKB_LINEAR_ASSERT(skb);
+	skb->tail += len;
+	skb->len  += len;
+	if (unlikely(skb->tail > skb->end))
+		skb_over_panic(skb, len, __builtin_return_address(0));
+	return tmp;
+}
+EXPORT_SYMBOL(skb_put);
+
+/**
+ *	skb_push - add data to the start of a buffer
+ *	@skb: buffer to use
+ *	@len: amount of data to add
+ *
+ *	This function extends the used data area of the buffer at the buffer
+ *	start. If this would exceed the total buffer headroom the kernel will
+ *	panic. A pointer to the first byte of the extra data is returned.
+ */
+unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
+{
+	skb->data -= len;
+	skb->len  += len;
+	if (unlikely(skb->data<skb->head))
+		skb_under_panic(skb, len, __builtin_return_address(0));
+	return skb->data;
+}
+EXPORT_SYMBOL(skb_push);
+
+/**
+ *	skb_pull - remove data from the start of a buffer
+ *	@skb: buffer to use
+ *	@len: amount of data to remove
+ *
+ *	This function removes data from the start of a buffer, returning
+ *	the memory to the headroom. A pointer to the next data in the buffer
+ *	is returned. Once the data has been pulled future pushes will overwrite
+ *	the old data.
+ */
+unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
+{
+	return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
+}
+EXPORT_SYMBOL(skb_pull);
+
+/**
+ *	skb_trim - remove end from a buffer
+ *	@skb: buffer to alter
+ *	@len: new length
+ *
+ *	Cut the length of a buffer down by removing data from the tail. If
+ *	the buffer is already under the length specified it is not modified.
+ *	The skb must be linear.
+ */
+void skb_trim(struct sk_buff *skb, unsigned int len)
+{
+	if (skb->len > len)
+		__skb_trim(skb, len);
+}
+EXPORT_SYMBOL(skb_trim);
+
 /* Trims skb to length len. It can change skb pointers.
  */
 
diff --git a/net/core/sock.c b/net/core/sock.c
index 09cb3a74de7f..83e11f7260ff 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -372,7 +372,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen)
 {
 	int ret = -ENOPROTOOPT;
 #ifdef CONFIG_NETDEVICES
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	char devname[IFNAMSIZ];
 	int index;
 
@@ -958,7 +958,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
 		 */
 		sk->sk_prot = sk->sk_prot_creator = prot;
 		sock_lock_init(sk);
-		sk->sk_net = get_net(net);
+		sock_net_set(sk, get_net(net));
 	}
 
 	return sk;
@@ -981,12 +981,31 @@ void sk_free(struct sock *sk)
 
 	if (atomic_read(&sk->sk_omem_alloc))
 		printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
-		       __FUNCTION__, atomic_read(&sk->sk_omem_alloc));
+		       __func__, atomic_read(&sk->sk_omem_alloc));
 
-	put_net(sk->sk_net);
+	put_net(sock_net(sk));
 	sk_prot_free(sk->sk_prot_creator, sk);
 }
 
+/*
+ * Last sock_put should drop referrence to sk->sk_net. It has already
+ * been dropped in sk_change_net. Taking referrence to stopping namespace
+ * is not an option.
+ * Take referrence to a socket to remove it from hash _alive_ and after that
+ * destroy it in the context of init_net.
+ */
+void sk_release_kernel(struct sock *sk)
+{
+	if (sk == NULL || sk->sk_socket == NULL)
+		return;
+
+	sock_hold(sk);
+	sock_release(sk->sk_socket);
+	sock_net_set(sk, get_net(&init_net));
+	sock_put(sk);
+}
+EXPORT_SYMBOL(sk_release_kernel);
+
 struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 {
 	struct sock *newsk;
@@ -998,7 +1017,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 		sock_copy(newsk, sk);
 
 		/* SANITY */
-		get_net(newsk->sk_net);
+		get_net(sock_net(newsk));
 		sk_node_init(&newsk->sk_node);
 		sock_lock_init(newsk);
 		bh_lock_sock(newsk);
@@ -1076,10 +1095,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 	if (sk->sk_route_caps & NETIF_F_GSO)
 		sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
 	if (sk_can_gso(sk)) {
-		if (dst->header_len)
+		if (dst->header_len) {
 			sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
-		else
+		} else {
 			sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
+			sk->sk_gso_max_size = dst->dev->gso_max_size;
+		}
 	}
 }
 EXPORT_SYMBOL_GPL(sk_setup_caps);
@@ -1919,16 +1940,113 @@ EXPORT_SYMBOL(sk_common_release);
 static DEFINE_RWLOCK(proto_list_lock);
 static LIST_HEAD(proto_list);
 
+#ifdef CONFIG_PROC_FS
+#define PROTO_INUSE_NR	64	/* should be enough for the first time */
+struct prot_inuse {
+	int val[PROTO_INUSE_NR];
+};
+
+static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR);
+
+#ifdef CONFIG_NET_NS
+void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
+{
+	int cpu = smp_processor_id();
+	per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
+
+int sock_prot_inuse_get(struct net *net, struct proto *prot)
+{
+	int cpu, idx = prot->inuse_idx;
+	int res = 0;
+
+	for_each_possible_cpu(cpu)
+		res += per_cpu_ptr(net->core.inuse, cpu)->val[idx];
+
+	return res >= 0 ? res : 0;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
+
+static int sock_inuse_init_net(struct net *net)
+{
+	net->core.inuse = alloc_percpu(struct prot_inuse);
+	return net->core.inuse ? 0 : -ENOMEM;
+}
+
+static void sock_inuse_exit_net(struct net *net)
+{
+	free_percpu(net->core.inuse);
+}
+
+static struct pernet_operations net_inuse_ops = {
+	.init = sock_inuse_init_net,
+	.exit = sock_inuse_exit_net,
+};
+
+static __init int net_inuse_init(void)
+{
+	if (register_pernet_subsys(&net_inuse_ops))
+		panic("Cannot initialize net inuse counters");
+
+	return 0;
+}
+
+core_initcall(net_inuse_init);
+#else
+static DEFINE_PER_CPU(struct prot_inuse, prot_inuse);
+
+void sock_prot_inuse_add(struct net *net, struct proto *prot, int val)
+{
+	__get_cpu_var(prot_inuse).val[prot->inuse_idx] += val;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_add);
+
+int sock_prot_inuse_get(struct net *net, struct proto *prot)
+{
+	int cpu, idx = prot->inuse_idx;
+	int res = 0;
+
+	for_each_possible_cpu(cpu)
+		res += per_cpu(prot_inuse, cpu).val[idx];
+
+	return res >= 0 ? res : 0;
+}
+EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
+#endif
+
+static void assign_proto_idx(struct proto *prot)
+{
+	prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR);
+
+	if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) {
+		printk(KERN_ERR "PROTO_INUSE_NR exhausted\n");
+		return;
+	}
+
+	set_bit(prot->inuse_idx, proto_inuse_idx);
+}
+
+static void release_proto_idx(struct proto *prot)
+{
+	if (prot->inuse_idx != PROTO_INUSE_NR - 1)
+		clear_bit(prot->inuse_idx, proto_inuse_idx);
+}
+#else
+static inline void assign_proto_idx(struct proto *prot)
+{
+}
+
+static inline void release_proto_idx(struct proto *prot)
+{
+}
+#endif
+
 int proto_register(struct proto *prot, int alloc_slab)
 {
 	char *request_sock_slab_name = NULL;
 	char *timewait_sock_slab_name;
 
-	if (sock_prot_inuse_init(prot) != 0) {
-		printk(KERN_CRIT "%s: Can't alloc inuse counters!\n", prot->name);
-		goto out;
-	}
-
 	if (alloc_slab) {
 		prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
 					       SLAB_HWCACHE_ALIGN, NULL);
@@ -1936,7 +2054,7 @@ int proto_register(struct proto *prot, int alloc_slab)
 		if (prot->slab == NULL) {
 			printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
 			       prot->name);
-			goto out_free_inuse;
+			goto out;
 		}
 
 		if (prot->rsk_prot != NULL) {
@@ -1979,6 +2097,7 @@ int proto_register(struct proto *prot, int alloc_slab)
 
 	write_lock(&proto_list_lock);
 	list_add(&prot->node, &proto_list);
+	assign_proto_idx(prot);
 	write_unlock(&proto_list_lock);
 	return 0;
 
@@ -1994,8 +2113,6 @@ out_free_request_sock_slab_name:
 out_free_sock_slab:
 	kmem_cache_destroy(prot->slab);
 	prot->slab = NULL;
-out_free_inuse:
-	sock_prot_inuse_free(prot);
 out:
 	return -ENOBUFS;
 }
@@ -2005,11 +2122,10 @@ EXPORT_SYMBOL(proto_register);
 void proto_unregister(struct proto *prot)
 {
 	write_lock(&proto_list_lock);
+	release_proto_idx(prot);
 	list_del(&prot->node);
 	write_unlock(&proto_list_lock);
 
-	sock_prot_inuse_free(prot);
-
 	if (prot->slab != NULL) {
 		kmem_cache_destroy(prot->slab);
 		prot->slab = NULL;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 130338f83ae5..5fc801057244 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -127,7 +127,7 @@ static struct ctl_table net_core_table[] = {
 	{
 		.ctl_name	= NET_CORE_SOMAXCONN,
 		.procname	= "somaxconn",
-		.data		= &init_net.sysctl_somaxconn,
+		.data		= &init_net.core.sysctl_somaxconn,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
@@ -161,7 +161,7 @@ static __net_init int sysctl_core_net_init(struct net *net)
 {
 	struct ctl_table *tbl, *tmp;
 
-	net->sysctl_somaxconn = SOMAXCONN;
+	net->core.sysctl_somaxconn = SOMAXCONN;
 
 	tbl = net_core_table;
 	if (net != &init_net) {
@@ -178,9 +178,9 @@ static __net_init int sysctl_core_net_init(struct net *net)
 		}
 	}
 
-	net->sysctl_core_hdr = register_net_sysctl_table(net,
+	net->core.sysctl_hdr = register_net_sysctl_table(net,
 			net_core_path, tbl);
-	if (net->sysctl_core_hdr == NULL)
+	if (net->core.sysctl_hdr == NULL)
 		goto err_reg;
 
 	return 0;
@@ -196,8 +196,8 @@ static __net_exit void sysctl_core_net_exit(struct net *net)
 {
 	struct ctl_table *tbl;
 
-	tbl = net->sysctl_core_hdr->ctl_table_arg;
-	unregister_net_sysctl_table(net->sysctl_core_hdr);
+	tbl = net->core.sysctl_hdr->ctl_table_arg;
+	unregister_net_sysctl_table(net->core.sysctl_hdr);
 	BUG_ON(tbl == net_core_table);
 	kfree(tbl);
 }
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index 287a62bc2e0f..e1b7c9c6a623 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -23,9 +23,9 @@
  * 	DCCP - specific warning and debugging macros.
  */
 #define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt,       \
-							__FUNCTION__, ##a)
+							__func__, ##a)
 #define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d/%s()\n", ##a, \
-					 __FILE__, __LINE__, __FUNCTION__)
+					 __FILE__, __LINE__, __func__)
 #define DCCP_BUG(a...)       do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0)
 #define DCCP_BUG_ON(cond)    do { if (unlikely((cond) != 0))		   \
 				     DCCP_BUG("\"%s\" holds (exception!)", \
@@ -36,7 +36,7 @@
 							printk(fmt, ##args); \
 						} while(0)
 #define DCCP_PR_DEBUG(enable, fmt, a...)	DCCP_PRINTK(enable, KERN_DEBUG \
-						  "%s: " fmt, __FUNCTION__, ##a)
+						  "%s: " fmt, __func__, ##a)
 
 #ifdef CONFIG_IP_DCCP_DEBUG
 extern int dccp_debug;
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 474075adbde4..7d62f7eb6134 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -450,7 +450,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
 					   struct sk_buff *skb)
 {
 	struct rtable *rt;
-	struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif,
+	struct flowi fl = { .oif = skb->rtable->rt_iif,
 			    .nl_u = { .ip4_u =
 				      { .daddr = ip_hdr(skb)->saddr,
 					.saddr = ip_hdr(skb)->daddr,
@@ -471,15 +471,14 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk,
 	return &rt->u.dst;
 }
 
-static int dccp_v4_send_response(struct sock *sk, struct request_sock *req,
-				 struct dst_entry *dst)
+static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
 {
 	int err = -1;
 	struct sk_buff *skb;
+	struct dst_entry *dst;
 
-	/* First, grab a route. */
-
-	if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL)
+	dst = inet_csk_route_req(sk, req);
+	if (dst == NULL)
 		goto out;
 
 	skb = dccp_make_response(sk, dst, req);
@@ -512,7 +511,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb)
 	if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET)
 		return;
 
-	if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL)
+	if (rxskb->rtable->rt_type != RTN_LOCAL)
 		return;
 
 	dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb);
@@ -564,8 +563,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
 
 	/* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */
-	if (((struct rtable *)skb->dst)->rt_flags &
-	    (RTCF_BROADCAST | RTCF_MULTICAST))
+	if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
 		return 0;	/* discard, don't send a reset here */
 
 	if (dccp_bad_service_code(sk, service)) {
@@ -620,7 +618,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 	dreq->dreq_iss	   = dccp_v4_init_sequence(skb);
 	dreq->dreq_service = service;
 
-	if (dccp_v4_send_response(sk, req, NULL))
+	if (dccp_v4_send_response(sk, req))
 		goto drop_and_free;
 
 	inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
@@ -917,8 +915,6 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = {
 	.twsk_obj_size	= sizeof(struct inet_timewait_sock),
 };
 
-DEFINE_PROTO_INUSE(dccp_v4)
-
 static struct proto dccp_v4_prot = {
 	.name			= "DCCP",
 	.owner			= THIS_MODULE,
@@ -943,12 +939,11 @@ static struct proto dccp_v4_prot = {
 	.obj_size		= sizeof(struct dccp_sock),
 	.rsk_prot		= &dccp_request_sock_ops,
 	.twsk_prot		= &dccp_timewait_sock_ops,
-	.hashinfo		= &dccp_hashinfo,
+	.h.hashinfo		= &dccp_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_dccp_setsockopt,
 	.compat_getsockopt	= compat_dccp_getsockopt,
 #endif
-	REF_PROTO_INUSE(dccp_v4)
 };
 
 static struct net_protocol dccp_v4_protocol = {
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 490333d47c7b..ea3f32648618 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -224,8 +224,7 @@ out:
 }
 
 
-static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
-				 struct dst_entry *dst)
+static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
 {
 	struct inet6_request_sock *ireq6 = inet6_rsk(req);
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -234,6 +233,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 	struct in6_addr *final_p = NULL, final;
 	struct flowi fl;
 	int err = -1;
+	struct dst_entry *dst;
 
 	memset(&fl, 0, sizeof(fl));
 	fl.proto = IPPROTO_DCCP;
@@ -245,28 +245,26 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
 	fl.fl_ip_sport = inet_sk(sk)->sport;
 	security_req_classify_flow(req, &fl);
 
-	if (dst == NULL) {
-		opt = np->opt;
+	opt = np->opt;
 
-		if (opt != NULL && opt->srcrt != NULL) {
-			const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+	if (opt != NULL && opt->srcrt != NULL) {
+		const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
 
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
+		ipv6_addr_copy(&final, &fl.fl6_dst);
+		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+		final_p = &final;
+	}
 
-		err = ip6_dst_lookup(sk, &dst, &fl);
-		if (err)
-			goto done;
+	err = ip6_dst_lookup(sk, &dst, &fl);
+	if (err)
+		goto done;
 
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
+	if (final_p)
+		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-		err = xfrm_lookup(&dst, &fl, sk, 0);
-		if (err < 0)
-			goto done;
-	}
+	err = xfrm_lookup(&dst, &fl, sk, 0);
+	if (err < 0)
+		goto done;
 
 	skb = dccp_make_response(sk, dst, req);
 	if (skb != NULL) {
@@ -448,7 +446,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	dreq->dreq_iss	   = dccp_v6_init_sequence(skb);
 	dreq->dreq_service = service;
 
-	if (dccp_v6_send_response(sk, req, NULL))
+	if (dccp_v6_send_response(sk, req))
 		goto drop_and_free;
 
 	inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
@@ -1102,8 +1100,6 @@ static struct timewait_sock_ops dccp6_timewait_sock_ops = {
 	.twsk_obj_size	= sizeof(struct dccp6_timewait_sock),
 };
 
-DEFINE_PROTO_INUSE(dccp_v6)
-
 static struct proto dccp_v6_prot = {
 	.name		   = "DCCPv6",
 	.owner		   = THIS_MODULE,
@@ -1128,12 +1124,11 @@ static struct proto dccp_v6_prot = {
 	.obj_size	   = sizeof(struct dccp6_sock),
 	.rsk_prot	   = &dccp6_request_sock_ops,
 	.twsk_prot	   = &dccp6_timewait_sock_ops,
-	.hashinfo	   = &dccp_hashinfo,
+	.h.hashinfo	   = &dccp_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_dccp_setsockopt,
 	.compat_getsockopt = compat_dccp_getsockopt,
 #endif
-	REF_PROTO_INUSE(dccp_v6)
 };
 
 static struct inet6_protocol dccp_v6_protocol = {
diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c
index 027d1814e1ab..33ad48321b08 100644
--- a/net/dccp/minisocks.c
+++ b/net/dccp/minisocks.c
@@ -216,7 +216,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb,
 			 * counter (backoff, monitored by dccp_response_timer).
 			 */
 			req->retrans++;
-			req->rsk_ops->rtx_syn_ack(sk, req, NULL);
+			req->rsk_ops->rtx_syn_ack(sk, req);
 		}
 		/* Network Duplicate, discard packet */
 		return NULL;
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index acd48ee522d6..fc2efe899e91 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1094,7 +1094,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
 
 	cb = DN_SKB_CB(skb);
 	sk->sk_ack_backlog--;
-	newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation);
+	newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation);
 	if (newsk == NULL) {
 		release_sock(sk);
 		kfree_skb(skb);
@@ -2089,7 +2089,7 @@ static int dn_device_event(struct notifier_block *this, unsigned long event,
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	switch(event) {
@@ -2320,25 +2320,8 @@ static const struct seq_operations dn_socket_seq_ops = {
 
 static int dn_socket_seq_open(struct inode *inode, struct file *file)
 {
-	struct seq_file *seq;
-	int rc = -ENOMEM;
-	struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
-
-	if (!s)
-		goto out;
-
-	rc = seq_open(file, &dn_socket_seq_ops);
-	if (rc)
-		goto out_kfree;
-
-	seq		= file->private_data;
-	seq->private	= s;
-	memset(s, 0, sizeof(*s));
-out:
-	return rc;
-out_kfree:
-	kfree(s);
-	goto out;
+	return seq_open_private(file, &dn_socket_seq_ops,
+			sizeof(struct dn_iter_state));
 }
 
 static const struct file_operations dn_socket_seq_fops = {
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 1bbfce5f7a2d..2f0ac3c3eb71 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -625,7 +625,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = {
 
 static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[IFA_MAX+1];
 	struct dn_dev *dn_db;
 	struct ifaddrmsg *ifm;
@@ -663,7 +663,7 @@ errout:
 
 static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[IFA_MAX+1];
 	struct net_device *dev;
 	struct dn_dev *dn_db;
@@ -779,7 +779,7 @@ errout:
 
 static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int idx, dn_idx = 0, skip_ndevs, skip_naddr;
 	struct net_device *dev;
 	struct dn_dev *dn_db;
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 4aa9a423e606..27ea2e9b080a 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -504,7 +504,7 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
 
 static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
 	struct rtmsg *r = NLMSG_DATA(nlh);
@@ -524,7 +524,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *
 
 static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct dn_fib_table *tb;
 	struct rtattr **rta = arg;
 	struct rtmsg *r = NLMSG_DATA(nlh);
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 9dc0abb50eaf..2f665a516476 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -580,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
 	struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
 	unsigned char padlen = 0;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto dump_it;
 
 	if (dn == NULL)
@@ -1512,7 +1512,7 @@ rtattr_failure:
  */
 static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = in_skb->sk->sk_net;
+	struct net *net = sock_net(in_skb->sk);
 	struct rtattr **rta = arg;
 	struct rtmsg *rtm = NLMSG_DATA(nlh);
 	struct dn_route *rt = NULL;
@@ -1601,7 +1601,7 @@ out_free:
  */
 int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct dn_route *rt;
 	int h, s_h;
 	int idx, s_idx;
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index e09d915dbd77..3a2830ac89c2 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -463,7 +463,7 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
 
 int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	unsigned int h, s_h;
 	unsigned int e = 0, s_e;
 	struct dn_fib_table *tb;
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index bc0f6252613f..68d154480043 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -1064,7 +1064,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
 	struct sock *sk;
 	struct ec_device *edev = dev->ec_ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	if (skb->pkt_type == PACKET_OTHERHOST)
@@ -1121,7 +1121,7 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void
 	struct net_device *dev = (struct net_device *)data;
 	struct ec_device *edev;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	switch (msg) {
diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig
index bd501046c9c0..94ed7d3cd9da 100644
--- a/net/ieee80211/Kconfig
+++ b/net/ieee80211/Kconfig
@@ -71,4 +71,3 @@ config IEEE80211_CRYPT_TKIP
 	This can be compiled as a module and it will be called
 	"ieee80211_crypt_tkip".
 
-source "net/ieee80211/softmac/Kconfig"
diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile
index 796a7c76ee48..f988417121da 100644
--- a/net/ieee80211/Makefile
+++ b/net/ieee80211/Makefile
@@ -10,4 +10,3 @@ ieee80211-objs := \
 	ieee80211_wx.o \
 	ieee80211_geo.o
 
-obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/
diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig
deleted file mode 100644
index 2811651cb134..000000000000
--- a/net/ieee80211/softmac/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config IEEE80211_SOFTMAC
-	tristate "Software MAC add-on to the IEEE 802.11 networking stack"
-	depends on IEEE80211 && EXPERIMENTAL
-	select WIRELESS_EXT
-	select IEEE80211_CRYPT_WEP
-	---help---
-	This option enables the hardware independent software MAC addon
-	for the IEEE 802.11 networking stack.
-
-config IEEE80211_SOFTMAC_DEBUG
-	bool "Enable full debugging output"
-	depends on IEEE80211_SOFTMAC
diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile
deleted file mode 100644
index bfcb391bb2c7..000000000000
--- a/net/ieee80211/softmac/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o
-ieee80211softmac-objs := \
-			ieee80211softmac_io.o \
-			ieee80211softmac_auth.o \
-			ieee80211softmac_module.o \
-			ieee80211softmac_scan.o \
-			ieee80211softmac_wx.o \
-			ieee80211softmac_assoc.o \
-			ieee80211softmac_event.o
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
deleted file mode 100644
index c4d122ddd72c..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * This file contains the softmac's association logic.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-/*
- * Overview
- *
- * Before you can associate, you have to authenticate.
- *
- */
-
-/* Sends out an association request to the desired AP */
-static void
-ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
-	unsigned long flags;
-
-	/* Switch to correct channel for this network */
-	mac->set_channel(mac->dev, net->channel);
-
-	/* Send association request */
-	ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0);
-
-	dprintk(KERN_INFO PFX "sent association request!\n");
-
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.associated = 0; /* just to make sure */
-
-	/* Set a timer for timeout */
-	/* FIXME: make timeout configurable */
-	if (likely(mac->running))
-		queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-void
-ieee80211softmac_assoc_timeout(struct work_struct *work)
-{
-	struct ieee80211softmac_device *mac =
-		container_of(work, struct ieee80211softmac_device,
-			     associnfo.timeout.work);
-	struct ieee80211softmac_network *n;
-
-	mutex_lock(&mac->associnfo.mutex);
-	/* we might race against ieee80211softmac_handle_assoc_response,
-	 * so make sure only one of us does something */
-	if (!mac->associnfo.associating)
-		goto out;
-	mac->associnfo.associating = 0;
-	mac->associnfo.bssvalid = 0;
-	mac->associnfo.associated = 0;
-
-	n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
-
-	dprintk(KERN_INFO PFX "assoc request timed out!\n");
-	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
-out:
-	mutex_unlock(&mac->associnfo.mutex);
-}
-
-void
-ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	if (mac->associnfo.associating)
-		cancel_delayed_work(&mac->associnfo.timeout);
-
-	netif_carrier_off(mac->dev);
-
-	mac->associnfo.associated = 0;
-	mac->associnfo.bssvalid = 0;
-	mac->associnfo.associating = 0;
-	ieee80211softmac_init_bss(mac);
-	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-/* Sends out a disassociation request to the desired AP */
-void
-ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason)
-{
-	struct ieee80211softmac_network *found;
-
-	if (mac->associnfo.bssvalid && mac->associnfo.associated) {
-		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
-		if (found)
-			ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
-	}
-
-	ieee80211softmac_disassoc(mac);
-}
-
-static inline int
-we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len)
-{
-	int idx;
-	u8 rate;
-
-	for (idx = 0; idx < (from_len); idx++) {
-		rate = (from)[idx];
-		if (!(rate & IEEE80211_BASIC_RATE_MASK))
-			continue;
-		rate &= ~IEEE80211_BASIC_RATE_MASK;
-		if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
-			return 0;
-	}
-	return 1;
-}
-
-static int
-network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net)
-{
-	/* we cannot associate to networks whose name we don't know */
-	if (ieee80211_is_empty_essid(net->ssid, net->ssid_len))
-		return 0;
-	/* do not associate to a network whose BSSBasicRateSet we cannot support */
-	if (!we_support_all_basic_rates(mac, net->rates, net->rates_len))
-		return 0;
-	/* do we really need to check the ex rates? */
-	if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len))
-		return 0;
-
-	/* assume that users know what they're doing ...
-	 * (note we don't let them select a net we're incompatible with) */
-	if (mac->associnfo.bssfixed) {
-		return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN);
-	}
-
-	/* if 'ANY' network requested, take any that doesn't have privacy enabled */
-	if (mac->associnfo.req_essid.len == 0
-	    && !(net->capability & WLAN_CAPABILITY_PRIVACY))
-		return 1;
-	if (net->ssid_len != mac->associnfo.req_essid.len)
-		return 0;
-	if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len))
-		return 1;
-	return 0;
-}
-
-static void
-ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	ieee80211softmac_assoc_work(&mac->associnfo.work.work);
-}
-
-static void
-ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	switch (event_type) {
-	case IEEE80211SOFTMAC_EVENT_AUTHENTICATED:
-		ieee80211softmac_assoc_work(&mac->associnfo.work.work);
-		break;
-	case IEEE80211SOFTMAC_EVENT_AUTH_FAILED:
-	case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT:
-		ieee80211softmac_disassoc(mac);
-		break;
-	}
-}
-
-/* This function is called to handle userspace requests (asynchronously) */
-void
-ieee80211softmac_assoc_work(struct work_struct *work)
-{
-	struct ieee80211softmac_device *mac =
-		container_of(work, struct ieee80211softmac_device,
-			     associnfo.work.work);
-	struct ieee80211softmac_network *found = NULL;
-	struct ieee80211_network *net = NULL, *best = NULL;
-	int bssvalid;
-	unsigned long flags;
-
-	mutex_lock(&mac->associnfo.mutex);
-
-	if (!mac->associnfo.associating)
-		goto out;
-
-	/* ieee80211_disassoc might clear this */
-	bssvalid = mac->associnfo.bssvalid;
-
-	/* meh */
-	if (mac->associnfo.associated)
-		ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
-
-	/* try to find the requested network in our list, if we found one already */
-	if (bssvalid || mac->associnfo.bssfixed)
-		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
-
-	/* Search the ieee80211 networks for this network if we didn't find it by bssid,
-	 * but only if we've scanned at least once (to get a better list of networks to
-	 * select from). If we have not scanned before, the !found logic below will be
-	 * invoked and will scan. */
-	if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT))
-	{
-		s8 rssi = -128;	/* if I don't initialise, gcc emits an invalid warning
-				   because it cannot follow the best pointer logic. */
-		spin_lock_irqsave(&mac->ieee->lock, flags);
-		list_for_each_entry(net, &mac->ieee->network_list, list) {
-			/* we're supposed to find the network with
-			 * the best signal here, as we're asked to join
-			 * any network with a specific ESSID, and many
-			 * different ones could have that.
-			 *
-			 * I'll for now just go with the reported rssi.
-			 *
-			 * We also should take into account the rateset
-			 * here to find the best BSSID to try.
-			 */
-			if (network_matches_request(mac, net)) {
-				if (!best) {
-					best = net;
-					rssi = best->stats.rssi;
-					continue;
-				}
-				/* we already had a matching network, so
-				 * compare their properties to get the
-				 * better of the two ... (see above)
-				 */
-				if (rssi < net->stats.rssi) {
-					best = net;
-					rssi = best->stats.rssi;
-				}
-			}
-		}
-		/* if we unlock here, we might get interrupted and the `best'
-		 * pointer could go stale */
-		if (best) {
-			found = ieee80211softmac_create_network(mac, best);
-			/* if found is still NULL, then we got -ENOMEM somewhere */
-			if (found)
-				ieee80211softmac_add_network(mac, found);
-		}
-		spin_unlock_irqrestore(&mac->ieee->lock, flags);
-	}
-
-	if (!found) {
-		if (mac->associnfo.scan_retry > 0) {
-			mac->associnfo.scan_retry--;
-
-			/* We know of no such network. Let's scan.
-			 * NB: this also happens if we had no memory to copy the network info...
-			 * Maybe we can hope to have more memory after scanning finishes ;)
-			 */
-			dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
-			ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
-			if (ieee80211softmac_start_scan(mac)) {
-				dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
-			}
-			goto out;
-		} else {
-			mac->associnfo.associating = 0;
-			mac->associnfo.associated = 0;
-
-			dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
-			/* reset the retry counter for the next user request since we
-			 * break out and don't reschedule ourselves after this point. */
-			mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
-			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
-			goto out;
-		}
-	}
-
-	/* reset the retry counter for the next user request since we
-	 * now found a net and will try to associate to it, but not
-	 * schedule this function again. */
-	mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
-	mac->associnfo.bssvalid = 1;
-	memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN);
-	/* copy the ESSID for displaying it */
-	mac->associnfo.associate_essid.len = found->essid.len;
-	memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
-
-	/* we found a network! authenticate (if necessary) and associate to it. */
-	if (found->authenticating) {
-		dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
-		if(!mac->associnfo.assoc_wait) {
-			mac->associnfo.assoc_wait = 1;
-			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
-		}
-		goto out;
-	}
-	if (!found->authenticated && !found->authenticating) {
-		/* This relies on the fact that _auth_req only queues the work,
-		 * otherwise adding the notification would be racy. */
-		if (!ieee80211softmac_auth_req(mac, found)) {
-			if(!mac->associnfo.assoc_wait) {
-				dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
-				mac->associnfo.assoc_wait = 1;
-				ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
-			}
-		} else {
-			printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
-			mac->associnfo.assoc_wait = 0;
-			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
-		}
-		goto out;
-	}
-	/* finally! now we can start associating */
-	mac->associnfo.assoc_wait = 0;
-	ieee80211softmac_assoc(mac, found);
-
-out:
-	mutex_unlock(&mac->associnfo.mutex);
-}
-
-/* call this to do whatever is necessary when we're associated */
-static void
-ieee80211softmac_associated(struct ieee80211softmac_device *mac,
-	struct ieee80211_assoc_response * resp,
-	struct ieee80211softmac_network *net)
-{
-	u16 cap = le16_to_cpu(resp->capability);
-	u8 erp_value = net->erp_value;
-
-	mac->associnfo.associating = 0;
-	mac->bssinfo.supported_rates = net->supported_rates;
-	ieee80211softmac_recalc_txrates(mac);
-
-	mac->associnfo.associated = 1;
-
-	mac->associnfo.short_preamble_available =
-		(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
-	ieee80211softmac_process_erp(mac, erp_value);
-
-	if (mac->set_bssid_filter)
-		mac->set_bssid_filter(mac->dev, net->bssid);
-	memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
-	netif_carrier_on(mac->dev);
-
-	mac->association_id = le16_to_cpup(&resp->aid);
-}
-
-/* received frame handling functions */
-int
-ieee80211softmac_handle_assoc_response(struct net_device * dev,
-				       struct ieee80211_assoc_response * resp,
-				       struct ieee80211_network * _ieee80211_network)
-{
-	/* NOTE: the network parameter has to be mostly ignored by
-	 *       this code because it is the ieee80211's pointer
-	 *       to the struct, not ours (we made a copy)
-	 */
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	u16 status = le16_to_cpup(&resp->status);
-	struct ieee80211softmac_network *network = NULL;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac2);
-
-	if (unlikely(!mac->running))
-		return -ENODEV;
-
-	spin_lock_irqsave(&mac->lock, flags);
-
-	if (!mac->associnfo.associating) {
-		/* we race against the timeout function, so make sure
-		 * only one of us can do work */
-		spin_unlock_irqrestore(&mac->lock, flags);
-		return 0;
-	}
-	network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3);
-
-	/* someone sending us things without us knowing him? Ignore. */
-	if (!network) {
-		dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n",
-			print_mac(mac2, resp->header.addr3));
-		spin_unlock_irqrestore(&mac->lock, flags);
-		return 0;
-	}
-
-	/* now that we know it was for us, we can cancel the timeout */
-	cancel_delayed_work(&mac->associnfo.timeout);
-
-	/* if the association response included an ERP IE, update our saved
-	 * copy */
-	if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
-		network->erp_value = _ieee80211_network->erp_value;
-
-	switch (status) {
-		case 0:
-			dprintk(KERN_INFO PFX "associated!\n");
-			ieee80211softmac_associated(mac, resp, network);
-			ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network);
-			break;
-		case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH:
-			if (!network->auth_desynced_once) {
-				/* there seem to be a few rare cases where our view of
-				 * the world is obscured, or buggy APs that don't DEAUTH
-				 * us properly. So we handle that, but allow it only once.
-				 */
-				printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n");
-				network->authenticated = 0;
-				/* we don't want to do this more than once ... */
-				network->auth_desynced_once = 1;
-				queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-				break;
-			}
-		default:
-			dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
-			mac->associnfo.associating = 0;
-			mac->associnfo.bssvalid = 0;
-			mac->associnfo.associated = 0;
-			ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
-	}
-
-	spin_unlock_irqrestore(&mac->lock, flags);
-	return 0;
-}
-
-void
-ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	mac->associnfo.associating = 1;
-	queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-int
-ieee80211softmac_handle_disassoc(struct net_device * dev,
-				 struct ieee80211_disassoc *disassoc)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	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");
-	ieee80211softmac_disassoc(mac);
-
-	ieee80211softmac_try_reassoc(mac);
-
-	return 0;
-}
-
-int
-ieee80211softmac_handle_reassoc_req(struct net_device * dev,
-				    struct ieee80211_reassoc_request * resp)
-{
-	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");
-		return 0;
-	}
-	queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-
-	return 0;
-}
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
deleted file mode 100644
index 1a96c2572578..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * This file contains the softmac's authentication logic.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-static void ieee80211softmac_auth_queue(struct work_struct *work);
-
-/* Queues an auth request to the desired AP */
-int
-ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net)
-{
-	struct ieee80211softmac_auth_queue_item *auth;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac2);
-
-	if (net->authenticating || net->authenticated)
-		return 0;
-	net->authenticating = 1;
-
-	/* Add the network if it's not already added */
-	ieee80211softmac_add_network(mac, net);
-
-	dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid));
-	/* Queue the auth request */
-	auth = (struct ieee80211softmac_auth_queue_item *)
-		kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL);
-	if(auth == NULL)
-		return -ENOMEM;
-
-	auth->net = net;
-	auth->mac = mac;
-	auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT;
-	auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST;
-	INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue);
-
-	/* Lock (for list) */
-	spin_lock_irqsave(&mac->lock, flags);
-
-	/* add to list */
-	list_add_tail(&auth->list, &mac->auth_queue);
-	queue_delayed_work(mac->wq, &auth->work, 0);
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	return 0;
-}
-
-
-/* Sends an auth request to the desired AP and handles timeouts */
-static void
-ieee80211softmac_auth_queue(struct work_struct *work)
-{
-	struct ieee80211softmac_device *mac;
-	struct ieee80211softmac_auth_queue_item *auth;
-	struct ieee80211softmac_network *net;
-	unsigned long flags;
-	DECLARE_MAC_BUF(mac2);
-
-	auth = container_of(work, struct ieee80211softmac_auth_queue_item,
-			    work.work);
-	net = auth->net;
-	mac = auth->mac;
-
-	if(auth->retry > 0) {
-		/* Switch to correct channel for this network */
-		mac->set_channel(mac->dev, net->channel);
-
-		/* 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;
-		/* add a timeout call so we eventually give up waiting for an auth reply */
-		queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
-		auth->retry--;
-		spin_unlock_irqrestore(&mac->lock, flags);
-		if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state))
-			dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n",
-				print_mac(mac2, net->bssid));
-		else
-			dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid));
-		return;
-	}
-
-	printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid));
-	/* Remove this item from the queue */
-	spin_lock_irqsave(&mac->lock, flags);
-	net->authenticating = 0;
-	ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net);
-	cancel_delayed_work(&auth->work); /* just to make sure... */
-	list_del(&auth->list);
-	spin_unlock_irqrestore(&mac->lock, flags);
-	/* Free it */
-	kfree(auth);
-}
-
-/* Sends a response to an auth challenge (for shared key auth). */
-static void
-ieee80211softmac_auth_challenge_response(struct work_struct *work)
-{
-	struct ieee80211softmac_auth_queue_item *aq =
-		container_of(work, struct ieee80211softmac_auth_queue_item,
-			     work.work);
-
-	/* Send our response */
-	ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
-}
-
-/* Handle the auth response from the AP
- * This should be registered with ieee80211 as handle_auth
- */
-int
-ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
-{
-
-	struct list_head *list_ptr;
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	struct ieee80211softmac_auth_queue_item *aq = NULL;
-	struct ieee80211softmac_network *net = NULL;
-	unsigned long flags;
-	u8 * data;
-	DECLARE_MAC_BUF(mac2);
-
-	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) {
-		aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
-		net = aq->net;
-		if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN))
-			break;
-		else
-			aq = NULL;
-	}
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	/* Make sure that we've got an auth queue item for this request */
-	if(aq == NULL)
-	{
-		dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2));
-		/* Error #? */
-		return -1;
-	}
-
-	/* Check for out of order authentication */
-	if(!net->authenticating)
-	{
-		dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2));
-		return -1;
-	}
-
-	/* Parse the auth packet */
-	switch(le16_to_cpu(auth->algorithm)) {
-	case WLAN_AUTH_OPEN:
-		/* Check the status code of the response */
-
-		switch(le16_to_cpu(auth->status)) {
-		case WLAN_STATUS_SUCCESS:
-			/* Update the status to Authenticated */
-			spin_lock_irqsave(&mac->lock, flags);
-			net->authenticating = 0;
-			net->authenticated = 1;
-			spin_unlock_irqrestore(&mac->lock, flags);
-
-			/* Send event */
-			printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid));
-			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
-			break;
-		default:
-			/* Lock and reset flags */
-			spin_lock_irqsave(&mac->lock, flags);
-			net->authenticated = 0;
-			net->authenticating = 0;
-			spin_unlock_irqrestore(&mac->lock, flags);
-
-			printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n",
-				print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
-			/* Count the error? */
-			break;
-		}
-		goto free_aq;
-		break;
-	case WLAN_AUTH_SHARED_KEY:
-		/* Figure out where we are in the process */
-		switch(le16_to_cpu(auth->transaction)) {
-		case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
-			/* Check to make sure we have a challenge IE */
-			data = (u8 *)auth->info_element;
-			if (*data++ != MFIE_TYPE_CHALLENGE) {
-				printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
-				break;
-			}
-			/* Save the challenge */
-			spin_lock_irqsave(&mac->lock, flags);
-			net->challenge_len = *data++;
-			if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
-				net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
-			kfree(net->challenge);
-			net->challenge = kmemdup(data, net->challenge_len,
-						 GFP_ATOMIC);
-			if (net->challenge == NULL) {
-				printkl(KERN_NOTICE PFX "Shared Key "
-					"Authentication failed due to "
-					"memory shortage.\n");
-				spin_unlock_irqrestore(&mac->lock, flags);
-				break;
-			}
-			aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
-
-			/* We reuse the work struct from the auth request here.
-			 * It is safe to do so as each one is per-request, and
-			 * at this point (dealing with authentication response)
-			 * we have obviously already sent the initial auth
-			 * request. */
-			cancel_delayed_work(&aq->work);
-			INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response);
-			queue_delayed_work(mac->wq, &aq->work, 0);
-			spin_unlock_irqrestore(&mac->lock, flags);
-			return 0;
-		case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
-			kfree(net->challenge);
-			net->challenge = NULL;
-			net->challenge_len = 0;
-			/* Check the status code of the response */
-			switch(auth->status) {
-			case WLAN_STATUS_SUCCESS:
-				/* Update the status to Authenticated */
-				spin_lock_irqsave(&mac->lock, flags);
-				net->authenticating = 0;
-				net->authenticated = 1;
-				spin_unlock_irqrestore(&mac->lock, flags);
-				printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n",
-					print_mac(mac2, net->bssid));
-				ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net);
-				break;
-			default:
-				printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n",
-					print_mac(mac2, net->bssid), le16_to_cpup(&auth->status));
-				/* Lock and reset flags */
-				spin_lock_irqsave(&mac->lock, flags);
-				net->authenticating = 0;
-				net->authenticated = 0;
-				spin_unlock_irqrestore(&mac->lock, flags);
-				/* Count the error? */
-				break;
-			}
-			goto free_aq;
-			break;
-		default:
-			printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction);
-			break;
-		}
-		goto free_aq;
-		break;
-	default:
-		/* ERROR */
-		goto free_aq;
-		break;
-	}
-	return 0;
-free_aq:
-	/* Cancel the timeout */
-	spin_lock_irqsave(&mac->lock, flags);
-	cancel_delayed_work(&aq->work);
-	/* Remove this item from the queue */
-	list_del(&aq->list);
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	/* Free it */
-	kfree(aq);
-	return 0;
-}
-
-/*
- * Handle deauthorization
- */
-static void
-ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net)
-{
-	struct ieee80211softmac_auth_queue_item *aq = NULL;
-	struct list_head *list_ptr;
-	unsigned long flags;
-
-	/* deauthentication implies disassociation */
-	ieee80211softmac_disassoc(mac);
-
-	/* Lock and reset status flags */
-	spin_lock_irqsave(&mac->lock, flags);
-	net->authenticating = 0;
-	net->authenticated = 0;
-
-	/* Find correct auth queue item, if it exists */
-	list_for_each(list_ptr, &mac->auth_queue) {
-		aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list);
-		if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN))
-			break;
-		else
-			aq = NULL;
-	}
-
-	/* Cancel pending work */
-	if(aq != NULL)
-		/* Not entirely safe?  What about running work? */
-		cancel_delayed_work(&aq->work);
-
-	/* Free our network ref */
-	ieee80211softmac_del_network_locked(mac, net);
-	if(net->challenge != NULL)
-		kfree(net->challenge);
-	kfree(net);
-
-	/* can't transmit data right now... */
-	netif_carrier_off(mac->dev);
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	ieee80211softmac_try_reassoc(mac);
-}
-
-/*
- * Sends a deauth request to the desired AP
- */
-int
-ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net, int reason)
-{
-	int ret;
-
-	/* Make sure the network is authenticated */
-	if (!net->authenticated)
-	{
-		dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n");
-		/* Error okay? */
-		return -EPERM;
-	}
-
-	/* Send the de-auth packet */
-	if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason)))
-		return ret;
-
-	ieee80211softmac_deauth_from_net(mac, net);
-	return 0;
-}
-
-/*
- * This should be registered with ieee80211 as handle_deauth
- */
-int
-ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth)
-{
-
-	struct ieee80211softmac_network *net = NULL;
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	DECLARE_MAC_BUF(mac2);
-
-	if (unlikely(!mac->running))
-		return -ENODEV;
-
-	if (!deauth) {
-		dprintk("deauth without deauth packet. eek!\n");
-		return 0;
-	}
-
-	net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2);
-
-	if (net == NULL) {
-		dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n",
-			print_mac(mac2, deauth->header.addr2));
-		return 0;
-	}
-
-	/* Make sure the network is authenticated */
-	if(!net->authenticated)
-	{
-		dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n");
-		/* Error okay? */
-		return -EPERM;
-	}
-
-	ieee80211softmac_deauth_from_net(mac, net);
-
-	/* let's try to re-associate */
-	queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-	return 0;
-}
diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c
deleted file mode 100644
index 8cef05b60f16..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_event.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Event system
- * Also see comments in public header file and longer explanation below.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-/*
- * Each event has associated to it
- *  - an event type (see constants in public header)
- *  - an event context (see below)
- *  - the function to be called
- *  - a context (extra parameter to call the function with)
- *  - and the softmac struct
- *
- * The event context is private and can only be used from
- * within this module. Its meaning varies with the event
- * type:
- *  SCAN_FINISHED,
- *  DISASSOCIATED:	NULL
- *  ASSOCIATED,
- *  ASSOCIATE_FAILED,
- *  ASSOCIATE_TIMEOUT,
- *  AUTHENTICATED,
- *  AUTH_FAILED,
- *  AUTH_TIMEOUT:	a pointer to the network struct
- * ...
- * Code within this module can use the event context to be only
- * called when the event is true for that specific context
- * as per above table.
- * If the event context is NULL, then the notification is always called,
- * regardless of the event context. The event context is not passed to
- * the callback, it is assumed that the context suffices.
- *
- * You can also use the event context only by setting the event type
- * to -1 (private use only), in which case you'll be notified
- * whenever the event context matches.
- */
-
-static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = {
-	NULL, /* scan finished */
-	NULL, /* associated */
-	"associating failed",
-	"associating timed out",
-	"authenticated",
-	"authenticating failed",
-	"authenticating timed out",
-	"associating failed because no suitable network was found",
-	NULL, /* disassociated */
-};
-
-
-static void
-ieee80211softmac_notify_callback(struct work_struct *work)
-{
-	struct ieee80211softmac_event *pevent =
-		container_of(work, struct ieee80211softmac_event, work.work);
-	struct ieee80211softmac_event event = *pevent;
-	kfree(pevent);
-
-	event.fun(event.mac->dev, event.event_type, event.context);
-}
-
-int
-ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
-	int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask)
-{
-	struct ieee80211softmac_event *eventptr;
-	unsigned long flags;
-
-	if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST)
-		return -ENOSYS;
-
-	if (!fun)
-		return -EINVAL;
-
-	eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask);
-	if (!eventptr)
-		return -ENOMEM;
-
-	eventptr->event_type = event;
-	INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback);
-	eventptr->fun = fun;
-	eventptr->context = context;
-	eventptr->mac = mac;
-	eventptr->event_context = event_context;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	list_add(&eventptr->list, &mac->events);
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	return 0;
-}
-
-int
-ieee80211softmac_notify_gfp(struct net_device *dev,
-	int event, notify_function_ptr fun, void *context, gfp_t gfp_mask)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST)
-		return -ENOSYS;
-
-	return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp);
-
-/* private -- calling all callbacks that were specified */
-void
-ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx)
-{
-	struct ieee80211softmac_event *eventptr, *tmp;
-	struct ieee80211softmac_network *network;
-
-	if (event >= 0) {
-		union iwreq_data wrqu;
-		int we_event;
-		char *msg = NULL;
-
-		memset(&wrqu, '\0', sizeof (union iwreq_data));
-
-		switch(event) {
-		case IEEE80211SOFTMAC_EVENT_ASSOCIATED:
-			network = (struct ieee80211softmac_network *)event_ctx;
-			memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN);
-			/* fall through */
-		case IEEE80211SOFTMAC_EVENT_DISASSOCIATED:
-			wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-			we_event = SIOCGIWAP;
-			break;
-		case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED:
-			we_event = SIOCGIWSCAN;
-			break;
-		default:
-			msg = event_descriptions[event];
-			if (!msg)
-				msg = "SOFTMAC EVENT BUG";
-			wrqu.data.length = strlen(msg);
-			we_event = IWEVCUSTOM;
-			break;
-		}
-		wireless_send_event(mac->dev, we_event, &wrqu, msg);
-	}
-
-	if (!list_empty(&mac->events))
-		list_for_each_entry_safe(eventptr, tmp, &mac->events, list) {
-			if ((eventptr->event_type == event || eventptr->event_type == -1)
-				&& (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) {
-				list_del(&eventptr->list);
-				/* User may have subscribed to ANY event, so
-				 * we tell them which event triggered it. */
-				eventptr->event_type = event;
-				queue_delayed_work(mac->wq, &eventptr->work, 0);
-			}
-		}
-}
-
-void
-ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	ieee80211softmac_call_events_locked(mac, event, event_ctx);
-
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
deleted file mode 100644
index 73b4b13fbd8f..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ /dev/null
@@ -1,488 +0,0 @@
-/*
- * Some parts based on code from net80211
- * Copyright (c) 2001 Atsushi Onoe
- * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "ieee80211softmac_priv.h"
-
-/* Helper functions for inserting data into the frames */
-
-/*
- * Adds an ESSID element to the frame
- *
- */
-static u8 *
-ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid)
-{
-	if (essid) {
-		*dst++ = MFIE_TYPE_SSID;
-		*dst++ = essid->len;
-		memcpy(dst, essid->data, essid->len);
-		return dst+essid->len;
-	} else {
-		*dst++ = MFIE_TYPE_SSID;
-		*dst++ = 0;
-		return dst;
-	}
-}
-
-/* Adds Supported Rates and if required Extended Rates Information Element
- * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */
-static u8 *
-ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r)
-{
-	int cck_len, ofdm_len;
-	*dst++ = MFIE_TYPE_RATES;
-
-	for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++);
-
-	if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN)
-		cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN;
-	*dst++ = cck_len;
-	memcpy(dst, r->rates, cck_len);
-	dst += cck_len;
-
-	if(cck_len < r->count){
-		for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++);
-		if (ofdm_len > 0) {
-			if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN)
-				ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN;
-			*dst++ = MFIE_TYPE_RATES_EX;
-			*dst++ = ofdm_len;
-			memcpy(dst, r->rates + cck_len, ofdm_len);
-			dst += ofdm_len;
-		}
-	}
-	return dst;
-}
-
-/* Allocate a management frame */
-static u8 *
-ieee80211softmac_alloc_mgt(u32 size)
-{
-	u8 * data;
-
-	/* Add the header and FCS to the size */
-	size = size + IEEE80211_3ADDR_LEN;
-	if(size > IEEE80211_DATA_LEN)
-		return NULL;
-	/* Allocate the frame */
-	data = kzalloc(size, GFP_ATOMIC);
-	return data;
-}
-
-/*
- * Add a 2 Address Header
- */
-static void
-ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac,
-	struct ieee80211_hdr_2addr *header, u32 type, u8 *dest)
-{
-	/* Fill in the frame control flags */
-	header->frame_ctl = cpu_to_le16(type);
-	/* Control packets always have WEP turned off */
-	if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL)
-		header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0;
-
-	/* Fill in the duration */
-	header->duration_id = 0;
-	/* FIXME: How do I find this?
-	 * calculate. But most drivers just fill in 0 (except if it's a station id of course) */
-
-	/* Fill in the Destination Address */
-	if(dest == NULL)
-		memset(header->addr1, 0xFF, ETH_ALEN);
-	else
-		memcpy(header->addr1, dest, ETH_ALEN);
-	/* Fill in the Source Address */
-	memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN);
-
-}
-
-
-/* Add a 3 Address Header */
-static void
-ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac,
-	struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid)
-{
-	/* This is common with 2addr, so use that instead */
-	ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest);
-
-	/* Fill in the BSS ID */
-	if(bssid == NULL)
-		memset(header->addr3, 0xFF, ETH_ALEN);
-	else
-		memcpy(header->addr3, bssid, ETH_ALEN);
-
-	/* Fill in the sequence # */
-	/* FIXME: I need to add this to the softmac struct
-	 * shouldn't the sequence number be in ieee80211? */
-}
-
-static __le16
-ieee80211softmac_capabilities(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net)
-{
-	__le16 capability = 0;
-
-	/* ESS and IBSS bits are set according to the current mode */
-	switch (mac->ieee->iw_mode) {
-	case IW_MODE_INFRA:
-		capability = cpu_to_le16(WLAN_CAPABILITY_ESS);
-		break;
-	case IW_MODE_ADHOC:
-		capability = cpu_to_le16(WLAN_CAPABILITY_IBSS);
-		break;
-	case IW_MODE_AUTO:
-		capability = cpu_to_le16(net->capabilities &
-			(WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS));
-		break;
-	default:
-		/* bleh. we don't ever go to these modes */
-		printk(KERN_ERR PFX "invalid iw_mode!\n");
-		break;
-	}
-
-	/* CF Pollable / CF Poll Request */
-	/* Needs to be implemented, for now, the 0's == not supported */
-
-	/* Privacy Bit */
-	capability |= mac->ieee->sec.level ?
-		cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0;
-
-	/* Short Preamble */
-	/* Always supported: we probably won't ever be powering devices which
-	 * dont support this... */
-	capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
-
-	/* PBCC */
-	/* Not widely used */
-
-	/* Channel Agility */
-	/* Not widely used */
-
-	/* Short Slot */
-	/* Will be implemented later */
-
-	/* DSSS-OFDM */
-	/* Not widely used */
-
-	return capability;
-}
-
-/*****************************************************************************
- * Create Management packets
- *****************************************************************************/
-
-/* Creates an association request packet */
-static u32
-ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
-	u8 *data;
-	(*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt(
-		2 +		/* Capability Info */
-		2 +	 	/* Listen Interval */
-		/* SSID IE */
-		1 + 1 + IW_ESSID_MAX_SIZE +
-		/* Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
-		/* Extended Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN +
-		/* WPA IE if present */
-		mac->wpa.IElen
-		/* Other IE's?  Optional?
-		 * Yeah, probably need an extra IE parameter -- lots of vendors like to
-		 * fill in their own IEs */
-	);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
-
-	/* Fill in the capabilities */
-	(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
-
-	/* Fill in Listen Interval (?) */
-	(*pkt)->listen_interval = cpu_to_le16(10);
-
-	data = (u8 *)(*pkt)->info_element;
-	/* Add SSID */
-	data = ieee80211softmac_add_essid(data, &net->essid);
-	/* Add Rates */
-	data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
-	/* Add WPA IE */
-	if (mac->wpa.IElen && mac->wpa.IE) {
-		memcpy(data, mac->wpa.IE, mac->wpa.IElen);
-		data += mac->wpa.IElen;
-	}
-	/* Return the number of used bytes */
-	return (data - (u8*)(*pkt));
-}
-
-/* Create a reassociation request packet */
-static u32
-ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
-	u8 *data;
-	(*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt(
-		2 +		/* Capability Info */
-		2 +	 	/* Listen Interval */
-		ETH_ALEN +	/* AP MAC */
-		/* SSID IE */
-		1 + 1 + IW_ESSID_MAX_SIZE +
-		/* Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
-		/* Extended Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
-		/* Other IE's? */
-	);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid);
-
-	/* Fill in the capabilities */
-	(*pkt)->capability = ieee80211softmac_capabilities(mac, net);
-
-	/* Fill in Listen Interval (?) */
-	(*pkt)->listen_interval = cpu_to_le16(10);
-	/* Fill in the current AP MAC */
-	memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN);
-
-	data = (u8 *)(*pkt)->info_element;
-	/* Add SSID */
-	data = ieee80211softmac_add_essid(data, &net->essid);
-	/* Add Rates */
-	data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
-	/* Return packet size */
-	return (data - (u8 *)(*pkt));
-}
-
-/* Create an authentication packet */
-static u32
-ieee80211softmac_auth(struct ieee80211_auth **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
-	u16 transaction, u16 status, int *encrypt_mpdu)
-{
-	u8 *data;
-	int auth_mode = mac->ieee->sec.auth_mode;
-	int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY
-		&& transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE);
-
-	/* Allocate Packet */
-	(*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt(
-		2 +		/* Auth Algorithm */
-		2 +		/* Auth Transaction Seq */
-		2 +		/* Status Code */
-		 /* Challenge Text IE */
-		(is_shared_response ? 1 + 1 + net->challenge_len : 0)
-	);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid);
-
-	/* Algorithm */
-	(*pkt)->algorithm = cpu_to_le16(auth_mode);
-	/* Transaction */
-	(*pkt)->transaction = cpu_to_le16(transaction);
-	/* Status */
-	(*pkt)->status = cpu_to_le16(status);
-
-	data = (u8 *)(*pkt)->info_element;
-	/* Challenge Text */
-	if (is_shared_response) {
-		*data = MFIE_TYPE_CHALLENGE;
-		data++;
-
-		/* Copy the challenge in */
-		*data = net->challenge_len;
-		data++;
-		memcpy(data, net->challenge, net->challenge_len);
-		data += net->challenge_len;
-
-		/* Make sure this frame gets encrypted with the shared key */
-		*encrypt_mpdu = 1;
-	} else
-		*encrypt_mpdu = 0;
-
-	/* Return the packet size */
-	return (data - (u8 *)(*pkt));
-}
-
-/* Create a disassocation or deauthentication packet */
-static u32
-ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net,
-	u16 type, u16 reason)
-{
-	/* Allocate Packet */
-	(*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid);
-	/* Reason */
-	(*pkt)->reason = cpu_to_le16(reason);
-	/* Return the packet size */
-	return (2 + IEEE80211_3ADDR_LEN);
-}
-
-/* Create a probe request packet */
-static u32
-ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid)
-{
-	u8 *data;
-	/* Allocate Packet */
-	(*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt(
-		/* SSID of requested network */
-		1 + 1 + IW_ESSID_MAX_SIZE +
-		/* Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN +
-		/* Extended Rates IE */
-		1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN
-	);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL);
-
-	data = (u8 *)(*pkt)->info_element;
-	/* Add ESSID (can be NULL) */
-	data = ieee80211softmac_add_essid(data, essid);
-	/* Add Rates */
-	data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo);
-	/* Return packet size */
-	return (data - (u8 *)(*pkt));
-}
-
-/* Create a probe response packet */
-/* FIXME: Not complete */
-static u32
-ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt,
-	struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net)
-{
-	u8 *data;
-	/* Allocate Packet */
-	(*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt(
-		8 +		/* Timestamp */
-		2 +		/* Beacon Interval */
-		2 +		/* Capability Info */
-				/* SSID IE */
-		1 + 1 + IW_ESSID_MAX_SIZE +
-		7 + 		/* FH Parameter Set */
-		2 +		/* DS Parameter Set */
-		8 +		/* CF Parameter Set */
-		4 		/* IBSS Parameter Set */
-	);
-	if (unlikely((*pkt) == NULL))
-		return 0;
-	ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid);
-	data = (u8 *)(*pkt)->info_element;
-
-	/* Return the packet size */
-	return (data - (u8 *)(*pkt));
-}
-
-
-/* Sends a manangement packet
- * FIXME: document the use of the arg parameter
- * for _AUTH: (transaction #) | (status << 16)
- */
-int
-ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
-	void *ptrarg, u32 type, u32 arg)
-{
-	void *pkt = NULL;
-	u32 pkt_size = 0;
-	int encrypt_mpdu = 0;
-
-	switch(type) {
-	case IEEE80211_STYPE_ASSOC_REQ:
-		pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
-		break;
-	case IEEE80211_STYPE_REASSOC_REQ:
-		pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
-		break;
-	case IEEE80211_STYPE_AUTH:
-		pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu);
-		break;
-	case IEEE80211_STYPE_DISASSOC:
-	case IEEE80211_STYPE_DEAUTH:
-		pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF));
-		break;
-	case IEEE80211_STYPE_PROBE_REQ:
-		pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg);
-		break;
-	case IEEE80211_STYPE_PROBE_RESP:
-		pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg);
-		break;
-	default:
-		printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type);
-		return -EINVAL;
-	};
-
-	if(pkt_size == 0 || pkt == NULL) {
-		printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n");
-		return -ENOMEM;
-	}
-
-	/* Send the packet to the ieee80211 layer for tx */
-	/* we defined softmac->mgmt_xmit for this. Should we keep it
-	 * as it is (that means we'd need to wrap this into a txb),
-	 * modify the prototype (so it matches this function),
-	 * or get rid of it alltogether?
-	 * Does this work for you now?
-	 */
-	ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt,
-		IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu);
-
-	kfree(pkt);
-	return 0;
-}
-
-/* Beacon handling */
-int ieee80211softmac_handle_beacon(struct net_device *dev,
-	struct ieee80211_beacon *beacon,
-	struct ieee80211_network *network)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	/* This might race, but we don't really care and it's not worth
-	 * adding heavyweight locking in this fastpath.
-	 */
-	if (mac->associnfo.associated) {
-		if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
-			ieee80211softmac_process_erp(mac, network->erp_value);
-	}
-
-	return 0;
-}
-
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
deleted file mode 100644
index 07505ca859af..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ /dev/null
@@ -1,568 +0,0 @@
-/*
- * Contains some basic softmac functions along with module registration code etc.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-#include <linux/sort.h>
-#include <linux/etherdevice.h>
-
-struct net_device *alloc_ieee80211softmac(int sizeof_priv)
-{
-	struct ieee80211softmac_device *softmac;
-	struct net_device *dev;
-
-	dev = alloc_ieee80211(sizeof(*softmac) + sizeof_priv);
-	if (!dev)
-		return NULL;
-	softmac = ieee80211_priv(dev);
-	softmac->wq = create_freezeable_workqueue("softmac");
-	if (!softmac->wq) {
-		free_ieee80211(dev);
-		return NULL;
-	}
-
-	softmac->dev = dev;
-	softmac->ieee = netdev_priv(dev);
-	spin_lock_init(&softmac->lock);
-
-	softmac->ieee->handle_auth = ieee80211softmac_auth_resp;
-	softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp;
-	softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
-	softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
-	softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
-	softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
-	softmac->scaninfo = NULL;
-
-	softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
-
-	/* TODO: initialise all the other callbacks in the ieee struct
-	 *	 (once they're written)
-	 */
-
-	INIT_LIST_HEAD(&softmac->auth_queue);
-	INIT_LIST_HEAD(&softmac->network_list);
-	INIT_LIST_HEAD(&softmac->events);
-
-	mutex_init(&softmac->associnfo.mutex);
-	INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work);
-	INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout);
-	softmac->start_scan = ieee80211softmac_start_scan_implementation;
-	softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation;
-	softmac->stop_scan = ieee80211softmac_stop_scan_implementation;
-
-	/* to start with, we can't send anything ... */
-	netif_carrier_off(dev);
-
-	return dev;
-}
-EXPORT_SYMBOL_GPL(alloc_ieee80211softmac);
-
-/* Clears the pending work queue items, stops all scans, etc. */
-void
-ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
-{
-	unsigned long flags;
-	struct ieee80211softmac_event *eventptr, *eventtmp;
-	struct ieee80211softmac_auth_queue_item *authptr, *authtmp;
-	struct ieee80211softmac_network *netptr, *nettmp;
-
-	ieee80211softmac_stop_scan(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);
-
-	/* Free all pending scan work items */
-	if(sm->scaninfo != NULL)
-		cancel_delayed_work(&sm->scaninfo->softmac_scan);
-
-	/* Free all pending auth work items */
-	list_for_each_entry(authptr, &sm->auth_queue, list)
-		cancel_delayed_work(&authptr->work);
-
-	/* delete all pending event calls and work items */
-	list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list)
-		cancel_delayed_work(&eventptr->work);
-
-	spin_unlock_irqrestore(&sm->lock, flags);
-	flush_workqueue(sm->wq);
-
-	/* now we should be save and no longer need locking... */
-	spin_lock_irqsave(&sm->lock, flags);
-	/* Free all pending auth work items */
-	list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) {
-		list_del(&authptr->list);
-		kfree(authptr);
-	}
-
-	/* delete all pending event calls and work items */
-	list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) {
-		list_del(&eventptr->list);
-		kfree(eventptr);
-	}
-
-	/* Free all networks */
-	list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) {
-		ieee80211softmac_del_network_locked(sm, netptr);
-		if(netptr->challenge != NULL)
-			kfree(netptr->challenge);
-		kfree(netptr);
-	}
-
-	spin_unlock_irqrestore(&sm->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work);
-
-void free_ieee80211softmac(struct net_device *dev)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(dev);
-	ieee80211softmac_clear_pending_work(sm);
-	kfree(sm->scaninfo);
-	kfree(sm->wpa.IE);
-	destroy_workqueue(sm->wq);
-	free_ieee80211(dev);
-}
-EXPORT_SYMBOL_GPL(free_ieee80211softmac);
-
-static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac)
-{
-	struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
-	/* I took out the sorting check, we're seperating by modulation now. */
-	if (ri->count)
-		return;
-	/* otherwise assume we hav'em all! */
-	if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) {
-		ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB;
-		ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB;
-		ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB;
-		ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB;
-	}
-	if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) {
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB;
-		ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB;
-	}
-}
-
-int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate)
-{
-	int search;
-	u8 search_rate;
-
-	for (search = 0; search < ri->count; search++) {
-		search_rate = ri->rates[search];
-		search_rate &= ~IEEE80211_BASIC_RATE_MASK;
-		if (rate == search_rate)
-			return 1;
-	}
-
-	return 0;
-}
-
-u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_ratesinfo *ri, int basic_only)
-{
-	u8 user_rate = mac->txrates.user_rate;
-	int i;
-
-	if (ri->count == 0)
-		return IEEE80211_CCK_RATE_1MB;
-
-	for (i = ri->count - 1; i >= 0; i--) {
-		u8 rate = ri->rates[i];
-		if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK))
-			continue;
-		rate &= ~IEEE80211_BASIC_RATE_MASK;
-		if (rate > user_rate)
-			continue;
-		if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate))
-			return rate;
-	}
-
-	/* If we haven't found a suitable rate by now, just trust the user */
-	return user_rate;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
-
-void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
-	u8 erp_value)
-{
-	int use_protection;
-	int short_preamble;
-	u32 changes = 0;
-
-	/* Barker preamble mode */
-	short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
-			  && mac->associnfo.short_preamble_available) ? 1 : 0;
-
-	/* Protection needed? */
-	use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
-
-	if (mac->bssinfo.short_preamble != short_preamble) {
-		changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
-		mac->bssinfo.short_preamble = short_preamble;
-	}
-
-	if (mac->bssinfo.use_protection != use_protection) {
-		changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
-		mac->bssinfo.use_protection = use_protection;
-	}
-
-	if (mac->bssinfo_change && changes)
-		mac->bssinfo_change(mac->dev, changes);
-}
-
-void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
-{
-	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	u32 change = 0;
-
-	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-	txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
-
-	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-	txrates->default_fallback = lower_rate(mac, txrates->default_rate);
-
-	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-	txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
-
-	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change);
-
-}
-
-void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
-{
-	struct ieee80211_device *ieee = mac->ieee;
-	u32 change = 0;
-	struct ieee80211softmac_txrates *txrates = &mac->txrates;
-	struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
-
-	/* TODO: We need some kind of state machine to lower the default rates
-	 *       if we loose too many packets.
-	 */
-	/* Change the default txrate to the highest possible value.
-	 * The txrate machine will lower it, if it is too high.
-	 */
-	if (ieee->modulation & IEEE80211_OFDM_MODULATION)
-		txrates->user_rate = IEEE80211_OFDM_RATE_24MB;
-	else
-		txrates->user_rate = IEEE80211_CCK_RATE_11MB;
-
-	txrates->default_rate = IEEE80211_CCK_RATE_1MB;
-	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-
-	txrates->default_fallback = IEEE80211_CCK_RATE_1MB;
-	change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-
-	txrates->mcast_rate = IEEE80211_CCK_RATE_1MB;
-	change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
-
-	txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB;
-	change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
-
-	if (mac->txrates_change)
-		mac->txrates_change(mac->dev, change);
-
-	change = 0;
-
-	bssinfo->supported_rates.count = 0;
-	memset(bssinfo->supported_rates.rates, 0,
-		sizeof(bssinfo->supported_rates.rates));
-	change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
-
-	bssinfo->short_preamble = 0;
-	change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
-
-	bssinfo->use_protection = 0;
-	change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
-
-	if (mac->bssinfo_change)
-		mac->bssinfo_change(mac->dev, change);
-
-	mac->running = 1;
-}
-
-void ieee80211softmac_start(struct net_device *dev)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	ieee80211softmac_start_check_rates(mac);
-	ieee80211softmac_init_bss(mac);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_start);
-
-void ieee80211softmac_stop(struct net_device *dev)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-
-	ieee80211softmac_clear_pending_work(mac);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_stop);
-
-void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	memcpy(mac->ratesinfo.rates, rates, count);
-	mac->ratesinfo.count = count;
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates);
-
-static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate)
-{
-	int i;
-	struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
-
-	for (i=0; i<ri->count-1; i++) {
-		if (ri->rates[i] == rate)
-			return ri->rates[i+1];
-	}
-	/* I guess we can't go any higher... */
-	return ri->rates[ri->count];
-}
-
-u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta)
-{
-	int i;
-	struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo;
-
-	for (i=delta; i<ri->count; i++) {
-		if (ri->rates[i] == rate)
-			return ri->rates[i-delta];
-	}
-	/* I guess we can't go any lower... */
-	return ri->rates[0];
-}
-
-static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
-						 int amount)
-{
-	u8 default_rate = mac->txrates.default_rate;
-	u8 default_fallback = mac->txrates.default_fallback;
-	u32 changes = 0;
-
-	//TODO: This is highly experimental code.
-	//      Maybe the dynamic rate selection does not work
-	//      and it has to be removed again.
-
-printk("badness %d\n", mac->txrate_badness);
-	mac->txrate_badness += amount;
-	if (mac->txrate_badness <= -1000) {
-		/* Very small badness. Try a faster bitrate. */
-		default_rate = raise_rate(mac, default_rate);
-		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-		default_fallback = get_fallback_rate(mac, default_rate);
-		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-		mac->txrate_badness = 0;
-printk("Bitrate raised to %u\n", default_rate);
-	} else if (mac->txrate_badness >= 10000) {
-		/* Very high badness. Try a slower bitrate. */
-		default_rate = lower_rate(mac, default_rate);
-		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
-		default_fallback = get_fallback_rate(mac, default_rate);
-		changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
-		mac->txrate_badness = 0;
-printk("Bitrate lowered to %u\n", default_rate);
-	}
-
-	mac->txrates.default_rate = default_rate;
-	mac->txrates.default_fallback = default_fallback;
-
-	if (changes && mac->txrates_change)
-		mac->txrates_change(mac->dev, changes);
-}
-
-void ieee80211softmac_fragment_lost(struct net_device *dev,
-				    u16 wl_seq)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	ieee80211softmac_add_txrates_badness(mac, 1000);
-	//TODO
-
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost);
-
-static int rate_cmp(const void *a_, const void *b_) {
-	u8 *a, *b;
-	a = (u8*)a_;
-	b = (u8*)b_;
-	return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK));
-}
-
-/* Allocate a softmac network struct and fill it from a network */
-struct ieee80211softmac_network *
-ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
-	struct ieee80211_network *net)
-{
-	struct ieee80211softmac_network *softnet;
-	softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC);
-	if(softnet == NULL)
-		return NULL;
-	memcpy(softnet->bssid, net->bssid, ETH_ALEN);
-	softnet->channel = net->channel;
-	softnet->essid.len = net->ssid_len;
-	memcpy(softnet->essid.data, net->ssid, softnet->essid.len);
-
-	/* copy rates over */
-	softnet->supported_rates.count = net->rates_len;
-	memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len);
-	memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
-	softnet->supported_rates.count += net->rates_ex_len;
-	sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-
-	/* we save the ERP value because it is needed at association time, and
-	 * many AP's do not include an ERP IE in the association response. */
-	softnet->erp_value = net->erp_value;
-
-	softnet->capabilities = net->capability;
-	return softnet;
-}
-
-
-/* Add a network to the list, while locked */
-void
-ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *add_net)
-{
-	struct ieee80211softmac_network *softmac_net;
-
-	list_for_each_entry(softmac_net, &mac->network_list, list) {
-		if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN))
-			return;
-	}
-	list_add(&(add_net->list), &mac->network_list);
-}
-
-/* Add a network to the list, with locking */
-void
-ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *add_net)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&mac->lock, flags);
-	ieee80211softmac_add_network_locked(mac, add_net);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-
-/* Delete a network from the list, while locked*/
-void
-ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *del_net)
-{
-	list_del(&(del_net->list));
-}
-
-/* Delete a network from the list with locking */
-void
-ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *del_net)
-{
-	unsigned long flags;
-	spin_lock_irqsave(&mac->lock, flags);
-	ieee80211softmac_del_network_locked(mac, del_net);
-	spin_unlock_irqrestore(&mac->lock, flags);
-}
-
-/* Get a network from the list by MAC while locked */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac,
-	u8 *bssid)
-{
-	struct ieee80211softmac_network *softmac_net;
-
-	list_for_each_entry(softmac_net, &mac->network_list, list) {
-		if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN))
-			return softmac_net;
-	}
-	return NULL;
-}
-
-/* Get a network from the list by BSSID with locking */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac,
-	u8 *bssid)
-{
-	unsigned long flags;
-	struct ieee80211softmac_network *softmac_net;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid);
-	spin_unlock_irqrestore(&mac->lock, flags);
-	return softmac_net;
-}
-
-/* Get a network from the list by ESSID while locked */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_essid *essid)
-{
-	struct ieee80211softmac_network *softmac_net;
-
-	list_for_each_entry(softmac_net, &mac->network_list, list) {
-		if (softmac_net->essid.len == essid->len &&
-			!memcmp(softmac_net->essid.data, essid->data, essid->len))
-			return softmac_net;
-	}
-	return NULL;
-}
-
-/* Get a network from the list by ESSID with locking */
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_essid *essid)
-{
-	unsigned long flags;
-	struct ieee80211softmac_network *softmac_net = NULL;
-
-	spin_lock_irqsave(&mac->lock, flags);
-	softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid);
-	spin_unlock_irqrestore(&mac->lock, flags);
-	return softmac_net;
-}
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Johannes Berg");
-MODULE_AUTHOR("Joseph Jezak");
-MODULE_AUTHOR("Larry Finger");
-MODULE_AUTHOR("Danny van Dyk");
-MODULE_AUTHOR("Michael Buesch");
-MODULE_DESCRIPTION("802.11 software MAC");
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
deleted file mode 100644
index c43b189634df..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Internal softmac API definitions.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#ifndef IEEE80211SOFTMAC_PRIV_H_
-#define IEEE80211SOFTMAC_PRIV_H_
-
-#include <net/ieee80211softmac.h>
-#include <net/ieee80211softmac_wx.h>
-#include <linux/kernel.h>
-#include <linux/stringify.h>
-
-
-#define PFX				"SoftMAC: "
-
-#ifdef assert
-# undef assert
-#endif
-#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
-#define assert(expr) \
-	do {										\
-		if (unlikely(!(expr))) {						\
-		printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr,	\
-			__FILE__, __LINE__, __FUNCTION__);				\
-		}									\
-	} while (0)
-#else
-#define assert(expr) do {} while (0)
-#endif
-
-/* rate limited printk(). */
-#ifdef printkl
-# undef printkl
-#endif
-#define printkl(f, x...)  do { if (printk_ratelimit()) printk(f ,##x); } while (0)
-/* rate limited printk() for debugging */
-#ifdef dprintkl
-# undef dprintkl
-#endif
-#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
-# define dprintkl		printkl
-#else
-# define dprintkl(f, x...)	do { /* nothing */ } while (0)
-#endif
-
-/* debugging printk() */
-#ifdef dprintk
-# undef dprintk
-#endif
-#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG
-# define dprintk(f, x...)  do { printk(f ,##x); } while (0)
-#else
-# define dprintk(f, x...)  do { /* nothing */ } while (0)
-#endif
-
-/* private definitions and prototypes */
-
-/*** prototypes from _scan.c */
-void ieee80211softmac_scan(struct work_struct *work);
-/* for internal use if scanning is needed */
-int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac);
-void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac);
-void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac);
-
-/* for use by _module.c to assign to the callbacks */
-int ieee80211softmac_start_scan_implementation(struct net_device *dev);
-void ieee80211softmac_stop_scan_implementation(struct net_device *dev);
-void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev);
-
-/*** Network prototypes from _module.c */
-struct ieee80211softmac_network * ieee80211softmac_create_network(
-	struct ieee80211softmac_device *mac, struct ieee80211_network *net);
-void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net);
-void ieee80211softmac_add_network(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net);
-void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net);
-void ieee80211softmac_del_network(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_network *net);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked(
-	struct ieee80211softmac_device *mac, u8 *ea);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid(
-	struct ieee80211softmac_device *mac, u8 *ea);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked(
-	struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
-struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid(
-	struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len);
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_essid *essid);
-struct ieee80211softmac_network *
-ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
-	struct ieee80211softmac_essid *essid);
-
-/* Rates related */
-void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
-	u8 erp_value);
-int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
-u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
-void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
-static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
-	return ieee80211softmac_lower_rate_delta(mac, rate, 1);
-}
-
-static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
-{
-	return ieee80211softmac_lower_rate_delta(mac, rate, 2);
-}
-
-
-/*** prototypes from _io.c */
-int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
-	void* ptrarg, u32 type, u32 arg);
-int ieee80211softmac_handle_beacon(struct net_device *dev,
-	struct ieee80211_beacon *beacon,
-	struct ieee80211_network *network);
-
-/*** prototypes from _auth.c */
-/* do these have to go into the public header? */
-int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net);
-int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason);
-
-/* for use by _module.c to assign to the callbacks */
-int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth);
-int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth);
-
-/*** prototypes from _assoc.c */
-void ieee80211softmac_assoc_work(struct work_struct *work);
-int ieee80211softmac_handle_assoc_response(struct net_device * dev,
-					   struct ieee80211_assoc_response * resp,
-					   struct ieee80211_network * network);
-int ieee80211softmac_handle_disassoc(struct net_device * dev,
-				     struct ieee80211_disassoc * disassoc);
-int ieee80211softmac_handle_reassoc_req(struct net_device * dev,
-					struct ieee80211_reassoc_request * reassoc);
-void ieee80211softmac_assoc_timeout(struct work_struct *work);
-void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason);
-void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac);
-
-/* some helper functions */
-static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm)
-{
-	return (sm->start_scan == ieee80211softmac_start_scan_implementation) &&
-		(sm->stop_scan == ieee80211softmac_stop_scan_implementation) &&
-		(sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation);
-}
-
-static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm)
-{
-	return ((sm->start_scan != ieee80211softmac_start_scan_implementation) &&
-		(sm->stop_scan != ieee80211softmac_stop_scan_implementation) &&
-		(sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation)
-		) || ieee80211softmac_scan_handlers_check_self(sm);
-}
-
-#define IEEE80211SOFTMAC_PROBE_DELAY		HZ/50
-#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN	(17 + IFNAMSIZ)
-
-struct ieee80211softmac_network {
-	struct list_head		list;	/* List */
-	/* Network information copied from ieee80211_network */
-	u8 bssid[ETH_ALEN];
-	u8 channel;
-	struct ieee80211softmac_essid essid;
-
-	struct ieee80211softmac_ratesinfo supported_rates;
-
-	/* SoftMAC specific */
-	u16 authenticating:1,			/* Status Flags */
-	    authenticated:1,
-	    auth_desynced_once:1;
-
-	u8 erp_value;				/* Saved ERP value */
-	u16 capabilities;			/* Capabilities bitfield */
-	u8 challenge_len;			/* Auth Challenge length */
-	char *challenge;			/* Challenge Text */
-};
-
-/* structure used to keep track of networks we're auth'ing to */
-struct ieee80211softmac_auth_queue_item {
-	struct list_head		list;	/* List head */
-	struct ieee80211softmac_network	*net;	/* Network to auth */
-	struct ieee80211softmac_device	*mac;	/* SoftMAC device */
-	u8 retry;				/* Retry limit */
-	u8 state;				/* Auth State */
-	struct delayed_work		work;	/* Work queue */
-};
-
-/* scanning information */
-struct ieee80211softmac_scaninfo {
-	u8 current_channel_idx,
-	   number_channels;
-	struct ieee80211_channel *channels;
-	u8 started:1,
-	   stop:1;
-	u8 skip_flags;
-	struct completion finished;
-	struct delayed_work softmac_scan;
-	struct ieee80211softmac_device *mac;
-};
-
-/* private event struct */
-struct ieee80211softmac_event {
-	struct list_head list;
-	int event_type;
-	void *event_context;
-	struct delayed_work work;
-	notify_function_ptr fun;
-	void *context;
-	struct ieee80211softmac_device *mac;
-};
-
-void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context);
-void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context);
-int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac,
-	int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask);
-
-void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac);
-
-#endif /* IEEE80211SOFTMAC_PRIV_H_ */
diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c
deleted file mode 100644
index bfab8d7db88f..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_scan.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Scanning routines.
- *
- * These are not exported because they're assigned to the function pointers.
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include <linux/completion.h>
-#include "ieee80211softmac_priv.h"
-
-/* internal, use to trigger scanning if needed.
- * Returns -EBUSY if already scanning,
- * result of start_scan otherwise */
-int
-ieee80211softmac_start_scan(struct ieee80211softmac_device *sm)
-{
-	unsigned long flags;
-	int ret;
-
-	spin_lock_irqsave(&sm->lock, flags);
-	if (sm->scanning)
-	{
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return -EINPROGRESS;
-	}
-	sm->scanning = 1;
-	spin_unlock_irqrestore(&sm->lock, flags);
-
-	ret = sm->start_scan(sm->dev);
-	if (ret) {
-		spin_lock_irqsave(&sm->lock, flags);
-		sm->scanning = 0;
-		spin_unlock_irqrestore(&sm->lock, flags);
-	}
-	return ret;
-}
-
-void
-ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sm->lock, flags);
-
-	if (!sm->scanning) {
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return;
-	}
-
-	spin_unlock_irqrestore(&sm->lock, flags);
-	sm->stop_scan(sm->dev);
-}
-
-void
-ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sm->lock, flags);
-
-	if (!sm->scanning) {
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return;
-	}
-
-	spin_unlock_irqrestore(&sm->lock, flags);
-	sm->wait_for_scan(sm->dev);
-}
-
-
-/* internal scanning implementation follows */
-void ieee80211softmac_scan(struct work_struct *work)
-{
-	int invalid_channel;
-	u8 current_channel_idx;
-	struct ieee80211softmac_scaninfo *si =
-		container_of(work, struct ieee80211softmac_scaninfo,
-			     softmac_scan.work);
-	struct ieee80211softmac_device *sm = si->mac;
-	unsigned long flags;
-
-	while (!(si->stop) && (si->current_channel_idx < si->number_channels)) {
-		current_channel_idx = si->current_channel_idx;
-		si->current_channel_idx++; /* go to the next channel */
-
-		invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags);
-
-		if (!invalid_channel) {
-			sm->set_channel(sm->dev, si->channels[current_channel_idx].channel);
-			// FIXME make this user configurable (active/passive)
-			if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0))
-				printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n");
-
-			/* also send directed management frame for the network we're looking for */
-			// 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;
-			}
-			queue_delayed_work(sm->wq, &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);
-		}
-	}
-
-	spin_lock_irqsave(&sm->lock, flags);
-	cancel_delayed_work(&si->softmac_scan);
-	si->started = 0;
-	spin_unlock_irqrestore(&sm->lock, flags);
-
-	dprintk(PFX "Scanning finished: scanned %d channels starting with channel %d\n",
-		     sm->scaninfo->number_channels, sm->scaninfo->channels[0].channel);
-	ieee80211softmac_scan_finished(sm);
-	complete_all(&sm->scaninfo->finished);
-}
-
-static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac)
-{
-	/* ugh. can we call this without having the spinlock held? */
-	struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC);
-	if (unlikely(!info))
-		return NULL;
-	INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan);
-	info->mac = mac;
-	init_completion(&info->finished);
-	return info;
-}
-
-int ieee80211softmac_start_scan_implementation(struct net_device *dev)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(dev);
-	unsigned long flags;
-
-	if (!(dev->flags & IFF_UP))
-		return -ENODEV;
-
-	assert(ieee80211softmac_scan_handlers_check_self(sm));
-	if (!ieee80211softmac_scan_handlers_check_self(sm))
-		return -EINVAL;
-
-	spin_lock_irqsave(&sm->lock, flags);
-	/* it looks like we need to hold the lock here
-	 * to make sure we don't allocate two of these... */
-	if (unlikely(!sm->scaninfo))
-		sm->scaninfo = allocate_scaninfo(sm);
-	if (unlikely(!sm->scaninfo)) {
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return -ENOMEM;
-	}
-
-	sm->scaninfo->skip_flags = IEEE80211_CH_INVALID;
-	if (0 /* not scanning in IEEE802.11b */)//TODO
-		sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY;
-	if (0 /* IEEE802.11a */) {//TODO
-		sm->scaninfo->channels = sm->ieee->geo.a;
-		sm->scaninfo->number_channels = sm->ieee->geo.a_channels;
-	} else {
-		sm->scaninfo->channels = sm->ieee->geo.bg;
-		sm->scaninfo->number_channels = sm->ieee->geo.bg_channels;
-	}
-	sm->scaninfo->current_channel_idx = 0;
-	sm->scaninfo->started = 1;
-	sm->scaninfo->stop = 0;
-	INIT_COMPLETION(sm->scaninfo->finished);
-	queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0);
-	spin_unlock_irqrestore(&sm->lock, flags);
-	return 0;
-}
-
-void ieee80211softmac_stop_scan_implementation(struct net_device *dev)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(dev);
-	unsigned long flags;
-
-	assert(ieee80211softmac_scan_handlers_check_self(sm));
-	if (!ieee80211softmac_scan_handlers_check_self(sm))
-		return;
-
-	spin_lock_irqsave(&sm->lock, flags);
-	assert(sm->scaninfo != NULL);
-	if (sm->scaninfo) {
-		if (sm->scaninfo->started)
-			sm->scaninfo->stop = 1;
-		else
-			complete_all(&sm->scaninfo->finished);
-	}
-	spin_unlock_irqrestore(&sm->lock, flags);
-}
-
-void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(dev);
-	unsigned long flags;
-
-	assert(ieee80211softmac_scan_handlers_check_self(sm));
-	if (!ieee80211softmac_scan_handlers_check_self(sm))
-		return;
-
-	spin_lock_irqsave(&sm->lock, flags);
-	if (!sm->scaninfo->started) {
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return;
-	}
-	spin_unlock_irqrestore(&sm->lock, flags);
-	wait_for_completion(&sm->scaninfo->finished);
-}
-
-/* this is what drivers (that do scanning) call when they're done */
-void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&sm->lock, flags);
-	sm->scanning = 0;
-	spin_unlock_irqrestore(&sm->lock, flags);
-
-	if (sm->associnfo.bssvalid) {
-		struct ieee80211softmac_network *net;
-
-		net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
-		if (net)
-			sm->set_channel(sm->dev, net->channel);
-	}
-	ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished);
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
deleted file mode 100644
index e01b59aedc54..000000000000
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them
- *
- * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net>
- *                          Joseph Jezak <josejx@gentoo.org>
- *                          Larry Finger <Larry.Finger@lwfinger.net>
- *                          Danny van Dyk <kugelfang@gentoo.org>
- *                          Michael Buesch <mbuesch@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-
-#include "ieee80211softmac_priv.h"
-
-#include <net/iw_handler.h>
-/* for is_broadcast_ether_addr and is_zero_ether_addr */
-#include <linux/etherdevice.h>
-
-int
-ieee80211softmac_wx_trigger_scan(struct net_device *net_dev,
-				 struct iw_request_info *info,
-				 union iwreq_data *data,
-				 char *extra)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-	return ieee80211softmac_start_scan(sm);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan);
-
-
-/* if we're still scanning, return -EAGAIN so that userspace tools
- * can get the complete scan results, otherwise return 0. */
-int
-ieee80211softmac_wx_get_scan_results(struct net_device *net_dev,
-				     struct iw_request_info *info,
-				     union iwreq_data *data,
-				     char *extra)
-{
-	unsigned long flags;
-	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-
-	spin_lock_irqsave(&sm->lock, flags);
-	if (sm->scanning) {
-		spin_unlock_irqrestore(&sm->lock, flags);
-		return -EAGAIN;
-	}
-	spin_unlock_irqrestore(&sm->lock, flags);
-	return ieee80211_wx_get_scan(sm->ieee, info, data, extra);
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results);
-
-int
-ieee80211softmac_wx_set_essid(struct net_device *net_dev,
-			      struct iw_request_info *info,
-			      union iwreq_data *data,
-			      char *extra)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-	struct ieee80211softmac_auth_queue_item *authptr;
-	int length = 0;
-	DECLARE_MAC_BUF(mac);
-
-check_assoc_again:
-	mutex_lock(&sm->associnfo.mutex);
-	if((sm->associnfo.associating || sm->associnfo.associated) &&
-	   (data->essid.flags && data->essid.length)) {
-		dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
-		/* Cancel assoc work */
-		cancel_delayed_work(&sm->associnfo.work);
-		/* We don't have to do this, but it's a little cleaner */
-		list_for_each_entry(authptr, &sm->auth_queue, list)
-			cancel_delayed_work(&authptr->work);
-		sm->associnfo.bssvalid = 0;
-		sm->associnfo.bssfixed = 0;
-		sm->associnfo.associating = 0;
-		sm->associnfo.associated = 0;
-		/* We must unlock to avoid deadlocks with the assoc workqueue
-		 * on the associnfo.mutex */
-		mutex_unlock(&sm->associnfo.mutex);
-		flush_workqueue(sm->wq);
-		/* Avoid race! Check assoc status again. Maybe someone started an
-		 * association while we flushed. */
-		goto check_assoc_again;
-	}
-
-	sm->associnfo.static_essid = 0;
-	sm->associnfo.assoc_wait = 0;
-
-	if (data->essid.flags && data->essid.length) {
-		length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
-		if (length) {
-			memcpy(sm->associnfo.req_essid.data, extra, length);
-			sm->associnfo.static_essid = 1;
-		}
-	}
-
-	/* set our requested ESSID length.
-	 * If applicable, we have already copied the data in */
-	sm->associnfo.req_essid.len = length;
-
-	sm->associnfo.associating = 1;
-	/* queue lower level code to do work (if necessary) */
-	queue_delayed_work(sm->wq, &sm->associnfo.work, 0);
-
-	mutex_unlock(&sm->associnfo.mutex);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid);
-
-int
-ieee80211softmac_wx_get_essid(struct net_device *net_dev,
-			      struct iw_request_info *info,
-			      union iwreq_data *data,
-			      char *extra)
-{
-	struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
-
-	mutex_lock(&sm->associnfo.mutex);
-	/* If all fails, return ANY (empty) */
-	data->essid.length = 0;
-	data->essid.flags = 0;  /* active */
-
-	/* If we have a statically configured ESSID then return it */
-	if (sm->associnfo.static_essid) {
-		data->essid.length = sm->associnfo.req_essid.len;
-		data->essid.flags = 1;  /* active */
-		memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len);
-		dprintk(KERN_INFO PFX "Getting essid from req_essid\n");
-	} else if (sm->associnfo.associated || sm->associnfo.associating) {
-	/* If we're associating/associated, return that */
-		data->essid.length = sm->associnfo.associate_essid.len;
-		data->essid.flags = 1;  /* active */
-		memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len);
-		dprintk(KERN_INFO PFX "Getting essid from associate_essid\n");
-	}
-	mutex_unlock(&sm->associnfo.mutex);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid);
-
-int
-ieee80211softmac_wx_set_rate(struct net_device *net_dev,
-			     struct iw_request_info *info,
-			     union iwreq_data *data,
-			     char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
-	struct ieee80211_device *ieee = mac->ieee;
-	unsigned long flags;
-	s32 in_rate = data->bitrate.value;
-	u8 rate;
-	int is_ofdm = 0;
-	int err = -EINVAL;
-
-	if (in_rate == -1) {
-		if (ieee->modulation & IEEE80211_OFDM_MODULATION)
-			in_rate = 24000000;
-		else
-			in_rate = 11000000;
-	}
-
-	switch (in_rate) {
-	case 1000000:
-		rate = IEEE80211_CCK_RATE_1MB;
-		break;
-	case 2000000:
-		rate = IEEE80211_CCK_RATE_2MB;
-		break;
-	case 5500000:
-		rate = IEEE80211_CCK_RATE_5MB;
-		break;
-	case 11000000:
-		rate = IEEE80211_CCK_RATE_11MB;
-		break;
-	case 6000000:
-		rate = IEEE80211_OFDM_RATE_6MB;
-		is_ofdm = 1;
-		break;
-	case 9000000:
-		rate = IEEE80211_OFDM_RATE_9MB;
-		is_ofdm = 1;
-		break;
-	case 12000000:
-		rate = IEEE80211_OFDM_RATE_12MB;
-		is_ofdm = 1;
-		break;
-	case 18000000:
-		rate = IEEE80211_OFDM_RATE_18MB;
-		is_ofdm = 1;
-		break;
-	case 24000000:
-		rate = IEEE80211_OFDM_RATE_24MB;
-		is_ofdm = 1;
-		break;
-	case 36000000:
-		rate = IEEE80211_OFDM_RATE_36MB;
-		is_ofdm = 1;
-		break;
-	case 48000000:
-		rate = IEEE80211_OFDM_RATE_48MB;
-		is_ofdm = 1;
-		break;
-	case 54000000:
-		rate = IEEE80211_OFDM_RATE_54MB;
-		is_ofdm = 1;
-		break;
-	default:
-		goto out;
-	}
-
-	spin_lock_irqsave(&mac->lock, flags);
-
-	/* Check if correct modulation for this PHY. */
-	if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION))
-		goto out_unlock;
-
-	mac->txrates.user_rate = rate;
-	ieee80211softmac_recalc_txrates(mac);
-	err = 0;
-
-out_unlock:
-	spin_unlock_irqrestore(&mac->lock, flags);
-out:
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate);
-
-int
-ieee80211softmac_wx_get_rate(struct net_device *net_dev,
-			     struct iw_request_info *info,
-			     union iwreq_data *data,
-			     char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
-	unsigned long flags;
-	int err = -EINVAL;
-
-	spin_lock_irqsave(&mac->lock, flags);
-
-	if (unlikely(!mac->running)) {
-		err = -ENODEV;
-		goto out_unlock;
-	}
-
-	switch (mac->txrates.default_rate) {
-	case IEEE80211_CCK_RATE_1MB:
-		data->bitrate.value = 1000000;
-		break;
-	case IEEE80211_CCK_RATE_2MB:
-		data->bitrate.value = 2000000;
-		break;
-	case IEEE80211_CCK_RATE_5MB:
-		data->bitrate.value = 5500000;
-		break;
-	case IEEE80211_CCK_RATE_11MB:
-		data->bitrate.value = 11000000;
-		break;
-	case IEEE80211_OFDM_RATE_6MB:
-		data->bitrate.value = 6000000;
-		break;
-	case IEEE80211_OFDM_RATE_9MB:
-		data->bitrate.value = 9000000;
-		break;
-	case IEEE80211_OFDM_RATE_12MB:
-		data->bitrate.value = 12000000;
-		break;
-	case IEEE80211_OFDM_RATE_18MB:
-		data->bitrate.value = 18000000;
-		break;
-	case IEEE80211_OFDM_RATE_24MB:
-		data->bitrate.value = 24000000;
-		break;
-	case IEEE80211_OFDM_RATE_36MB:
-		data->bitrate.value = 36000000;
-		break;
-	case IEEE80211_OFDM_RATE_48MB:
-		data->bitrate.value = 48000000;
-		break;
-	case IEEE80211_OFDM_RATE_54MB:
-		data->bitrate.value = 54000000;
-		break;
-	default:
-		assert(0);
-		goto out_unlock;
-	}
-	err = 0;
-out_unlock:
-	spin_unlock_irqrestore(&mac->lock, flags);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate);
-
-int
-ieee80211softmac_wx_get_wap(struct net_device *net_dev,
-			    struct iw_request_info *info,
-			    union iwreq_data *data,
-			    char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
-	int err = 0;
-
-	mutex_lock(&mac->associnfo.mutex);
-	if (mac->associnfo.bssvalid)
-		memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN);
-	else
-		memset(data->ap_addr.sa_data, 0xff, ETH_ALEN);
-	data->ap_addr.sa_family = ARPHRD_ETHER;
-	mutex_unlock(&mac->associnfo.mutex);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap);
-
-int
-ieee80211softmac_wx_set_wap(struct net_device *net_dev,
-			    struct iw_request_info *info,
-			    union iwreq_data *data,
-			    char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
-
-	/* sanity check */
-	if (data->ap_addr.sa_family != ARPHRD_ETHER) {
-		return -EINVAL;
-	}
-
-	mutex_lock(&mac->associnfo.mutex);
-	if (is_broadcast_ether_addr(data->ap_addr.sa_data)) {
-		/* the bssid we have is not to be fixed any longer,
-		 * and we should reassociate to the best AP. */
-		mac->associnfo.bssfixed = 0;
-		/* force reassociation */
-		mac->associnfo.bssvalid = 0;
-		if (mac->associnfo.associated)
-			queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-	} else if (is_zero_ether_addr(data->ap_addr.sa_data)) {
-		/* the bssid we have is no longer fixed */
-		mac->associnfo.bssfixed = 0;
-	} else {
-		if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) {
-			if (mac->associnfo.associating || mac->associnfo.associated) {
-			/* bssid unchanged and associated or associating - just return */
-				goto out;
-			}
-		} else {
-			/* copy new value in data->ap_addr.sa_data to bssid */
-			memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN);
-		}
-		/* tell the other code that this bssid should be used no matter what */
-		mac->associnfo.bssfixed = 1;
-		/* queue associate if new bssid or (old one again and not associated) */
-		queue_delayed_work(mac->wq, &mac->associnfo.work, 0);
-	}
-
- out:
-	mutex_unlock(&mac->associnfo.mutex);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap);
-
-int
-ieee80211softmac_wx_set_genie(struct net_device *dev,
-			      struct iw_request_info *info,
-			      union iwreq_data *wrqu,
-			      char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	unsigned long flags;
-	int err = 0;
-	char *buf;
-	int i;
-
-	mutex_lock(&mac->associnfo.mutex);
-	spin_lock_irqsave(&mac->lock, flags);
-	/* bleh. shouldn't be locked for that kmalloc... */
-
-	if (wrqu->data.length) {
-		if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) {
-			/* this is an IE, so the length must be
-			 * correct. Is it possible though that
-			 * more than one IE is passed in?
-			 */
-			err = -EINVAL;
-			goto out;
-		}
-		if (mac->wpa.IEbuflen <= wrqu->data.length) {
-			buf = kmalloc(wrqu->data.length, GFP_ATOMIC);
-			if (!buf) {
-				err = -ENOMEM;
-				goto out;
-			}
-			kfree(mac->wpa.IE);
-			mac->wpa.IE = buf;
-			mac->wpa.IEbuflen = wrqu->data.length;
-		}
-		memcpy(mac->wpa.IE, extra, wrqu->data.length);
-		dprintk(KERN_INFO PFX "generic IE set to ");
-		for (i=0;i<wrqu->data.length;i++)
-			dprintk("%.2x", (u8)mac->wpa.IE[i]);
-		dprintk("\n");
-		mac->wpa.IElen = wrqu->data.length;
-	} else {
-		kfree(mac->wpa.IE);
-		mac->wpa.IE = NULL;
-		mac->wpa.IElen = 0;
-		mac->wpa.IEbuflen = 0;
-	}
-
- out:
-	spin_unlock_irqrestore(&mac->lock, flags);
-	mutex_unlock(&mac->associnfo.mutex);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie);
-
-int
-ieee80211softmac_wx_get_genie(struct net_device *dev,
-			      struct iw_request_info *info,
-			      union iwreq_data *wrqu,
-			      char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	unsigned long flags;
-	int err = 0;
-	int space = wrqu->data.length;
-
-	mutex_lock(&mac->associnfo.mutex);
-	spin_lock_irqsave(&mac->lock, flags);
-
-	wrqu->data.length = 0;
-
-	if (mac->wpa.IE && mac->wpa.IElen) {
-		wrqu->data.length = mac->wpa.IElen;
-		if (mac->wpa.IElen <= space)
-			memcpy(extra, mac->wpa.IE, mac->wpa.IElen);
-		else
-			err = -E2BIG;
-	}
-	spin_unlock_irqrestore(&mac->lock, flags);
-	mutex_unlock(&mac->associnfo.mutex);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie);
-
-int
-ieee80211softmac_wx_set_mlme(struct net_device *dev,
-			     struct iw_request_info *info,
-			     union iwreq_data *wrqu,
-			     char *extra)
-{
-	struct ieee80211softmac_device *mac = ieee80211_priv(dev);
-	struct iw_mlme *mlme = (struct iw_mlme *)extra;
-	u16 reason = mlme->reason_code;
-	struct ieee80211softmac_network *net;
-	int err = -EINVAL;
-
-	mutex_lock(&mac->associnfo.mutex);
-
-	if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) {
-		printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n");
-		goto out;
-	}
-
-	switch (mlme->cmd) {
-	case IW_MLME_DEAUTH:
-		net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data);
-		if (!net) {
-			printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n");
-			goto out;
-		}
-		err =  ieee80211softmac_deauth_req(mac, net, reason);
-		goto out;
-	case IW_MLME_DISASSOC:
-		ieee80211softmac_send_disassoc_req(mac, reason);
-		mac->associnfo.associated = 0;
-		mac->associnfo.associating = 0;
-		err = 0;
-		goto out;
-	default:
-		err = -EOPNOTSUPP;
-	}
-
-out:
-	mutex_unlock(&mac->associnfo.mutex);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 0d109504ed86..5882a1316441 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -243,6 +243,23 @@ void build_ehash_secret(void)
 }
 EXPORT_SYMBOL(build_ehash_secret);
 
+static inline int inet_netns_ok(struct net *net, int protocol)
+{
+	int hash;
+	struct net_protocol *ipprot;
+
+	if (net == &init_net)
+		return 1;
+
+	hash = protocol & (MAX_INET_PROTOS - 1);
+	ipprot = rcu_dereference(inet_protos[hash]);
+
+	if (ipprot == NULL)
+		/* raw IP is OK */
+		return 1;
+	return ipprot->netns_ok;
+}
+
 /*
  *	Create an inet socket.
  */
@@ -259,9 +276,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol)
 	int try_loading_module = 0;
 	int err;
 
-	if (net != &init_net)
-		return -EAFNOSUPPORT;
-
 	if (sock->type != SOCK_RAW &&
 	    sock->type != SOCK_DGRAM &&
 	    !inet_ehash_secret)
@@ -320,6 +334,10 @@ lookup_protocol:
 	if (answer->capability > 0 && !capable(answer->capability))
 		goto out_rcu_unlock;
 
+	err = -EAFNOSUPPORT;
+	if (!inet_netns_ok(net, protocol))
+		goto out_rcu_unlock;
+
 	sock->ops = answer->ops;
 	answer_prot = answer->prot;
 	answer_no_check = answer->no_check;
@@ -446,7 +464,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	if (addr_len < sizeof(struct sockaddr_in))
 		goto out;
 
-	chk_addr_ret = inet_addr_type(&init_net, addr->sin_addr.s_addr);
+	chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
 
 	/* Not specified by any standard per-se, however it breaks too
 	 * many applications when removed.  It is unfortunate since
@@ -784,6 +802,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
+	struct net *net = sock_net(sk);
 
 	switch (cmd) {
 		case SIOCGSTAMP:
@@ -795,12 +814,12 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
-			err = ip_rt_ioctl(sk->sk_net, cmd, (void __user *)arg);
+			err = ip_rt_ioctl(net, cmd, (void __user *)arg);
 			break;
 		case SIOCDARP:
 		case SIOCGARP:
 		case SIOCSARP:
-			err = arp_ioctl(sk->sk_net, cmd, (void __user *)arg);
+			err = arp_ioctl(net, cmd, (void __user *)arg);
 			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
@@ -813,7 +832,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 		case SIOCSIFPFLAGS:
 		case SIOCGIFPFLAGS:
 		case SIOCSIFFLAGS:
-			err = devinet_ioctl(cmd, (void __user *)arg);
+			err = devinet_ioctl(net, cmd, (void __user *)arg);
 			break;
 		default:
 			if (sk->sk_prot->ioctl)
@@ -1059,7 +1078,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
 	if (sysctl_ip_dynaddr > 1) {
 		printk(KERN_INFO "%s(): shifting inet->"
 				 "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
-		       __FUNCTION__,
+		       __func__,
 		       NIPQUAD(old_saddr),
 		       NIPQUAD(new_saddr));
 	}
@@ -1113,7 +1132,7 @@ int inet_sk_rebuild_header(struct sock *sk)
 	};
 
 	security_sk_classify_flow(sk, &fl);
-	err = ip_route_output_flow(&init_net, &rt, &fl, sk, 0);
+	err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0);
 }
 	if (!err)
 		sk_setup_caps(sk, &rt->u.dst);
@@ -1283,17 +1302,20 @@ static struct net_protocol tcp_protocol = {
 	.gso_send_check = tcp_v4_gso_send_check,
 	.gso_segment =	tcp_tso_segment,
 	.no_policy =	1,
+	.netns_ok =	1,
 };
 
 static struct net_protocol udp_protocol = {
 	.handler =	udp_rcv,
 	.err_handler =	udp_err,
 	.no_policy =	1,
+	.netns_ok =	1,
 };
 
 static struct net_protocol icmp_protocol = {
 	.handler =	icmp_rcv,
 	.no_policy =	1,
+	.netns_ok =	1,
 };
 
 static int __init init_ipv4_mibs(void)
@@ -1414,7 +1436,7 @@ static int __init inet_init(void)
 
 	ip_init();
 
-	tcp_v4_init(&inet_family_ops);
+	tcp_v4_init();
 
 	/* Setup TCP slab cache for open requests. */
 	tcp_init();
@@ -1429,7 +1451,8 @@ static int __init inet_init(void)
 	 *	Set the ICMP layer up
 	 */
 
-	icmp_init(&inet_family_ops);
+	if (icmp_init() < 0)
+		panic("Failed to create the ICMP control socket.\n");
 
 	/*
 	 *	Initialise the multicast router
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 8e17f65f4002..3ce2e137e7bc 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -242,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh)
 		return -EINVAL;
 	}
 
-	neigh->type = inet_addr_type(&init_net, addr);
+	neigh->type = inet_addr_type(dev_net(dev), addr);
 
 	parms = in_dev->arp_parms;
 	__neigh_parms_put(neigh->parms);
@@ -341,14 +341,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
 	switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
 	default:
 	case 0:		/* By default announce any local IP */
-		if (skb && inet_addr_type(&init_net, ip_hdr(skb)->saddr) == RTN_LOCAL)
+		if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL)
 			saddr = ip_hdr(skb)->saddr;
 		break;
 	case 1:		/* Restrict announcements of saddr in same subnet */
 		if (!skb)
 			break;
 		saddr = ip_hdr(skb)->saddr;
-		if (inet_addr_type(&init_net, saddr) == RTN_LOCAL) {
+		if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) {
 			/* saddr should be known to target */
 			if (inet_addr_onlink(in_dev, target, saddr))
 				break;
@@ -424,7 +424,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
 	int flag = 0;
 	/*unsigned long now; */
 
-	if (ip_route_output_key(&init_net, &rt, &fl) < 0)
+	if (ip_route_output_key(dev_net(dev), &rt, &fl) < 0)
 		return 1;
 	if (rt->u.dst.dev != dev) {
 		NET_INC_STATS_BH(LINUX_MIB_ARPFILTER);
@@ -475,9 +475,9 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb)
 		return 1;
 	}
 
-	paddr = ((struct rtable*)skb->dst)->rt_gateway;
+	paddr = skb->rtable->rt_gateway;
 
-	if (arp_set_predefined(inet_addr_type(&init_net, paddr), haddr, paddr, dev))
+	if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev))
 		return 0;
 
 	n = __neigh_lookup(&arp_tbl, &paddr, dev, 1);
@@ -570,14 +570,13 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
 	 *	Allocate a buffer
 	 */
 
-	skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
-				+ LL_RESERVED_SPACE(dev), GFP_ATOMIC);
+	skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
 	if (skb == NULL)
 		return NULL;
 
 	skb_reserve(skb, LL_RESERVED_SPACE(dev));
 	skb_reset_network_header(skb);
-	arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
+	arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev));
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_ARP);
 	if (src_hw == NULL)
@@ -710,6 +709,7 @@ static int arp_process(struct sk_buff *skb)
 	u16 dev_type = dev->type;
 	int addr_type;
 	struct neighbour *n;
+	struct net *net = dev_net(dev);
 
 	/* arp_rcv below verifies the ARP header and verifies the device
 	 * is ARP'able.
@@ -805,7 +805,7 @@ static int arp_process(struct sk_buff *skb)
 	/* Special case: IPv4 duplicate address detection packet (RFC2131) */
 	if (sip == 0) {
 		if (arp->ar_op == htons(ARPOP_REQUEST) &&
-		    inet_addr_type(&init_net, tip) == RTN_LOCAL &&
+		    inet_addr_type(net, tip) == RTN_LOCAL &&
 		    !arp_ignore(in_dev, sip, tip))
 			arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha,
 				 dev->dev_addr, sha);
@@ -815,7 +815,7 @@ static int arp_process(struct sk_buff *skb)
 	if (arp->ar_op == htons(ARPOP_REQUEST) &&
 	    ip_route_input(skb, tip, sip, 0, dev) == 0) {
 
-		rt = (struct rtable*)skb->dst;
+		rt = skb->rtable;
 		addr_type = rt->rt_type;
 
 		if (addr_type == RTN_LOCAL) {
@@ -835,7 +835,7 @@ static int arp_process(struct sk_buff *skb)
 			goto out;
 		} else if (IN_DEV_FORWARD(in_dev)) {
 			    if (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
-			     (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &init_net, &tip, dev, 0))) {
+			     (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
 				n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
 				if (n)
 					neigh_release(n);
@@ -858,14 +858,14 @@ static int arp_process(struct sk_buff *skb)
 
 	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
 
-	if (IPV4_DEVCONF_ALL(dev->nd_net, ARP_ACCEPT)) {
+	if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) {
 		/* Unsolicited ARP is not accepted by default.
 		   It is possible, that this option should be enabled for some
 		   devices (strip is candidate)
 		 */
 		if (n == NULL &&
 		    arp->ar_op == htons(ARPOP_REPLY) &&
-		    inet_addr_type(&init_net, sip) == RTN_UNICAST)
+		    inet_addr_type(net, sip) == RTN_UNICAST)
 			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
 	}
 
@@ -912,13 +912,8 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
 {
 	struct arphdr *arp;
 
-	if (dev->nd_net != &init_net)
-		goto freeskb;
-
 	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
-	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
-				 (2 * dev->addr_len) +
-				 (2 * sizeof(u32)))))
+	if (!pskb_may_pull(skb, arp_hdr_len(dev)))
 		goto freeskb;
 
 	arp = arp_hdr(skb);
@@ -1201,9 +1196,6 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
-		return NOTIFY_DONE;
-
 	switch (event) {
 	case NETDEV_CHANGEADDR:
 		neigh_changeaddr(&arp_tbl, dev);
@@ -1385,13 +1377,29 @@ static const struct file_operations arp_seq_fops = {
 	.release	= seq_release_net,
 };
 
-static int __init arp_proc_init(void)
+
+static int __net_init arp_net_init(struct net *net)
 {
-	if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops))
+	if (!proc_net_fops_create(net, "arp", S_IRUGO, &arp_seq_fops))
 		return -ENOMEM;
 	return 0;
 }
 
+static void __net_exit arp_net_exit(struct net *net)
+{
+	proc_net_remove(net, "arp");
+}
+
+static struct pernet_operations arp_net_ops = {
+	.init = arp_net_init,
+	.exit = arp_net_exit,
+};
+
+static int __init arp_proc_init(void)
+{
+	return register_pernet_subsys(&arp_net_ops);
+}
+
 #else /* CONFIG_PROC_FS */
 
 static int __init arp_proc_init(void)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 8cd357f41283..4637ded3dba8 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -1800,7 +1800,6 @@ int cipso_v4_sock_setattr(struct sock *sk,
 	}
 	memcpy(opt->__data, buf, buf_len);
 	opt->optlen = opt_len;
-	opt->is_data = 1;
 	opt->cipso = sizeof(struct iphdr);
 	kfree(buf);
 	buf = NULL;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 87490f7bb0f7..6848e4760f34 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -165,7 +165,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
 	if (!in_dev)
 		goto out;
 	INIT_RCU_HEAD(&in_dev->rcu_head);
-	memcpy(&in_dev->cnf, dev->nd_net->ipv4.devconf_dflt,
+	memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt,
 			sizeof(in_dev->cnf));
 	in_dev->cnf.sysctl = NULL;
 	in_dev->dev = dev;
@@ -437,7 +437,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
 
 static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *tb[IFA_MAX+1];
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm;
@@ -446,9 +446,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
 
 	ASSERT_RTNL();
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
 	if (err < 0)
 		goto errout;
@@ -555,14 +552,11 @@ errout:
 
 static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct in_ifaddr *ifa;
 
 	ASSERT_RTNL();
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	ifa = rtm_to_ifaddr(net, nlh);
 	if (IS_ERR(ifa))
 		return PTR_ERR(ifa);
@@ -595,7 +589,7 @@ static __inline__ int inet_abc_len(__be32 addr)
 }
 
 
-int devinet_ioctl(unsigned int cmd, void __user *arg)
+int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 {
 	struct ifreq ifr;
 	struct sockaddr_in sin_orig;
@@ -624,7 +618,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg)
 		*colon = 0;
 
 #ifdef CONFIG_KMOD
-	dev_load(&init_net, ifr.ifr_name);
+	dev_load(net, ifr.ifr_name);
 #endif
 
 	switch (cmd) {
@@ -665,7 +659,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg)
 	rtnl_lock();
 
 	ret = -ENODEV;
-	if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL)
+	if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL)
 		goto done;
 
 	if (colon)
@@ -878,6 +872,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
 {
 	__be32 addr = 0;
 	struct in_device *in_dev;
+	struct net *net = dev_net(dev);
 
 	rcu_read_lock();
 	in_dev = __in_dev_get_rcu(dev);
@@ -906,7 +901,7 @@ no_in_dev:
 	 */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
 			continue;
 
@@ -979,7 +974,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev,
 	if (scope != RT_SCOPE_LINK)
 		return confirm_addr_indev(in_dev, dst, local, scope);
 
-	net = in_dev->dev->nd_net;
+	net = dev_net(in_dev->dev);
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
 	for_each_netdev(net, dev) {
@@ -1045,9 +1040,6 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
 	struct net_device *dev = ptr;
 	struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
-	if (dev->nd_net != &init_net)
-		return NOTIFY_DONE;
-
 	ASSERT_RTNL();
 
 	if (!in_dev) {
@@ -1166,16 +1158,13 @@ nla_put_failure:
 
 static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int idx, ip_idx;
 	struct net_device *dev;
 	struct in_device *in_dev;
 	struct in_ifaddr *ifa;
 	int s_ip_idx, s_idx = cb->args[0];
 
-	if (net != &init_net)
-		return 0;
-
 	s_ip_idx = ip_idx = cb->args[1];
 	idx = 0;
 	for_each_netdev(net, dev) {
@@ -1214,7 +1203,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh,
 	int err = -ENOBUFS;
 	struct net *net;
 
-	net = ifa->ifa_dev->dev->nd_net;
+	net = dev_net(ifa->ifa_dev->dev);
 	skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL);
 	if (skb == NULL)
 		goto errout;
@@ -1528,7 +1517,7 @@ static void devinet_sysctl_register(struct in_device *idev)
 {
 	neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
 			NET_IPV4_NEIGH, "ipv4", NULL, NULL);
-	__devinet_sysctl_register(idev->dev->nd_net, idev->dev->name,
+	__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
 			idev->dev->ifindex, &idev->cnf);
 }
 
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 86ff2711fc95..0f1557a4ac7a 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -257,7 +257,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
 	if (in_dev == NULL)
 		goto e_inval;
 
-	net = dev->nd_net;
+	net = dev_net(dev);
 	if (fib_lookup(net, &fl, &res))
 		goto last_resort;
 	if (res.type != RTN_UNICAST)
@@ -583,7 +583,7 @@ errout:
 
 static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct fib_config cfg;
 	struct fib_table *tb;
 	int err;
@@ -605,7 +605,7 @@ errout:
 
 static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct fib_config cfg;
 	struct fib_table *tb;
 	int err;
@@ -627,7 +627,7 @@ errout:
 
 static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	unsigned int h, s_h;
 	unsigned int e = 0, s_e;
 	struct fib_table *tb;
@@ -674,7 +674,7 @@ out:
 
 static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
 {
-	struct net *net = ifa->ifa_dev->dev->nd_net;
+	struct net *net = dev_net(ifa->ifa_dev->dev);
 	struct fib_table *tb;
 	struct fib_config cfg = {
 		.fc_protocol = RTPROT_KERNEL,
@@ -801,15 +801,15 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
 		fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
 
 		/* Check, that this local address finally disappeared. */
-		if (inet_addr_type(dev->nd_net, ifa->ifa_local) != RTN_LOCAL) {
+		if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) {
 			/* And the last, but not the least thing.
 			   We must flush stray FIB entries.
 
 			   First of all, we scan fib_info list searching
 			   for stray nexthop entries, then ignite fib_flush.
 			*/
-			if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local))
-				fib_flush(dev->nd_net);
+			if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local))
+				fib_flush(dev_net(dev));
 		}
 	}
 #undef LOCAL_OK
@@ -857,7 +857,7 @@ static void nl_fib_input(struct sk_buff *skb)
 	struct fib_table *tb;
 	u32 pid;
 
-	net = skb->sk->sk_net;
+	net = sock_net(skb->sk);
 	nlh = nlmsg_hdr(skb);
 	if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
 	    nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn)))
@@ -899,7 +899,7 @@ static void nl_fib_lookup_exit(struct net *net)
 static void fib_disable_ip(struct net_device *dev, int force)
 {
 	if (fib_sync_down_dev(dev, force))
-		fib_flush(dev->nd_net);
+		fib_flush(dev_net(dev));
 	rt_cache_flush(0);
 	arp_ifdown(dev);
 }
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 8d58d85dfac6..02088deb0461 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -821,7 +821,7 @@ static struct fib_alias *fib_get_first(struct seq_file *seq)
 	struct fib_table *main_table;
 	struct fn_hash *table;
 
-	main_table = fib_get_table(iter->p.net, RT_TABLE_MAIN);
+	main_table = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN);
 	table = (struct fn_hash *)main_table->tb_data;
 
 	iter->bucket    = 0;
@@ -959,11 +959,10 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos)
 static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(fib_hash_lock)
 {
-	struct fib_iter_state *iter = seq->private;
 	void *v = NULL;
 
 	read_lock(&fib_hash_lock);
-	if (fib_get_table(iter->p.net, RT_TABLE_MAIN))
+	if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN))
 		v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
 	return v;
 }
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 19274d01afa4..1fb56876be54 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -137,7 +137,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 			       struct nlmsghdr *nlh, struct fib_rule_hdr *frh,
 			       struct nlattr **tb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int err = -EINVAL;
 	struct fib4_rule *rule4 = (struct fib4_rule *) rule;
 
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index f6cdc012eec5..9e491e70e855 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2029,9 +2029,8 @@ struct fib_table *fib_hash_table(u32 id)
 /* Depth first Trie walk iterator */
 struct fib_trie_iter {
 	struct seq_net_private p;
-	struct trie *trie_local, *trie_main;
+	struct fib_table *tb;
 	struct tnode *tnode;
-	struct trie *trie;
 	unsigned index;
 	unsigned depth;
 };
@@ -2084,31 +2083,26 @@ rescan:
 static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
 				       struct trie *t)
 {
-	struct node *n ;
+	struct node *n;
 
 	if (!t)
 		return NULL;
 
 	n = rcu_dereference(t->trie);
-
-	if (!iter)
+	if (!n)
 		return NULL;
 
-	if (n) {
-		if (IS_TNODE(n)) {
-			iter->tnode = (struct tnode *) n;
-			iter->trie = t;
-			iter->index = 0;
-			iter->depth = 1;
-		} else {
-			iter->tnode = NULL;
-			iter->trie  = t;
-			iter->index = 0;
-			iter->depth = 0;
-		}
-		return n;
+	if (IS_TNODE(n)) {
+		iter->tnode = (struct tnode *) n;
+		iter->index = 0;
+		iter->depth = 1;
+	} else {
+		iter->tnode = NULL;
+		iter->index = 0;
+		iter->depth = 0;
 	}
-	return NULL;
+
+	return n;
 }
 
 static void trie_collect_stats(struct trie *t, struct trie_stat *s)
@@ -2119,8 +2113,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s)
 	memset(s, 0, sizeof(*s));
 
 	rcu_read_lock();
-	for (n = fib_trie_get_first(&iter, t); n;
-	     n = fib_trie_get_next(&iter)) {
+	for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) {
 		if (IS_LEAF(n)) {
 			struct leaf *l = (struct leaf *)n;
 			struct leaf_info *li;
@@ -2209,36 +2202,48 @@ static void trie_show_usage(struct seq_file *seq,
 }
 #endif /*  CONFIG_IP_FIB_TRIE_STATS */
 
-static void fib_trie_show(struct seq_file *seq, const char *name,
-			  struct trie *trie)
+static void fib_table_print(struct seq_file *seq, struct fib_table *tb)
 {
-	struct trie_stat stat;
-
-	trie_collect_stats(trie, &stat);
-	seq_printf(seq, "%s:\n", name);
-	trie_show_stats(seq, &stat);
-#ifdef CONFIG_IP_FIB_TRIE_STATS
-	trie_show_usage(seq, &trie->stats);
-#endif
+	if (tb->tb_id == RT_TABLE_LOCAL)
+		seq_puts(seq, "Local:\n");
+	else if (tb->tb_id == RT_TABLE_MAIN)
+		seq_puts(seq, "Main:\n");
+	else
+		seq_printf(seq, "Id %d:\n", tb->tb_id);
 }
 
+
 static int fib_triestat_seq_show(struct seq_file *seq, void *v)
 {
 	struct net *net = (struct net *)seq->private;
-	struct fib_table *tb;
+	unsigned int h;
 
 	seq_printf(seq,
 		   "Basic info: size of leaf:"
 		   " %Zd bytes, size of tnode: %Zd bytes.\n",
 		   sizeof(struct leaf), sizeof(struct tnode));
 
-	tb = fib_get_table(net, RT_TABLE_LOCAL);
-	if (tb)
-		fib_trie_show(seq, "Local", (struct trie *) tb->tb_data);
+	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		struct hlist_node *node;
+		struct fib_table *tb;
+
+		hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+			struct trie *t = (struct trie *) tb->tb_data;
+			struct trie_stat stat;
+
+			if (!t)
+				continue;
+
+			fib_table_print(seq, tb);
 
-	tb = fib_get_table(net, RT_TABLE_MAIN);
-	if (tb)
-		fib_trie_show(seq, "Main", (struct trie *) tb->tb_data);
+			trie_collect_stats(t, &stat);
+			trie_show_stats(seq, &stat);
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+			trie_show_usage(seq, &t->stats);
+#endif
+		}
+	}
 
 	return 0;
 }
@@ -2274,67 +2279,79 @@ static const struct file_operations fib_triestat_fops = {
 	.release = fib_triestat_seq_release,
 };
 
-static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
-				      loff_t pos)
+static struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos)
 {
+	struct fib_trie_iter *iter = seq->private;
+	struct net *net = seq_file_net(seq);
 	loff_t idx = 0;
-	struct node *n;
+	unsigned int h;
 
-	for (n = fib_trie_get_first(iter, iter->trie_local);
-	     n; ++idx, n = fib_trie_get_next(iter)) {
-		if (pos == idx)
-			return n;
-	}
+	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		struct hlist_node *node;
+		struct fib_table *tb;
 
-	for (n = fib_trie_get_first(iter, iter->trie_main);
-	     n; ++idx, n = fib_trie_get_next(iter)) {
-		if (pos == idx)
-			return n;
+		hlist_for_each_entry_rcu(tb, node, head, tb_hlist) {
+			struct node *n;
+
+			for (n = fib_trie_get_first(iter,
+						    (struct trie *) tb->tb_data);
+			     n; n = fib_trie_get_next(iter))
+				if (pos == idx++) {
+					iter->tb = tb;
+					return n;
+				}
+		}
 	}
+
 	return NULL;
 }
 
 static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(RCU)
 {
-	struct fib_trie_iter *iter = seq->private;
-	struct fib_table *tb;
-
-	if (!iter->trie_local) {
-		tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL);
-		if (tb)
-			iter->trie_local = (struct trie *) tb->tb_data;
-	}
-	if (!iter->trie_main) {
-		tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
-		if (tb)
-			iter->trie_main = (struct trie *) tb->tb_data;
-	}
 	rcu_read_lock();
-	if (*pos == 0)
-		return SEQ_START_TOKEN;
-	return fib_trie_get_idx(iter, *pos - 1);
+	return fib_trie_get_idx(seq, *pos);
 }
 
 static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct fib_trie_iter *iter = seq->private;
-	void *l = v;
+	struct net *net = seq_file_net(seq);
+	struct fib_table *tb = iter->tb;
+	struct hlist_node *tb_node;
+	unsigned int h;
+	struct node *n;
 
 	++*pos;
-	if (v == SEQ_START_TOKEN)
-		return fib_trie_get_idx(iter, 0);
-
-	v = fib_trie_get_next(iter);
-	BUG_ON(v == l);
-	if (v)
-		return v;
+	/* next node in same table */
+	n = fib_trie_get_next(iter);
+	if (n)
+		return n;
 
-	/* continue scan in next trie */
-	if (iter->trie == iter->trie_local)
-		return fib_trie_get_first(iter, iter->trie_main);
+	/* walk rest of this hash chain */
+	h = tb->tb_id & (FIB_TABLE_HASHSZ - 1);
+	while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) {
+		tb = hlist_entry(tb_node, struct fib_table, tb_hlist);
+		n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
+		if (n)
+			goto found;
+	}
 
+	/* new hash chain */
+	while (++h < FIB_TABLE_HASHSZ) {
+		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
+		hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) {
+			n = fib_trie_get_first(iter, (struct trie *) tb->tb_data);
+			if (n)
+				goto found;
+		}
+	}
 	return NULL;
+
+found:
+	iter->tb = tb;
+	return n;
 }
 
 static void fib_trie_seq_stop(struct seq_file *seq, void *v)
@@ -2391,15 +2408,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
 	const struct fib_trie_iter *iter = seq->private;
 	struct node *n = v;
 
-	if (v == SEQ_START_TOKEN)
-		return 0;
-
-	if (!node_parent_rcu(n)) {
-		if (iter->trie == iter->trie_local)
-			seq_puts(seq, "<local>:\n");
-		else
-			seq_puts(seq, "<main>:\n");
-	}
+	if (!node_parent_rcu(n))
+		fib_table_print(seq, iter->tb);
 
 	if (IS_TNODE(n)) {
 		struct tnode *tn = (struct tnode *) n;
@@ -2502,7 +2512,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos)
 	struct fib_table *tb;
 
 	rcu_read_lock();
-	tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
+	tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN);
 	if (!tb)
 		return NULL;
 
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index a944e8053e28..803bc9f173a7 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -188,29 +188,6 @@ struct icmp_err icmp_err_convert[] = {
 	},
 };
 
-/* Control parameters for ECHO replies. */
-int sysctl_icmp_echo_ignore_all __read_mostly;
-int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1;
-
-/* Control parameter - ignore bogus broadcast responses? */
-int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1;
-
-/*
- * 	Configurable global rate limit.
- *
- *	ratelimit defines tokens/packet consumed for dst->rate_token bucket
- *	ratemask defines which icmp types are ratelimited by setting
- * 	it's bit position.
- *
- *	default:
- *	dest unreachable (3), source quench (4),
- *	time exceeded (11), parameter problem (12)
- */
-
-int sysctl_icmp_ratelimit __read_mostly = 1 * HZ;
-int sysctl_icmp_ratemask __read_mostly = 0x1818;
-int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly;
-
 /*
  *	ICMP control array. This specifies what to do with each ICMP.
  */
@@ -229,14 +206,16 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
  *
  *	On SMP we have one ICMP socket per-cpu.
  */
-static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
-#define icmp_socket	__get_cpu_var(__icmp_socket)
+static struct sock *icmp_sk(struct net *net)
+{
+	return net->ipv4.icmp_sk[smp_processor_id()];
+}
 
-static inline int icmp_xmit_lock(void)
+static inline int icmp_xmit_lock(struct sock *sk)
 {
 	local_bh_disable();
 
-	if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) {
+	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
 		/* This can happen if the output path signals a
 		 * dst_link_failure() for an outgoing ICMP packet.
 		 */
@@ -246,9 +225,9 @@ static inline int icmp_xmit_lock(void)
 	return 0;
 }
 
-static inline void icmp_xmit_unlock(void)
+static inline void icmp_xmit_unlock(struct sock *sk)
 {
-	spin_unlock_bh(&icmp_socket->sk->sk_lock.slock);
+	spin_unlock_bh(&sk->sk_lock.slock);
 }
 
 /*
@@ -291,7 +270,8 @@ int xrlim_allow(struct dst_entry *dst, int timeout)
 	return rc;
 }
 
-static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
+static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
+		int type, int code)
 {
 	struct dst_entry *dst = &rt->u.dst;
 	int rc = 1;
@@ -308,8 +288,8 @@ static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
 		goto out;
 
 	/* Limit if icmp type is enabled in ratemask. */
-	if ((1 << type) & sysctl_icmp_ratemask)
-		rc = xrlim_allow(dst, sysctl_icmp_ratelimit);
+	if ((1 << type) & net->ipv4.sysctl_icmp_ratemask)
+		rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit);
 out:
 	return rc;
 }
@@ -346,19 +326,21 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
 static void icmp_push_reply(struct icmp_bxm *icmp_param,
 			    struct ipcm_cookie *ipc, struct rtable *rt)
 {
+	struct sock *sk;
 	struct sk_buff *skb;
 
-	if (ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param,
+	sk = icmp_sk(dev_net(rt->u.dst.dev));
+	if (ip_append_data(sk, icmp_glue_bits, icmp_param,
 			   icmp_param->data_len+icmp_param->head_len,
 			   icmp_param->head_len,
 			   ipc, rt, MSG_DONTWAIT) < 0)
-		ip_flush_pending_frames(icmp_socket->sk);
-	else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) {
+		ip_flush_pending_frames(sk);
+	else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) {
 		struct icmphdr *icmph = icmp_hdr(skb);
 		__wsum csum = 0;
 		struct sk_buff *skb1;
 
-		skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) {
+		skb_queue_walk(&sk->sk_write_queue, skb1) {
 			csum = csum_add(csum, skb1->csum);
 		}
 		csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
@@ -366,7 +348,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
 						 icmp_param->head_len, csum);
 		icmph->checksum = csum_fold(csum);
 		skb->ip_summed = CHECKSUM_NONE;
-		ip_push_pending_frames(icmp_socket->sk);
+		ip_push_pending_frames(sk);
 	}
 }
 
@@ -376,16 +358,17 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param,
 
 static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 {
-	struct sock *sk = icmp_socket->sk;
-	struct inet_sock *inet = inet_sk(sk);
 	struct ipcm_cookie ipc;
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
+	struct net *net = dev_net(rt->u.dst.dev);
+	struct sock *sk = icmp_sk(net);
+	struct inet_sock *inet = inet_sk(sk);
 	__be32 daddr;
 
 	if (ip_options_echo(&icmp_param->replyopts, skb))
 		return;
 
-	if (icmp_xmit_lock())
+	if (icmp_xmit_lock(sk))
 		return;
 
 	icmp_param->data.icmph.checksum = 0;
@@ -405,15 +388,15 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 						.tos = RT_TOS(ip_hdr(skb)->tos) } },
 				    .proto = IPPROTO_ICMP };
 		security_skb_classify_flow(skb, &fl);
-		if (ip_route_output_key(rt->u.dst.dev->nd_net, &rt, &fl))
+		if (ip_route_output_key(net, &rt, &fl))
 			goto out_unlock;
 	}
-	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
+	if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,
 			       icmp_param->data.icmph.code))
 		icmp_push_reply(icmp_param, &ipc, rt);
 	ip_rt_put(rt);
 out_unlock:
-	icmp_xmit_unlock();
+	icmp_xmit_unlock(sk);
 }
 
 
@@ -433,15 +416,17 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	struct iphdr *iph;
 	int room;
 	struct icmp_bxm icmp_param;
-	struct rtable *rt = (struct rtable *)skb_in->dst;
+	struct rtable *rt = skb_in->rtable;
 	struct ipcm_cookie ipc;
 	__be32 saddr;
 	u8  tos;
 	struct net *net;
+	struct sock *sk;
 
 	if (!rt)
 		goto out;
-	net = rt->u.dst.dev->nd_net;
+	net = dev_net(rt->u.dst.dev);
+	sk = icmp_sk(net);
 
 	/*
 	 *	Find the original header. It is expected to be valid, of course.
@@ -505,7 +490,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 		}
 	}
 
-	if (icmp_xmit_lock())
+	if (icmp_xmit_lock(sk))
 		return;
 
 	/*
@@ -516,7 +501,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	if (!(rt->rt_flags & RTCF_LOCAL)) {
 		struct net_device *dev = NULL;
 
-		if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr)
+		if (rt->fl.iif &&
+			net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
 			dev = dev_get_by_index(net, rt->fl.iif);
 
 		if (dev) {
@@ -544,7 +530,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	icmp_param.data.icmph.checksum	 = 0;
 	icmp_param.skb	  = skb_in;
 	icmp_param.offset = skb_network_offset(skb_in);
-	inet_sk(icmp_socket->sk)->tos = tos;
+	inet_sk(sk)->tos = tos;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
 
@@ -609,7 +595,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 					     RT_TOS(tos), rt2->u.dst.dev);
 
 			dst_release(&rt2->u.dst);
-			rt2 = (struct rtable *)skb_in->dst;
+			rt2 = skb_in->rtable;
 			skb_in->dst = odst;
 		}
 
@@ -632,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
 	}
 
 route_done:
-	if (!icmpv4_xrlim_allow(rt, type, code))
+	if (!icmpv4_xrlim_allow(net, rt, type, code))
 		goto ende;
 
 	/* RFC says return as much as we can without exceeding 576 bytes. */
@@ -652,7 +638,7 @@ route_done:
 ende:
 	ip_rt_put(rt);
 out_unlock:
-	icmp_xmit_unlock();
+	icmp_xmit_unlock(sk);
 out:;
 }
 
@@ -670,7 +656,7 @@ static void icmp_unreach(struct sk_buff *skb)
 	u32 info = 0;
 	struct net *net;
 
-	net = skb->dst->dev->nd_net;
+	net = dev_net(skb->dst->dev);
 
 	/*
 	 *	Incomplete header ?
@@ -738,7 +724,7 @@ static void icmp_unreach(struct sk_buff *skb)
 	 *	get the other vendor to fix their kit.
 	 */
 
-	if (!sysctl_icmp_ignore_bogus_error_responses &&
+	if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
 	    inet_addr_type(net, iph->daddr) == RTN_BROADCAST) {
 		if (net_ratelimit())
 			printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
@@ -833,7 +819,10 @@ out_err:
 
 static void icmp_echo(struct sk_buff *skb)
 {
-	if (!sysctl_icmp_echo_ignore_all) {
+	struct net *net;
+
+	net = dev_net(skb->dst->dev);
+	if (!net->ipv4.sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
 		icmp_param.data.icmph	   = *icmp_hdr(skb);
@@ -936,7 +925,7 @@ static void icmp_address(struct sk_buff *skb)
 
 static void icmp_address_reply(struct sk_buff *skb)
 {
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct net_device *dev = skb->dev;
 	struct in_device *in_dev;
 	struct in_ifaddr *ifa;
@@ -981,7 +970,7 @@ static void icmp_discard(struct sk_buff *skb)
 int icmp_rcv(struct sk_buff *skb)
 {
 	struct icmphdr *icmph;
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 
 	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 		int nh;
@@ -1036,6 +1025,9 @@ int icmp_rcv(struct sk_buff *skb)
 	 */
 
 	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
+		struct net *net;
+
+		net = dev_net(rt->u.dst.dev);
 		/*
 		 *	RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
 		 *	  silently ignored (we let user decide with a sysctl).
@@ -1044,7 +1036,7 @@ int icmp_rcv(struct sk_buff *skb)
 		 */
 		if ((icmph->type == ICMP_ECHO ||
 		     icmph->type == ICMP_TIMESTAMP) &&
-		    sysctl_icmp_echo_ignore_broadcasts) {
+		    net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
 			goto error;
 		}
 		if (icmph->type != ICMP_ECHO &&
@@ -1139,29 +1131,46 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
 	},
 };
 
-void __init icmp_init(struct net_proto_family *ops)
+static void __net_exit icmp_sk_exit(struct net *net)
 {
-	struct inet_sock *inet;
 	int i;
 
-	for_each_possible_cpu(i) {
-		int err;
+	for_each_possible_cpu(i)
+		sk_release_kernel(net->ipv4.icmp_sk[i]);
+	kfree(net->ipv4.icmp_sk);
+	net->ipv4.icmp_sk = NULL;
+}
+
+int __net_init icmp_sk_init(struct net *net)
+{
+	int i, err;
 
-		err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP,
-				       &per_cpu(__icmp_socket, i));
+	net->ipv4.icmp_sk =
+		kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+	if (net->ipv4.icmp_sk == NULL)
+		return -ENOMEM;
 
+	for_each_possible_cpu(i) {
+		struct sock *sk;
+		struct socket *sock;
+		struct inet_sock *inet;
+
+		err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock);
 		if (err < 0)
-			panic("Failed to create the ICMP control socket.\n");
+			goto fail;
+
+		net->ipv4.icmp_sk[i] = sk = sock->sk;
+		sk_change_net(sk, net);
 
-		per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC;
+		sk->sk_allocation = GFP_ATOMIC;
 
 		/* Enough space for 2 64K ICMP packets, including
 		 * sk_buff struct overhead.
 		 */
-		per_cpu(__icmp_socket, i)->sk->sk_sndbuf =
+		sk->sk_sndbuf =
 			(2 * ((64 * 1024) + sizeof(struct sk_buff)));
 
-		inet = inet_sk(per_cpu(__icmp_socket, i)->sk);
+		inet = inet_sk(sk);
 		inet->uc_ttl = -1;
 		inet->pmtudisc = IP_PMTUDISC_DONT;
 
@@ -1169,8 +1178,49 @@ void __init icmp_init(struct net_proto_family *ops)
 		 * see it, we do not wish this socket to see incoming
 		 * packets.
 		 */
-		per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk);
+		sk->sk_prot->unhash(sk);
 	}
+
+	/* Control parameters for ECHO replies. */
+	net->ipv4.sysctl_icmp_echo_ignore_all = 0;
+	net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1;
+
+	/* Control parameter - ignore bogus broadcast responses? */
+	net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1;
+
+	/*
+	 * 	Configurable global rate limit.
+	 *
+	 *	ratelimit defines tokens/packet consumed for dst->rate_token
+	 *	bucket ratemask defines which icmp types are ratelimited by
+	 *	setting	it's bit position.
+	 *
+	 *	default:
+	 *	dest unreachable (3), source quench (4),
+	 *	time exceeded (11), parameter problem (12)
+	 */
+
+	net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;
+	net->ipv4.sysctl_icmp_ratemask = 0x1818;
+	net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0;
+
+	return 0;
+
+fail:
+	for_each_possible_cpu(i)
+		sk_release_kernel(net->ipv4.icmp_sk[i]);
+	kfree(net->ipv4.icmp_sk);
+	return err;
+}
+
+static struct pernet_operations __net_initdata icmp_sk_ops = {
+       .init = icmp_sk_init,
+       .exit = icmp_sk_exit,
+};
+
+int __init icmp_init(void)
+{
+	return register_pernet_device(&icmp_sk_ops);
 }
 
 EXPORT_SYMBOL(icmp_err_convert);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 732cd07e6071..6250f4239b61 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -130,12 +130,12 @@
  */
 
 #define IGMP_V1_SEEN(in_dev) \
-	(IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 1 || \
+	(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \
 	 IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \
 	 ((in_dev)->mr_v1_seen && \
 	  time_before(jiffies, (in_dev)->mr_v1_seen)))
 #define IGMP_V2_SEEN(in_dev) \
-	(IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 2 || \
+	(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \
 	 IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \
 	 ((in_dev)->mr_v2_seen && \
 	  time_before(jiffies, (in_dev)->mr_v2_seen)))
@@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb)
 	case IGMPV2_HOST_MEMBERSHIP_REPORT:
 	case IGMPV3_HOST_MEMBERSHIP_REPORT:
 		/* Is it our report looped back? */
-		if (((struct rtable*)skb->dst)->fl.iif == 0)
+		if (skb->rtable->fl.iif == 0)
 			break;
 		/* don't rely on MC router hearing unicast reports */
 		if (skb->pkt_type == PACKET_MULTICAST ||
@@ -1198,6 +1198,9 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
 
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	for (im=in_dev->mc_list; im; im=im->next) {
 		if (im->multiaddr == addr) {
 			im->users++;
@@ -1277,6 +1280,9 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
 
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
 		if (i->multiaddr==addr) {
 			if (--i->users == 0) {
@@ -1304,6 +1310,9 @@ void ip_mc_down(struct in_device *in_dev)
 
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	for (i=in_dev->mc_list; i; i=i->next)
 		igmp_group_dropped(i);
 
@@ -1324,6 +1333,9 @@ void ip_mc_init_dev(struct in_device *in_dev)
 {
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	in_dev->mc_tomb = NULL;
 #ifdef CONFIG_IP_MULTICAST
 	in_dev->mr_gq_running = 0;
@@ -1347,6 +1359,9 @@ void ip_mc_up(struct in_device *in_dev)
 
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
 	for (i=in_dev->mc_list; i; i=i->next)
@@ -1363,6 +1378,9 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
 
 	ASSERT_RTNL();
 
+	if (dev_net(in_dev->dev) != &init_net)
+		return;
+
 	/* Deactivate timers */
 	ip_mc_down(in_dev);
 
@@ -1744,6 +1762,9 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
 	if (!ipv4_is_multicast(addr))
 		return -EINVAL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 
 	in_dev = ip_mc_find_dev(imr);
@@ -1812,6 +1833,9 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
 	u32 ifindex;
 	int ret = -EADDRNOTAVAIL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 	in_dev = ip_mc_find_dev(imr);
 	ifindex = imr->imr_ifindex;
@@ -1857,6 +1881,9 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
 	if (!ipv4_is_multicast(addr))
 		return -EINVAL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;
@@ -1990,6 +2017,9 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
 	    msf->imsf_fmode != MCAST_EXCLUDE)
 		return -EINVAL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
@@ -2070,6 +2100,9 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
 	if (!ipv4_is_multicast(addr))
 		return -EINVAL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 
 	imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
@@ -2132,6 +2165,9 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
 	if (!ipv4_is_multicast(addr))
 		return -EINVAL;
 
+	if (sock_net(sk) != &init_net)
+		return -EPROTONOSUPPORT;
+
 	rtnl_lock();
 
 	err = -EADDRNOTAVAIL;
@@ -2216,6 +2252,9 @@ void ip_mc_drop_socket(struct sock *sk)
 	if (inet->mc_list == NULL)
 		return;
 
+	if (sock_net(sk) != &init_net)
+		return;
+
 	rtnl_lock();
 	while ((iml = inet->mc_list) != NULL) {
 		struct in_device *in_dev;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index b189278c7bc1..a7fcaf205644 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -80,12 +80,12 @@ EXPORT_SYMBOL_GPL(inet_csk_bind_conflict);
  */
 int inet_csk_get_port(struct sock *sk, unsigned short snum)
 {
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 	struct inet_bind_hashbucket *head;
 	struct hlist_node *node;
 	struct inet_bind_bucket *tb;
 	int ret;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 
 	local_bh_disable();
 	if (!snum) {
@@ -333,7 +333,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
 					 .dport = ireq->rmt_port } } };
 
 	security_req_classify_flow(req, &fl);
-	if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0)) {
+	if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) {
 		IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
 		return NULL;
 	}
@@ -414,8 +414,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
 	struct inet_connection_sock *icsk = inet_csk(parent);
 	struct request_sock_queue *queue = &icsk->icsk_accept_queue;
 	struct listen_sock *lopt = queue->listen_opt;
-	int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
-	int thresh = max_retries;
+	int thresh = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
 	unsigned long now = jiffies;
 	struct request_sock **reqp, *req;
 	int i, budget;
@@ -451,9 +450,6 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
 		}
 	}
 
-	if (queue->rskq_defer_accept)
-		max_retries = queue->rskq_defer_accept;
-
 	budget = 2 * (lopt->nr_table_entries / (timeout / interval));
 	i = lopt->clock_hand;
 
@@ -461,9 +457,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent,
 		reqp=&lopt->syn_table[i];
 		while ((req = *reqp) != NULL) {
 			if (time_after_eq(now, req->expires)) {
-				if ((req->retrans < thresh ||
-				     (inet_rsk(req)->acked && req->retrans < max_retries))
-				    && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) {
+				if (req->retrans < thresh &&
+				    !req->rsk_ops->rtx_syn_ack(parent, req)) {
 					unsigned long timeo;
 
 					if (req->retrans++ == 0)
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index a0a3c78cb5e0..4ed429bd5951 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -107,10 +107,10 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
 	if (del_timer(&fq->timer))
 		atomic_dec(&fq->refcnt);
 
-	if (!(fq->last_in & COMPLETE)) {
+	if (!(fq->last_in & INET_FRAG_COMPLETE)) {
 		fq_unlink(fq, f);
 		atomic_dec(&fq->refcnt);
-		fq->last_in |= COMPLETE;
+		fq->last_in |= INET_FRAG_COMPLETE;
 	}
 }
 
@@ -134,7 +134,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f,
 	struct sk_buff *fp;
 	struct netns_frags *nf;
 
-	BUG_TRAP(q->last_in & COMPLETE);
+	BUG_TRAP(q->last_in & INET_FRAG_COMPLETE);
 	BUG_TRAP(del_timer(&q->timer) == 0);
 
 	/* Release all fragment data. */
@@ -177,7 +177,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f)
 		read_unlock(&f->lock);
 
 		spin_lock(&q->lock);
-		if (!(q->last_in & COMPLETE))
+		if (!(q->last_in & INET_FRAG_COMPLETE))
 			inet_frag_kill(q, f);
 		spin_unlock(&q->lock);
 
@@ -209,7 +209,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
 		if (qp->net == nf && f->match(qp, arg)) {
 			atomic_inc(&qp->refcnt);
 			write_unlock(&f->lock);
-			qp_in->last_in |= COMPLETE;
+			qp_in->last_in |= INET_FRAG_COMPLETE;
 			inet_frag_put(qp_in, f);
 			return qp;
 		}
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 1aba606f6bbb..32ca2f8b581c 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -68,7 +68,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
  */
 static void __inet_put_port(struct sock *sk)
 {
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 	const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size);
 	struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
 	struct inet_bind_bucket *tb;
@@ -139,7 +139,7 @@ static struct sock *inet_lookup_listener_slow(struct net *net,
 	sk_for_each(sk, node, head) {
 		const struct inet_sock *inet = inet_sk(sk);
 
-		if (sk->sk_net == net && inet->num == hnum &&
+		if (net_eq(sock_net(sk), net) && inet->num == hnum &&
 				!ipv6_only_sock(sk)) {
 			const __be32 rcv_saddr = inet->rcv_saddr;
 			int score = sk->sk_family == PF_INET ? 1 : 0;
@@ -182,7 +182,7 @@ struct sock *__inet_lookup_listener(struct net *net,
 		if (inet->num == hnum && !sk->sk_node.next &&
 		    (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
 		    (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) &&
-		    !sk->sk_bound_dev_if && sk->sk_net == net)
+		    !sk->sk_bound_dev_if && net_eq(sock_net(sk), net))
 			goto sherry_cache;
 		sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif);
 	}
@@ -254,7 +254,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
 	struct sock *sk2;
 	const struct hlist_node *node;
 	struct inet_timewait_sock *tw;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 
 	prefetch(head->chain.first);
 	write_lock(lock);
@@ -288,7 +288,7 @@ unique:
 	sk->sk_hash = hash;
 	BUG_TRAP(sk_unhashed(sk));
 	__sk_add_node(sk, &head->chain);
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock(lock);
 
 	if (twp) {
@@ -318,7 +318,7 @@ static inline u32 inet_sk_port_offset(const struct sock *sk)
 
 void __inet_hash_nolisten(struct sock *sk)
 {
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 	struct hlist_head *list;
 	rwlock_t *lock;
 	struct inet_ehash_bucket *head;
@@ -332,14 +332,14 @@ void __inet_hash_nolisten(struct sock *sk)
 
 	write_lock(lock);
 	__sk_add_node(sk, list);
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock(lock);
 }
 EXPORT_SYMBOL_GPL(__inet_hash_nolisten);
 
 static void __inet_hash(struct sock *sk)
 {
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 	struct hlist_head *list;
 	rwlock_t *lock;
 
@@ -354,7 +354,7 @@ static void __inet_hash(struct sock *sk)
 
 	inet_listen_wlock(hashinfo);
 	__sk_add_node(sk, list);
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock(lock);
 	wake_up(&hashinfo->lhash_wait);
 }
@@ -372,7 +372,7 @@ EXPORT_SYMBOL_GPL(inet_hash);
 void inet_unhash(struct sock *sk)
 {
 	rwlock_t *lock;
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 
 	if (sk_unhashed(sk))
 		goto out;
@@ -387,7 +387,7 @@ void inet_unhash(struct sock *sk)
 	}
 
 	if (__sk_del_node_init(sk))
-		sock_prot_inuse_add(sk->sk_prot, -1);
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 	write_unlock_bh(lock);
 out:
 	if (sk->sk_state == TCP_LISTEN)
@@ -406,7 +406,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
 	struct inet_bind_hashbucket *head;
 	struct inet_bind_bucket *tb;
 	int ret;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 
 	if (!snum) {
 		int i, remaining, low, high, port;
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 876169f3a528..a74137866fbc 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -91,7 +91,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
 
 	/* Step 2: Remove SK from established hash. */
 	if (__sk_del_node_init(sk))
-		sock_prot_inuse_add(sk->sk_prot, -1);
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 
 	/* Step 3: Hash TW into TIMEWAIT chain. */
 	inet_twsk_add_node(tw, &ehead->twchain);
@@ -124,6 +124,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
 		tw->tw_hash	    = sk->sk_hash;
 		tw->tw_ipv6only	    = 0;
 		tw->tw_prot	    = sk->sk_prot_creator;
+		twsk_net_set(tw, sock_net(sk));
 		atomic_set(&tw->tw_refcnt, 1);
 		inet_twsk_dead_node_init(tw);
 		__module_get(tw->tw_prot->owner);
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index a4506c8cfef0..4813c39b438b 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -80,7 +80,7 @@ int ip_forward(struct sk_buff *skb)
 	if (!xfrm4_route_forward(skb))
 		goto drop;
 
-	rt = (struct rtable*)skb->dst;
+	rt = skb->rtable;
 
 	if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)
 		goto sr_failed;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 3b2e5adca838..02ae470fe60c 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -194,7 +194,7 @@ static void ip_expire(unsigned long arg)
 
 	spin_lock(&qp->q.lock);
 
-	if (qp->q.last_in & COMPLETE)
+	if (qp->q.last_in & INET_FRAG_COMPLETE)
 		goto out;
 
 	ipq_kill(qp);
@@ -202,10 +202,13 @@ static void ip_expire(unsigned long arg)
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
 
-	if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) {
+	if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) {
 		struct sk_buff *head = qp->q.fragments;
+		struct net *net;
+
+		net = container_of(qp->q.net, struct net, ipv4.frags);
 		/* Send an ICMP "Fragment Reassembly Timeout" message. */
-		if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) {
+		if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) {
 			icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
 			dev_put(head->dev);
 		}
@@ -298,7 +301,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	int ihl, end;
 	int err = -ENOENT;
 
-	if (qp->q.last_in & COMPLETE)
+	if (qp->q.last_in & INET_FRAG_COMPLETE)
 		goto err;
 
 	if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
@@ -324,9 +327,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 		 * or have different end, the segment is corrrupted.
 		 */
 		if (end < qp->q.len ||
-		    ((qp->q.last_in & LAST_IN) && end != qp->q.len))
+		    ((qp->q.last_in & INET_FRAG_LAST_IN) && end != qp->q.len))
 			goto err;
-		qp->q.last_in |= LAST_IN;
+		qp->q.last_in |= INET_FRAG_LAST_IN;
 		qp->q.len = end;
 	} else {
 		if (end&7) {
@@ -336,7 +339,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 		}
 		if (end > qp->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (qp->q.last_in & LAST_IN)
+			if (qp->q.last_in & INET_FRAG_LAST_IN)
 				goto err;
 			qp->q.len = end;
 		}
@@ -435,9 +438,10 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	qp->q.meat += skb->len;
 	atomic_add(skb->truesize, &qp->q.net->mem);
 	if (offset == 0)
-		qp->q.last_in |= FIRST_IN;
+		qp->q.last_in |= INET_FRAG_FIRST_IN;
 
-	if (qp->q.last_in == (FIRST_IN | LAST_IN) && qp->q.meat == qp->q.len)
+	if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
+	    qp->q.meat == qp->q.len)
 		return ip_frag_reasm(qp, prev, dev);
 
 	write_lock(&ip4_frags.lock);
@@ -568,7 +572,7 @@ int ip_defrag(struct sk_buff *skb, u32 user)
 
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
 
-	net = skb->dev ? skb->dev->nd_net : skb->dst->dev->nd_net;
+	net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev);
 	/* Start by cleaning up the memory. */
 	if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh)
 		ip_evictor(net);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index e7821ba7a9a0..50972b397a9a 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -619,7 +619,7 @@ static int ipgre_rcv(struct sk_buff *skb)
 #ifdef CONFIG_NET_IPGRE_BROADCAST
 		if (ipv4_is_multicast(iph->daddr)) {
 			/* Looped back packet, drop it! */
-			if (((struct rtable*)skb->dst)->fl.iif == 0)
+			if (skb->rtable->fl.iif == 0)
 				goto drop;
 			tunnel->stat.multicast++;
 			skb->pkt_type = PACKET_BROADCAST;
@@ -699,7 +699,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 		}
 
 		if (skb->protocol == htons(ETH_P_IP)) {
-			rt = (struct rtable*)skb->dst;
+			rt = skb->rtable;
 			if ((dst = rt->rt_gateway) == 0)
 				goto tx_error_icmp;
 		}
@@ -1190,7 +1190,7 @@ static int ipgre_close(struct net_device *dev)
 	struct ip_tunnel *t = netdev_priv(dev);
 	if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) {
 		struct in_device *in_dev;
-		in_dev = inetdev_by_index(dev->nd_net, t->mlink);
+		in_dev = inetdev_by_index(dev_net(dev), t->mlink);
 		if (in_dev) {
 			ip_mc_dec_group(in_dev, t->parms.iph.daddr);
 			in_dev_put(in_dev);
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 65631391d479..4be00959b748 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -160,6 +160,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
 	struct ip_ra_chain *ra;
 	u8 protocol = ip_hdr(skb)->protocol;
 	struct sock *last = NULL;
+	struct net_device *dev = skb->dev;
 
 	read_lock(&ip_ra_lock);
 	for (ra = ip_ra_chain; ra; ra = ra->next) {
@@ -170,7 +171,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
 		 */
 		if (sk && inet_sk(sk)->num == protocol &&
 		    (!sk->sk_bound_dev_if ||
-		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
+		     sk->sk_bound_dev_if == dev->ifindex) &&
+		    sock_net(sk) == dev_net(dev)) {
 			if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
 				if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
 					read_unlock(&ip_ra_lock);
@@ -197,6 +199,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
 
 static int ip_local_deliver_finish(struct sk_buff *skb)
 {
+	struct net *net = dev_net(skb->dev);
+
 	__skb_pull(skb, ip_hdrlen(skb));
 
 	/* Point into the IP datagram, just past the header. */
@@ -212,7 +216,8 @@ static int ip_local_deliver_finish(struct sk_buff *skb)
 		raw = raw_local_deliver(skb, protocol);
 
 		hash = protocol & (MAX_INET_PROTOS - 1);
-		if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
+		ipprot = rcu_dereference(inet_protos[hash]);
+		if (ipprot != NULL && (net == &init_net || ipprot->netns_ok)) {
 			int ret;
 
 			if (!ipprot->no_policy) {
@@ -283,13 +288,14 @@ static inline int ip_rcv_options(struct sk_buff *skb)
 	}
 
 	iph = ip_hdr(skb);
+	opt = &(IPCB(skb)->opt);
+	opt->optlen = iph->ihl*4 - sizeof(struct iphdr);
 
-	if (ip_options_compile(NULL, skb)) {
+	if (ip_options_compile(dev_net(dev), opt, skb)) {
 		IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
 		goto drop;
 	}
 
-	opt = &(IPCB(skb)->opt);
 	if (unlikely(opt->srr)) {
 		struct in_device *in_dev = in_dev_get(dev);
 		if (in_dev) {
@@ -351,7 +357,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
 	if (iph->ihl > 5 && ip_rcv_options(skb))
 		goto drop;
 
-	rt = (struct rtable*)skb->dst;
+	rt = skb->rtable;
 	if (rt->rt_type == RTN_MULTICAST)
 		IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
 	else if (rt->rt_type == RTN_BROADCAST)
@@ -372,9 +378,6 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
 	struct iphdr *iph;
 	u32 len;
 
-	if (dev->nd_net != &init_net)
-		goto drop;
-
 	/* When the interface is in promisc. mode, drop all the crap
 	 * that it receives, do not try to analyse it.
 	 */
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 4d315158fd3c..d107543d3f81 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -45,7 +45,6 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
 	memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));
 	memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);
 	opt = &(IPCB(skb)->opt);
-	opt->is_data = 0;
 
 	if (opt->srr)
 		memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);
@@ -95,8 +94,6 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
 
 	memset(dopt, 0, sizeof(struct ip_options));
 
-	dopt->is_data = 1;
-
 	sopt = &(IPCB(skb)->opt);
 
 	if (sopt->optlen == 0) {
@@ -107,10 +104,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
 	sptr = skb_network_header(skb);
 	dptr = dopt->__data;
 
-	if (skb->dst)
-		daddr = ((struct rtable*)skb->dst)->rt_spec_dst;
-	else
-		daddr = ip_hdr(skb)->daddr;
+	daddr = skb->rtable->rt_spec_dst;
 
 	if (sopt->rr) {
 		optlen  = sptr[sopt->rr+1];
@@ -151,7 +145,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
 						__be32 addr;
 
 						memcpy(&addr, sptr+soffset-1, 4);
-						if (inet_addr_type(&init_net, addr) != RTN_LOCAL) {
+						if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) {
 							dopt->ts_needtime = 1;
 							soffset += 8;
 						}
@@ -254,26 +248,22 @@ void ip_options_fragment(struct sk_buff * skb)
  * If opt == NULL, then skb->data should point to IP header.
  */
 
-int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
+int ip_options_compile(struct net *net,
+		       struct ip_options * opt, struct sk_buff * skb)
 {
 	int l;
 	unsigned char * iph;
 	unsigned char * optptr;
 	int optlen;
 	unsigned char * pp_ptr = NULL;
-	struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL;
-
-	if (!opt) {
-		opt = &(IPCB(skb)->opt);
-		iph = skb_network_header(skb);
-		opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);
-		optptr = iph + sizeof(struct iphdr);
-		opt->is_data = 0;
-	} else {
-		optptr = opt->is_data ? opt->__data :
-					(unsigned char *)&(ip_hdr(skb)[1]);
-		iph = optptr - sizeof(struct iphdr);
-	}
+	struct rtable *rt = NULL;
+
+	if (skb != NULL) {
+		rt = skb->rtable;
+		optptr = (unsigned char *)&(ip_hdr(skb)[1]);
+	} else
+		optptr = opt->__data;
+	iph = optptr - sizeof(struct iphdr);
 
 	for (l = opt->optlen; l > 0; ) {
 		switch (*optptr) {
@@ -400,7 +390,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
 					{
 						__be32 addr;
 						memcpy(&addr, &optptr[optptr[2]-1], 4);
-						if (inet_addr_type(&init_net, addr) == RTN_UNICAST)
+						if (inet_addr_type(net, addr) == RTN_UNICAST)
 							break;
 						if (skb)
 							timeptr = (__be32*)&optptr[optptr[2]+3];
@@ -517,14 +507,13 @@ static struct ip_options *ip_options_get_alloc(const int optlen)
 		       GFP_KERNEL);
 }
 
-static int ip_options_get_finish(struct ip_options **optp,
+static int ip_options_get_finish(struct net *net, struct ip_options **optp,
 				 struct ip_options *opt, int optlen)
 {
 	while (optlen & 3)
 		opt->__data[optlen++] = IPOPT_END;
 	opt->optlen = optlen;
-	opt->is_data = 1;
-	if (optlen && ip_options_compile(opt, NULL)) {
+	if (optlen && ip_options_compile(net, opt, NULL)) {
 		kfree(opt);
 		return -EINVAL;
 	}
@@ -533,7 +522,8 @@ static int ip_options_get_finish(struct ip_options **optp,
 	return 0;
 }
 
-int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen)
+int ip_options_get_from_user(struct net *net, struct ip_options **optp,
+			     unsigned char __user *data, int optlen)
 {
 	struct ip_options *opt = ip_options_get_alloc(optlen);
 
@@ -543,10 +533,11 @@ int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *dat
 		kfree(opt);
 		return -EFAULT;
 	}
-	return ip_options_get_finish(optp, opt, optlen);
+	return ip_options_get_finish(net, optp, opt, optlen);
 }
 
-int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen)
+int ip_options_get(struct net *net, struct ip_options **optp,
+		   unsigned char *data, int optlen)
 {
 	struct ip_options *opt = ip_options_get_alloc(optlen);
 
@@ -554,14 +545,14 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen)
 		return -ENOMEM;
 	if (optlen)
 		memcpy(opt->__data, data, optlen);
-	return ip_options_get_finish(optp, opt, optlen);
+	return ip_options_get_finish(net, optp, opt, optlen);
 }
 
 void ip_forward_options(struct sk_buff *skb)
 {
 	struct   ip_options * opt	= &(IPCB(skb)->opt);
 	unsigned char * optptr;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	unsigned char *raw = skb_network_header(skb);
 
 	if (opt->rr_needaddr) {
@@ -609,7 +600,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
 	__be32 nexthop;
 	struct iphdr *iph = ip_hdr(skb);
 	unsigned char *optptr = skb_network_header(skb) + opt->srr;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct rtable *rt2;
 	int err;
 
@@ -634,13 +625,13 @@ int ip_options_rcv_srr(struct sk_buff *skb)
 		}
 		memcpy(&nexthop, &optptr[srrptr-1], 4);
 
-		rt = (struct rtable*)skb->dst;
-		skb->dst = NULL;
+		rt = skb->rtable;
+		skb->rtable = NULL;
 		err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev);
-		rt2 = (struct rtable*)skb->dst;
+		rt2 = skb->rtable;
 		if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
 			ip_rt_put(rt2);
-			skb->dst = &rt->u.dst;
+			skb->rtable = rt;
 			return -EINVAL;
 		}
 		ip_rt_put(rt);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 341779e685d9..08349267ceb4 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -142,7 +142,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
 			  __be32 saddr, __be32 daddr, struct ip_options *opt)
 {
 	struct inet_sock *inet = inet_sk(sk);
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct iphdr *iph;
 
 	/* Build the IP header. */
@@ -240,7 +240,7 @@ static int ip_finish_output(struct sk_buff *skb)
 int ip_mc_output(struct sk_buff *skb)
 {
 	struct sock *sk = skb->sk;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct net_device *dev = rt->u.dst.dev;
 
 	/*
@@ -321,7 +321,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
 	/* Skip all of this if the packet is already routed,
 	 * f.e. by something like SCTP.
 	 */
-	rt = (struct rtable *) skb->dst;
+	rt = skb->rtable;
 	if (rt != NULL)
 		goto packet_routed;
 
@@ -351,7 +351,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
 			 * itself out.
 			 */
 			security_sk_classify_flow(sk, &fl);
-			if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0))
+			if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0))
 				goto no_route;
 		}
 		sk_setup_caps(sk, &rt->u.dst);
@@ -441,7 +441,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 	unsigned int mtu, hlen, left, len, ll_rs, pad;
 	int offset;
 	__be16 not_last_frag;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	int err = 0;
 
 	dev = rt->u.dst.dev;
@@ -825,7 +825,7 @@ int ip_append_data(struct sock *sk,
 		inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ?
 					    rt->u.dst.dev->mtu :
 					    dst_mtu(rt->u.dst.path);
-		inet->cork.rt = rt;
+		inet->cork.dst = &rt->u.dst;
 		inet->cork.length = 0;
 		sk->sk_sndmsg_page = NULL;
 		sk->sk_sndmsg_off = 0;
@@ -834,7 +834,7 @@ int ip_append_data(struct sock *sk,
 			transhdrlen += exthdrlen;
 		}
 	} else {
-		rt = inet->cork.rt;
+		rt = (struct rtable *)inet->cork.dst;
 		if (inet->cork.flags & IPCORK_OPT)
 			opt = inet->cork.opt;
 
@@ -1083,7 +1083,7 @@ ssize_t	ip_append_page(struct sock *sk, struct page *page,
 	if (skb_queue_empty(&sk->sk_write_queue))
 		return -EINVAL;
 
-	rt = inet->cork.rt;
+	rt = (struct rtable *)inet->cork.dst;
 	if (inet->cork.flags & IPCORK_OPT)
 		opt = inet->cork.opt;
 
@@ -1208,10 +1208,8 @@ static void ip_cork_release(struct inet_sock *inet)
 	inet->cork.flags &= ~IPCORK_OPT;
 	kfree(inet->cork.opt);
 	inet->cork.opt = NULL;
-	if (inet->cork.rt) {
-		ip_rt_put(inet->cork.rt);
-		inet->cork.rt = NULL;
-	}
+	dst_release(inet->cork.dst);
+	inet->cork.dst = NULL;
 }
 
 /*
@@ -1224,7 +1222,7 @@ int ip_push_pending_frames(struct sock *sk)
 	struct sk_buff **tail_skb;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ip_options *opt = NULL;
-	struct rtable *rt = inet->cork.rt;
+	struct rtable *rt = (struct rtable *)inet->cork.dst;
 	struct iphdr *iph;
 	__be16 df = 0;
 	__u8 ttl;
@@ -1357,7 +1355,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 	} replyopts;
 	struct ipcm_cookie ipc;
 	__be32 daddr;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 
 	if (ip_options_echo(&replyopts.opt, skb))
 		return;
@@ -1384,7 +1382,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
 						 .dport = tcp_hdr(skb)->source } },
 				    .proto = sk->sk_protocol };
 		security_skb_classify_flow(skb, &fl);
-		if (ip_route_output_key(sk->sk_net, &rt, &fl))
+		if (ip_route_output_key(sock_net(sk), &rt, &fl))
 			return;
 	}
 
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index f72457b4b0a7..d6e76f5229cc 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -57,7 +57,7 @@
 static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 {
 	struct in_pktinfo info;
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 
 	info.ipi_addr.s_addr = ip_hdr(skb)->daddr;
 	if (rt) {
@@ -163,7 +163,7 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 		ip_cmsg_recv_security(msg, skb);
 }
 
-int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
+int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
 {
 	int err;
 	struct cmsghdr *cmsg;
@@ -176,7 +176,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
 		switch (cmsg->cmsg_type) {
 		case IP_RETOPTS:
 			err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr));
-			err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40);
+			err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40);
 			if (err)
 				return err;
 			break;
@@ -449,7 +449,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 		struct ip_options * opt = NULL;
 		if (optlen > 40 || optlen < 0)
 			goto e_inval;
-		err = ip_options_get_from_user(&opt, optval, optlen);
+		err = ip_options_get_from_user(sock_net(sk), &opt,
+					       optval, optlen);
 		if (err)
 			break;
 		if (inet->is_icsk) {
@@ -589,13 +590,13 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 				err = 0;
 				break;
 			}
-			dev = ip_dev_find(&init_net, mreq.imr_address.s_addr);
+			dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr);
 			if (dev) {
 				mreq.imr_ifindex = dev->ifindex;
 				dev_put(dev);
 			}
 		} else
-			dev = __dev_get_by_index(&init_net, mreq.imr_ifindex);
+			dev = __dev_get_by_index(sock_net(sk), mreq.imr_ifindex);
 
 
 		err = -EADDRNOTAVAIL;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 7c992fbbc2c3..08e8fb60d315 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -292,7 +292,7 @@ static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg)
 
 	mm_segment_t oldfs = get_fs();
 	set_fs(get_ds());
-	res = devinet_ioctl(cmd, (struct ifreq __user *) arg);
+	res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg);
 	set_fs(oldfs);
 	return res;
 }
@@ -434,7 +434,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 	unsigned char *sha, *tha;		/* s for "source", t for "target" */
 	struct ic_device *d;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
@@ -460,10 +460,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 	if (rarp->ar_pro != htons(ETH_P_IP))
 		goto drop;
 
-	if (!pskb_may_pull(skb,
-			   sizeof(struct arphdr) +
-			   (2 * dev->addr_len) +
-			   (2 * 4)))
+	if (!pskb_may_pull(skb, arp_hdr_len(dev)))
 		goto drop;
 
 	/* OK, it is all there and looks valid, process... */
@@ -857,7 +854,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str
 	struct ic_device *d;
 	int len, ext_len;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	/* Perform verifications before taking the lock.  */
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index dbaed69de06a..894bce96284a 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -528,7 +528,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
 	if (!dst) {
 		/* NBMA tunnel */
-		if ((rt = (struct rtable*)skb->dst) == NULL) {
+		if ((rt = skb->rtable) == NULL) {
 			tunnel->stat.tx_fifo_errors++;
 			goto tx_error;
 		}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index a94f52c207a7..11700a4dcd95 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -849,7 +849,7 @@ static void mrtsock_destruct(struct sock *sk)
 {
 	rtnl_lock();
 	if (sk == mroute_socket) {
-		IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)--;
+		IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)--;
 
 		write_lock_bh(&mrt_lock);
 		mroute_socket=NULL;
@@ -898,7 +898,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt
 			mroute_socket=sk;
 			write_unlock_bh(&mrt_lock);
 
-			IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)++;
+			IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++;
 		}
 		rtnl_unlock();
 		return ret;
@@ -1089,7 +1089,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
 	struct vif_device *v;
 	int ct;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event != NETDEV_UNREGISTER)
@@ -1283,7 +1283,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local
 	if (vif_table[vif].dev != skb->dev) {
 		int true_vifi;
 
-		if (((struct rtable*)skb->dst)->fl.iif == 0) {
+		if (skb->rtable->fl.iif == 0) {
 			/* It is our own packet, looped back.
 			   Very complicated situation...
 
@@ -1357,7 +1357,7 @@ dont_forward:
 int ip_mr_input(struct sk_buff *skb)
 {
 	struct mfc_cache *cache;
-	int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL;
+	int local = skb->rtable->rt_flags&RTCF_LOCAL;
 
 	/* Packet is looped back after forward, it should not be
 	   forwarded second time, but still can be delivered locally.
@@ -1594,7 +1594,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
 {
 	int err;
 	struct mfc_cache *cache;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 
 	read_lock(&mrt_lock);
 	cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 12dc0d640b6d..620e40ff79a9 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -550,7 +550,7 @@ tcp_app_conn_bind(struct ip_vs_conn *cp)
 
 			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
 				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __FUNCTION__,
+				  __func__,
 				  NIPQUAD(cp->caddr), ntohs(cp->cport),
 				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
 				  inc->name, ntohs(inc->port));
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 1fa7b330b9ac..1caa2908373f 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -344,7 +344,7 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp)
 
 			IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->"
 				  "%u.%u.%u.%u:%u to app %s on port %u\n",
-				  __FUNCTION__,
+				  __func__,
 				  NIPQUAD(cp->caddr), ntohs(cp->cport),
 				  NIPQUAD(cp->vaddr), ntohs(cp->vport),
 				  inc->name, ntohs(inc->port));
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 948378d0a755..69c56663cc9a 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -916,7 +916,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
 	if (!tinfo)
 		return -ENOMEM;
 
-	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current));
+	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
 	IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %Zd bytes\n",
 		  sizeof(struct ip_vs_sync_conn));
 
@@ -956,7 +956,7 @@ int stop_sync_thread(int state)
 	    (state == IP_VS_STATE_BACKUP && !sync_backup_pid))
 		return -ESRCH;
 
-	IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current));
+	IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current));
 	IP_VS_INFO("stopping sync thread %d ...\n",
 		   (state == IP_VS_STATE_MASTER) ?
 		   sync_master_pid : sync_backup_pid);
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index a7591ce344d2..1563f29b5117 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -52,7 +52,7 @@ MODULE_DESCRIPTION("arptables core");
 do {								\
 	if (!(x))						\
 		printk("ARP_NF_ASSERT: %s:%s:%u\n",		\
-		       __FUNCTION__, __FILE__, __LINE__);	\
+		       __func__, __FILE__, __LINE__);	\
 } while(0)
 #else
 #define ARP_NF_ASSERT(x)
@@ -233,10 +233,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
 	void *table_base;
 	struct xt_table_info *private;
 
-	/* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
-	if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
-				 (2 * skb->dev->addr_len) +
-				 (2 * sizeof(u32)))))
+	if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
 		return NF_DROP;
 
 	indev = in ? in->name : nulldevname;
@@ -1499,11 +1496,11 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user,
 
 	switch (cmd) {
 	case ARPT_SO_SET_REPLACE:
-		ret = compat_do_replace(sk->sk_net, user, len);
+		ret = compat_do_replace(sock_net(sk), user, len);
 		break;
 
 	case ARPT_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 1);
+		ret = do_add_counters(sock_net(sk), user, len, 1);
 		break;
 
 	default:
@@ -1647,10 +1644,10 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user,
 
 	switch (cmd) {
 	case ARPT_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 1);
+		ret = get_info(sock_net(sk), user, len, 1);
 		break;
 	case ARPT_SO_GET_ENTRIES:
-		ret = compat_get_entries(sk->sk_net, user, len);
+		ret = compat_get_entries(sock_net(sk), user, len);
 		break;
 	default:
 		ret = do_arpt_get_ctl(sk, cmd, user, len);
@@ -1668,11 +1665,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned
 
 	switch (cmd) {
 	case ARPT_SO_SET_REPLACE:
-		ret = do_replace(sk->sk_net, user, len);
+		ret = do_replace(sock_net(sk), user, len);
 		break;
 
 	case ARPT_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 0);
+		ret = do_add_counters(sock_net(sk), user, len, 0);
 		break;
 
 	default:
@@ -1692,11 +1689,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
 
 	switch (cmd) {
 	case ARPT_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 0);
+		ret = get_info(sock_net(sk), user, len, 0);
 		break;
 
 	case ARPT_SO_GET_ENTRIES:
-		ret = get_entries(sk->sk_net, user, len);
+		ret = get_entries(sock_net(sk), user, len);
 		break;
 
 	case ARPT_SO_GET_REVISION_TARGET: {
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 4dc162894cb2..719be29f7506 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -481,7 +481,7 @@ ipq_rcv_dev_event(struct notifier_block *this,
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* Drop any packets associated with the downed device */
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 600737f122d2..a819d191e1aa 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -53,7 +53,7 @@ MODULE_DESCRIPTION("IPv4 packet filter");
 do {								\
 	if (!(x))						\
 		printk("IP_NF_ASSERT: %s:%s:%u\n",		\
-		       __FUNCTION__, __FILE__, __LINE__);	\
+		       __func__, __FILE__, __LINE__);	\
 } while(0)
 #else
 #define IP_NF_ASSERT(x)
@@ -1852,11 +1852,11 @@ compat_do_ipt_set_ctl(struct sock *sk,	int cmd, void __user *user,
 
 	switch (cmd) {
 	case IPT_SO_SET_REPLACE:
-		ret = compat_do_replace(sk->sk_net, user, len);
+		ret = compat_do_replace(sock_net(sk), user, len);
 		break;
 
 	case IPT_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 1);
+		ret = do_add_counters(sock_net(sk), user, len, 1);
 		break;
 
 	default:
@@ -1963,10 +1963,10 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
 	switch (cmd) {
 	case IPT_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 1);
+		ret = get_info(sock_net(sk), user, len, 1);
 		break;
 	case IPT_SO_GET_ENTRIES:
-		ret = compat_get_entries(sk->sk_net, user, len);
+		ret = compat_get_entries(sock_net(sk), user, len);
 		break;
 	default:
 		ret = do_ipt_get_ctl(sk, cmd, user, len);
@@ -1985,11 +1985,11 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
 	switch (cmd) {
 	case IPT_SO_SET_REPLACE:
-		ret = do_replace(sk->sk_net, user, len);
+		ret = do_replace(sock_net(sk), user, len);
 		break;
 
 	case IPT_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 0);
+		ret = do_add_counters(sock_net(sk), user, len, 0);
 		break;
 
 	default:
@@ -2010,11 +2010,11 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
 	switch (cmd) {
 	case IPT_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 0);
+		ret = get_info(sock_net(sk), user, len, 0);
 		break;
 
 	case IPT_SO_GET_ENTRIES:
-		ret = get_entries(sk->sk_net, user, len);
+		ret = get_entries(sock_net(sk), user, len);
 		break;
 
 	case IPT_SO_GET_REVISION_MATCH:
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 52926c8e3cc1..965b08a7d738 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -331,7 +331,7 @@ clusterip_tg(struct sk_buff *skb, const struct net_device *in,
 	}
 
 #ifdef DEBUG
-	DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+	NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
 #endif
 	pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
 	if (!clusterip_responsible(cipinfo->config, hash)) {
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index d80fee8327e4..84c26dd27d81 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -77,7 +77,7 @@ masquerade_tg(struct sk_buff *skb, const struct net_device *in,
 		return NF_ACCEPT;
 
 	mr = targinfo;
-	rt = (struct rtable *)skb->dst;
+	rt = skb->rtable;
 	newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE);
 	if (!newsrc) {
 		printk("MASQUERADE: %s ate my IP address\n", out->name);
@@ -120,7 +120,7 @@ static int masq_device_event(struct notifier_block *this,
 {
 	const struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event == NETDEV_DOWN) {
@@ -139,18 +139,8 @@ static int masq_inet_event(struct notifier_block *this,
 			   unsigned long event,
 			   void *ptr)
 {
-	const struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
-
-	if (event == NETDEV_DOWN) {
-		/* IP address was deleted.  Search entire table for
-		   conntracks which were associated with that device,
-		   and forget them. */
-		NF_CT_ASSERT(dev->ifindex != 0);
-
-		nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex);
-	}
-
-	return NOTIFY_DONE;
+	struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+	return masq_device_event(this, event, dev);
 }
 
 static struct notifier_block masq_dev_notifier = {
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index f500b0fdaef4..e60b885d2dcd 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -379,7 +379,7 @@ static const struct file_operations ct_cpu_seq_fops = {
 	.open    = ct_cpu_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release,
 };
 
 int __init nf_conntrack_ipv4_compat_init(void)
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index ca57f47bbd25..2fca727aa8ba 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -139,7 +139,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb,
 			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct iphdr *iph;
 	struct tcphdr *tcph;
 	int oldlen, datalen;
@@ -217,7 +217,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
 			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct iphdr *iph;
 	struct udphdr *udph;
 	int datalen, oldlen;
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b4c8d4968bb2..4334d5cabc5b 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -2,6 +2,8 @@
  *
  * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
  * based on RR's ip_nat_ftp.c and other modules.
+ * (C) 2007 United Security Providers
+ * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
  *
  * 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
@@ -26,275 +28,461 @@ MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
 MODULE_DESCRIPTION("SIP NAT helper");
 MODULE_ALIAS("ip_nat_sip");
 
-struct addr_map {
-	struct {
-		char		src[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
-		char		dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
-		unsigned int	srclen, srciplen;
-		unsigned int	dstlen, dstiplen;
-	} addr[IP_CT_DIR_MAX];
-};
 
-static void addr_map_init(const struct nf_conn *ct, struct addr_map *map)
+static unsigned int mangle_packet(struct sk_buff *skb,
+				  const char **dptr, unsigned int *datalen,
+				  unsigned int matchoff, unsigned int matchlen,
+				  const char *buffer, unsigned int buflen)
 {
-	const struct nf_conntrack_tuple *t;
-	enum ip_conntrack_dir dir;
-	unsigned int n;
-
-	for (dir = 0; dir < IP_CT_DIR_MAX; dir++) {
-		t = &ct->tuplehash[dir].tuple;
-
-		n = sprintf(map->addr[dir].src, "%u.%u.%u.%u",
-			    NIPQUAD(t->src.u3.ip));
-		map->addr[dir].srciplen = n;
-		n += sprintf(map->addr[dir].src + n, ":%u",
-			     ntohs(t->src.u.udp.port));
-		map->addr[dir].srclen = n;
-
-		n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u",
-			    NIPQUAD(t->dst.u3.ip));
-		map->addr[dir].dstiplen = n;
-		n += sprintf(map->addr[dir].dst + n, ":%u",
-			     ntohs(t->dst.u.udp.port));
-		map->addr[dir].dstlen = n;
-	}
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen,
+				      buffer, buflen))
+		return 0;
+
+	/* Reload data pointer and adjust datalen value */
+	*dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
+	*datalen += buflen - matchlen;
+	return 1;
 }
 
-static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
-			struct nf_conn *ct, const char **dptr, size_t dlen,
-			enum sip_header_pos pos, struct addr_map *map)
+static int map_addr(struct sk_buff *skb,
+		    const char **dptr, unsigned int *datalen,
+		    unsigned int matchoff, unsigned int matchlen,
+		    union nf_inet_addr *addr, __be16 port)
 {
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	unsigned int matchlen, matchoff, addrlen;
-	char *addr;
-
-	if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
+	char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+	unsigned int buflen;
+	__be32 newaddr;
+	__be16 newport;
+
+	if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip &&
+	    ct->tuplehash[dir].tuple.src.u.udp.port == port) {
+		newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
+		newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
+	} else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
+		   ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
+		newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
+		newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
+	} else
 		return 1;
 
-	if ((matchlen == map->addr[dir].srciplen ||
-	     matchlen == map->addr[dir].srclen) &&
-	    memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
-		addr    = map->addr[!dir].dst;
-		addrlen = map->addr[!dir].dstlen;
-	} else if ((matchlen == map->addr[dir].dstiplen ||
-		    matchlen == map->addr[dir].dstlen) &&
-		   memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
-		addr    = map->addr[!dir].src;
-		addrlen = map->addr[!dir].srclen;
-	} else
+	if (newaddr == addr->ip && newport == port)
 		return 1;
 
-	if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
-				      matchoff, matchlen, addr, addrlen))
-		return 0;
-	*dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
-	return 1;
+	buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
+			 NIPQUAD(newaddr), ntohs(newport));
 
+	return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+			     buffer, buflen);
 }
 
-static unsigned int ip_nat_sip(struct sk_buff *skb,
-			       enum ip_conntrack_info ctinfo,
-			       struct nf_conn *ct,
-			       const char **dptr)
+static int map_sip_addr(struct sk_buff *skb,
+			const char **dptr, unsigned int *datalen,
+			enum sip_header_types type)
 {
-	enum sip_header_pos pos;
-	struct addr_map map;
-	int dataoff, datalen;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	unsigned int matchlen, matchoff;
+	union nf_inet_addr addr;
+	__be16 port;
 
-	dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
-	datalen = skb->len - dataoff;
-	if (datalen < sizeof("SIP/2.0") - 1)
-		return NF_ACCEPT;
+	if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
+				    &matchoff, &matchlen, &addr, &port) <= 0)
+		return 1;
+	return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port);
+}
 
-	addr_map_init(ct, &map);
+static unsigned int ip_nat_sip(struct sk_buff *skb,
+			       const char **dptr, unsigned int *datalen)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	unsigned int dataoff, matchoff, matchlen;
+	union nf_inet_addr addr;
+	__be16 port;
+	int request, in_header;
 
 	/* Basic rules: requests and responses. */
-	if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) {
-		/* 10.2: Constructing the REGISTER Request:
-		 *
-		 * The "userinfo" and "@" components of the SIP URI MUST NOT
-		 * be present.
-		 */
-		if (datalen >= sizeof("REGISTER") - 1 &&
-		    strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0)
-			pos = POS_REG_REQ_URI;
-		else
-			pos = POS_REQ_URI;
-
-		if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map))
+	if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
+		if (ct_sip_parse_request(ct, *dptr, *datalen,
+					 &matchoff, &matchlen,
+					 &addr, &port) > 0 &&
+		    !map_addr(skb, dptr, datalen, matchoff, matchlen,
+			      &addr, port))
+			return NF_DROP;
+		request = 1;
+	} else
+		request = 0;
+
+	/* Translate topmost Via header and parameters */
+	if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+				    SIP_HDR_VIA, NULL, &matchoff, &matchlen,
+				    &addr, &port) > 0) {
+		unsigned int matchend, poff, plen, buflen, n;
+		char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+
+		/* We're only interested in headers related to this
+		 * connection */
+		if (request) {
+			if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
+			    port != ct->tuplehash[dir].tuple.src.u.udp.port)
+				goto next;
+		} else {
+			if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
+			    port != ct->tuplehash[dir].tuple.dst.u.udp.port)
+				goto next;
+		}
+
+		if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
+			      &addr, port))
 			return NF_DROP;
+
+		matchend = matchoff + matchlen;
+
+		/* The maddr= parameter (RFC 2361) specifies where to send
+		 * the reply. */
+		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
+					       "maddr=", &poff, &plen,
+					       &addr) > 0 &&
+		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
+		    addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
+			__be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+			buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+			if (!mangle_packet(skb, dptr, datalen, poff, plen,
+					   buffer, buflen))
+				return NF_DROP;
+		}
+
+		/* The received= parameter (RFC 2361) contains the address
+		 * from which the server received the request. */
+		if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
+					       "received=", &poff, &plen,
+					       &addr) > 0 &&
+		    addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
+		    addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
+			__be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip;
+			buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
+			if (!mangle_packet(skb, dptr, datalen, poff, plen,
+					   buffer, buflen))
+				return NF_DROP;
+		}
+
+		/* The rport= parameter (RFC 3581) contains the port number
+		 * from which the server received the request. */
+		if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
+						 "rport=", &poff, &plen,
+						 &n) > 0 &&
+		    htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
+		    htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
+			__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
+			buflen = sprintf(buffer, "%u", ntohs(p));
+			if (!mangle_packet(skb, dptr, datalen, poff, plen,
+					   buffer, buflen))
+				return NF_DROP;
+		}
 	}
 
-	if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
-	    !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
-	    !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
-	    !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
+next:
+	/* Translate Contact headers */
+	dataoff = 0;
+	in_header = 0;
+	while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
+				       SIP_HDR_CONTACT, &in_header,
+				       &matchoff, &matchlen,
+				       &addr, &port) > 0) {
+		if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
+			      &addr, port))
+			return NF_DROP;
+	}
+
+	if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
+	    !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO))
 		return NF_DROP;
 	return NF_ACCEPT;
 }
 
-static unsigned int mangle_sip_packet(struct sk_buff *skb,
-				      enum ip_conntrack_info ctinfo,
-				      struct nf_conn *ct,
-				      const char **dptr, size_t dlen,
-				      char *buffer, int bufflen,
-				      enum sip_header_pos pos)
+/* Handles expected signalling connections and media streams */
+static void ip_nat_sip_expected(struct nf_conn *ct,
+				struct nf_conntrack_expect *exp)
 {
-	unsigned int matchlen, matchoff;
+	struct nf_nat_range range;
 
-	if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0)
-		return 0;
+	/* This must be a fresh one. */
+	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
 
-	if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
-				      matchoff, matchlen, buffer, bufflen))
-		return 0;
+	/* For DST manip, map port here to where it's expected. */
+	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+	range.min = range.max = exp->saved_proto;
+	range.min_ip = range.max_ip = exp->saved_ip;
+	nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
 
-	/* We need to reload this. Thanks Patrick. */
-	*dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
-	return 1;
+	/* Change src to where master sends to, but only if the connection
+	 * actually came from the same source. */
+	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
+	    ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
+		range.flags = IP_NAT_RANGE_MAP_IPS;
+		range.min_ip = range.max_ip
+			= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+		nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
+	}
 }
 
-static int mangle_content_len(struct sk_buff *skb,
-			      enum ip_conntrack_info ctinfo,
-			      struct nf_conn *ct,
-			      const char *dptr)
+static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
+				      const char **dptr, unsigned int *datalen,
+				      struct nf_conntrack_expect *exp,
+				      unsigned int matchoff,
+				      unsigned int matchlen)
 {
-	unsigned int dataoff, matchoff, matchlen;
-	char buffer[sizeof("65536")];
-	int bufflen;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	__be32 newip;
+	u_int16_t port;
+	char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
+	unsigned buflen;
 
-	dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
+	/* Connection will come from reply */
+	if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
+		newip = exp->tuple.dst.u3.ip;
+	else
+		newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
 
-	/* Get actual SDP length */
-	if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
-			    &matchlen, POS_SDP_HEADER) > 0) {
+	/* If the signalling port matches the connection's source port in the
+	 * original direction, try to use the destination port in the opposite
+	 * direction. */
+	if (exp->tuple.dst.u.udp.port ==
+	    ct->tuplehash[dir].tuple.src.u.udp.port)
+		port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
+	else
+		port = ntohs(exp->tuple.dst.u.udp.port);
+
+	exp->saved_ip = exp->tuple.dst.u3.ip;
+	exp->tuple.dst.u3.ip = newip;
+	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
+	exp->dir = !dir;
+	exp->expectfn = ip_nat_sip_expected;
 
-		/* since ct_sip_get_info() give us a pointer passing 'v='
-		   we need to add 2 bytes in this count. */
-		int c_len = skb->len - dataoff - matchoff + 2;
+	for (; port != 0; port++) {
+		exp->tuple.dst.u.udp.port = htons(port);
+		if (nf_ct_expect_related(exp) == 0)
+			break;
+	}
 
-		/* Now, update SDP length */
-		if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff,
-				    &matchlen, POS_CONTENT) > 0) {
+	if (port == 0)
+		return NF_DROP;
 
-			bufflen = sprintf(buffer, "%u", c_len);
-			return nf_nat_mangle_udp_packet(skb, ct, ctinfo,
-							matchoff, matchlen,
-							buffer, bufflen);
-		}
+	if (exp->tuple.dst.u3.ip != exp->saved_ip ||
+	    exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
+		buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
+				 NIPQUAD(newip), port);
+		if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+				   buffer, buflen))
+			goto err;
 	}
-	return 0;
+	return NF_ACCEPT;
+
+err:
+	nf_ct_unexpect_related(exp);
+	return NF_DROP;
 }
 
-static unsigned int mangle_sdp(struct sk_buff *skb,
-			       enum ip_conntrack_info ctinfo,
-			       struct nf_conn *ct,
-			       __be32 newip, u_int16_t port,
-			       const char *dptr)
+static int mangle_content_len(struct sk_buff *skb,
+			      const char **dptr, unsigned int *datalen)
 {
-	char buffer[sizeof("nnn.nnn.nnn.nnn")];
-	unsigned int dataoff, bufflen;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	unsigned int matchoff, matchlen;
+	char buffer[sizeof("65536")];
+	int buflen, c_len;
 
-	dataoff = ip_hdrlen(skb) + sizeof(struct udphdr);
+	/* Get actual SDP length */
+	if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+				  SDP_HDR_VERSION, SDP_HDR_UNSPEC,
+				  &matchoff, &matchlen) <= 0)
+		return 0;
+	c_len = *datalen - matchoff + strlen("v=");
 
-	/* Mangle owner and contact info. */
-	bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
-	if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
-			       buffer, bufflen, POS_OWNER_IP4))
+	/* Now, update SDP length */
+	if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
+			      &matchoff, &matchlen) <= 0)
 		return 0;
 
-	if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
-			       buffer, bufflen, POS_CONNECTION_IP4))
+	buflen = sprintf(buffer, "%u", c_len);
+	return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+			     buffer, buflen);
+}
+
+static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
+				  unsigned int dataoff, unsigned int *datalen,
+				  enum sdp_header_types type,
+				  enum sdp_header_types term,
+				  char *buffer, int buflen)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	unsigned int matchlen, matchoff;
+
+	if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term,
+				  &matchoff, &matchlen) <= 0)
 		return 0;
+	return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+			     buffer, buflen);
+}
 
-	/* Mangle media port. */
-	bufflen = sprintf(buffer, "%u", port);
-	if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff,
-			       buffer, bufflen, POS_MEDIA))
+static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
+				    unsigned int dataoff,
+				    unsigned int *datalen,
+				    enum sdp_header_types type,
+				    enum sdp_header_types term,
+				    const union nf_inet_addr *addr)
+{
+	char buffer[sizeof("nnn.nnn.nnn.nnn")];
+	unsigned int buflen;
+
+	buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip));
+	if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
+			       buffer, buflen))
 		return 0;
 
-	return mangle_content_len(skb, ctinfo, ct, dptr);
+	return mangle_content_len(skb, dptr, datalen);
 }
 
-static void ip_nat_sdp_expect(struct nf_conn *ct,
-			      struct nf_conntrack_expect *exp)
+static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
+				    const char **dptr,
+				    unsigned int *datalen,
+				    unsigned int matchoff,
+				    unsigned int matchlen,
+				    u_int16_t port)
 {
-	struct nf_nat_range range;
+	char buffer[sizeof("nnnnn")];
+	unsigned int buflen;
 
-	/* This must be a fresh one. */
-	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+	buflen = sprintf(buffer, "%u", port);
+	if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
+			   buffer, buflen))
+		return 0;
 
-	/* Change src to where master sends to */
-	range.flags = IP_NAT_RANGE_MAP_IPS;
-	range.min_ip = range.max_ip
-		= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
-	nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
+	return mangle_content_len(skb, dptr, datalen);
+}
 
-	/* For DST manip, map port here to where it's expected. */
-	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
-	range.min = range.max = exp->saved_proto;
-	range.min_ip = range.max_ip = exp->saved_ip;
-	nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
+static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
+				       unsigned int dataoff,
+				       unsigned int *datalen,
+				       const union nf_inet_addr *addr)
+{
+	char buffer[sizeof("nnn.nnn.nnn.nnn")];
+	unsigned int buflen;
+
+	/* Mangle session description owner and contact addresses */
+	buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip));
+	if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
+			       SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
+			       buffer, buflen))
+		return 0;
+
+	if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
+			       SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
+			       buffer, buflen))
+		return 0;
+
+	return mangle_content_len(skb, dptr, datalen);
 }
 
 /* So, this packet has hit the connection tracking matching code.
    Mangle it, and change the expectation to match the new version. */
-static unsigned int ip_nat_sdp(struct sk_buff *skb,
-			       enum ip_conntrack_info ctinfo,
-			       struct nf_conntrack_expect *exp,
-			       const char *dptr)
+static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
+				     const char **dptr,
+				     unsigned int *datalen,
+				     struct nf_conntrack_expect *rtp_exp,
+				     struct nf_conntrack_expect *rtcp_exp,
+				     unsigned int mediaoff,
+				     unsigned int medialen,
+				     union nf_inet_addr *rtp_addr)
 {
-	struct nf_conn *ct = exp->master;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	__be32 newip;
 	u_int16_t port;
 
 	/* Connection will come from reply */
 	if (ct->tuplehash[dir].tuple.src.u3.ip ==
 	    ct->tuplehash[!dir].tuple.dst.u3.ip)
-		newip = exp->tuple.dst.u3.ip;
+		rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
 	else
-		newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
-
-	exp->saved_ip = exp->tuple.dst.u3.ip;
-	exp->tuple.dst.u3.ip = newip;
-	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
-	exp->dir = !dir;
-
-	/* When you see the packet, we need to NAT it the same as the
-	   this one. */
-	exp->expectfn = ip_nat_sdp_expect;
-
-	/* Try to get same port: if not, try to change it. */
-	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
-		exp->tuple.dst.u.udp.port = htons(port);
-		if (nf_ct_expect_related(exp) == 0)
+		rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+
+	rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
+	rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
+	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
+	rtp_exp->dir = !dir;
+	rtp_exp->expectfn = ip_nat_sip_expected;
+
+	rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
+	rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
+	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
+	rtcp_exp->dir = !dir;
+	rtcp_exp->expectfn = ip_nat_sip_expected;
+
+	/* Try to get same pair of ports: if not, try to change them. */
+	for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
+	     port != 0; port += 2) {
+		rtp_exp->tuple.dst.u.udp.port = htons(port);
+		if (nf_ct_expect_related(rtp_exp) != 0)
+			continue;
+		rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
+		if (nf_ct_expect_related(rtcp_exp) == 0)
 			break;
+		nf_ct_unexpect_related(rtp_exp);
 	}
 
 	if (port == 0)
-		return NF_DROP;
+		goto err1;
+
+	/* Update media port. */
+	if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
+	    !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port))
+		goto err2;
 
-	if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) {
-		nf_ct_unexpect_related(exp);
-		return NF_DROP;
-	}
 	return NF_ACCEPT;
+
+err2:
+	nf_ct_unexpect_related(rtp_exp);
+	nf_ct_unexpect_related(rtcp_exp);
+err1:
+	return NF_DROP;
 }
 
 static void __exit nf_nat_sip_fini(void)
 {
 	rcu_assign_pointer(nf_nat_sip_hook, NULL);
-	rcu_assign_pointer(nf_nat_sdp_hook, NULL);
+	rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
+	rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
+	rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
+	rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
+	rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
 	synchronize_rcu();
 }
 
 static int __init nf_nat_sip_init(void)
 {
 	BUG_ON(nf_nat_sip_hook != NULL);
-	BUG_ON(nf_nat_sdp_hook != NULL);
+	BUG_ON(nf_nat_sip_expect_hook != NULL);
+	BUG_ON(nf_nat_sdp_addr_hook != NULL);
+	BUG_ON(nf_nat_sdp_port_hook != NULL);
+	BUG_ON(nf_nat_sdp_session_hook != NULL);
+	BUG_ON(nf_nat_sdp_media_hook != NULL);
 	rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
-	rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
+	rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
+	rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
+	rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
+	rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
+	rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
 	return 0;
 }
 
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 540ce6ae887c..000e080bac5c 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -50,6 +50,7 @@
 #include <net/udp.h>
 
 #include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_nat_helper.h>
 
@@ -1267,11 +1268,15 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 	return ret;
 }
 
+static const struct nf_conntrack_expect_policy snmp_exp_policy = {
+	.max_expected	= 0,
+	.timeout	= 180,
+};
+
 static struct nf_conntrack_helper snmp_helper __read_mostly = {
-	.max_expected		= 0,
-	.timeout		= 180,
 	.me			= THIS_MODULE,
 	.help			= help,
+	.expect_policy		= &snmp_exp_policy,
 	.name			= "snmp",
 	.tuple.src.l3num	= AF_INET,
 	.tuple.src.u.udp.port	= __constant_htons(SNMP_PORT),
@@ -1279,10 +1284,9 @@ static struct nf_conntrack_helper snmp_helper __read_mostly = {
 };
 
 static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
-	.max_expected		= 0,
-	.timeout		= 180,
 	.me			= THIS_MODULE,
 	.help			= help,
+	.expect_policy		= &snmp_exp_policy,
 	.name			= "snmp_trap",
 	.tuple.src.l3num	= AF_INET,
 	.tuple.src.u.udp.port	= __constant_htons(SNMP_TRAP_PORT),
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index d63474c6b400..552169b41b16 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -51,24 +51,54 @@
  */
 static int sockstat_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = seq->private;
+
 	socket_seq_show(seq);
 	seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
-		   sock_prot_inuse_get(&tcp_prot),
+		   sock_prot_inuse_get(net, &tcp_prot),
 		   atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot),
+	seq_printf(seq, "UDP: inuse %d mem %d\n",
+		   sock_prot_inuse_get(net, &udp_prot),
 		   atomic_read(&udp_memory_allocated));
-	seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot));
-	seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot));
+	seq_printf(seq, "UDPLITE: inuse %d\n",
+		   sock_prot_inuse_get(net, &udplite_prot));
+	seq_printf(seq, "RAW: inuse %d\n",
+		   sock_prot_inuse_get(net, &raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n",
-			ip_frag_nqueues(&init_net), ip_frag_mem(&init_net));
+			ip_frag_nqueues(net), ip_frag_mem(net));
 	return 0;
 }
 
 static int sockstat_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, sockstat_seq_show, NULL);
+	int err;
+	struct net *net;
+
+	err = -ENXIO;
+	net = get_proc_net(inode);
+	if (net == NULL)
+		goto err_net;
+
+	err = single_open(file, sockstat_seq_show, net);
+	if (err < 0)
+		goto err_open;
+
+	return 0;
+
+err_open:
+	put_net(net);
+err_net:
+	return err;
+}
+
+static int sockstat_seq_release(struct inode *inode, struct file *file)
+{
+	struct net *net = ((struct seq_file *)file->private_data)->private;
+
+	put_net(net);
+	return single_release(inode, file);
 }
 
 static const struct file_operations sockstat_seq_fops = {
@@ -76,7 +106,7 @@ static const struct file_operations sockstat_seq_fops = {
 	.open	 = sockstat_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = sockstat_seq_release,
 };
 
 /* snmp items */
@@ -423,25 +453,42 @@ static const struct file_operations netstat_seq_fops = {
 	.release = single_release,
 };
 
+static __net_init int ip_proc_init_net(struct net *net)
+{
+	if (!proc_net_fops_create(net, "sockstat", S_IRUGO, &sockstat_seq_fops))
+		return -ENOMEM;
+	return 0;
+}
+
+static __net_exit void ip_proc_exit_net(struct net *net)
+{
+	proc_net_remove(net, "sockstat");
+}
+
+static __net_initdata struct pernet_operations ip_proc_ops = {
+	.init = ip_proc_init_net,
+	.exit = ip_proc_exit_net,
+};
+
 int __init ip_misc_proc_init(void)
 {
 	int rc = 0;
 
+	if (register_pernet_subsys(&ip_proc_ops))
+		goto out_pernet;
+
 	if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops))
 		goto out_netstat;
 
 	if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops))
 		goto out_snmp;
-
-	if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops))
-		goto out_sockstat;
 out:
 	return rc;
-out_sockstat:
-	proc_net_remove(&init_net, "snmp");
 out_snmp:
 	proc_net_remove(&init_net, "netstat");
 out_netstat:
+	unregister_pernet_subsys(&ip_proc_ops);
+out_pernet:
 	rc = -ENOMEM;
 	goto out;
 }
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index a3002fe65b7f..11d7f753a820 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -81,41 +81,34 @@
 #include <linux/netfilter_ipv4.h>
 
 static struct raw_hashinfo raw_v4_hashinfo = {
-	.lock = __RW_LOCK_UNLOCKED(),
+	.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
 };
 
-void raw_hash_sk(struct sock *sk, struct raw_hashinfo *h)
+void raw_hash_sk(struct sock *sk)
 {
+	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
 	struct hlist_head *head;
 
 	head = &h->ht[inet_sk(sk)->num & (RAW_HTABLE_SIZE - 1)];
 
 	write_lock_bh(&h->lock);
 	sk_add_node(sk, head);
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock_bh(&h->lock);
 }
 EXPORT_SYMBOL_GPL(raw_hash_sk);
 
-void raw_unhash_sk(struct sock *sk, struct raw_hashinfo *h)
+void raw_unhash_sk(struct sock *sk)
 {
+	struct raw_hashinfo *h = sk->sk_prot->h.raw_hash;
+
 	write_lock_bh(&h->lock);
 	if (sk_del_node_init(sk))
-		sock_prot_inuse_add(sk->sk_prot, -1);
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 	write_unlock_bh(&h->lock);
 }
 EXPORT_SYMBOL_GPL(raw_unhash_sk);
 
-static void raw_v4_hash(struct sock *sk)
-{
-	raw_hash_sk(sk, &raw_v4_hashinfo);
-}
-
-static void raw_v4_unhash(struct sock *sk)
-{
-	raw_unhash_sk(sk, &raw_v4_hashinfo);
-}
-
 static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
 		unsigned short num, __be32 raddr, __be32 laddr, int dif)
 {
@@ -124,7 +117,7 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk,
 	sk_for_each_from(sk, node) {
 		struct inet_sock *inet = inet_sk(sk);
 
-		if (sk->sk_net == net && inet->num == num 		&&
+		if (net_eq(sock_net(sk), net) && inet->num == num	&&
 		    !(inet->daddr && inet->daddr != raddr) 		&&
 		    !(inet->rcv_saddr && inet->rcv_saddr != laddr)	&&
 		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
@@ -175,7 +168,7 @@ static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
 	if (hlist_empty(head))
 		goto out;
 
-	net = skb->dev->nd_net;
+	net = dev_net(skb->dev);
 	sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol,
 			     iph->saddr, iph->daddr,
 			     skb->dev->ifindex);
@@ -283,7 +276,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info)
 	raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]);
 	if (raw_sk != NULL) {
 		iph = (struct iphdr *)skb->data;
-		net = skb->dev->nd_net;
+		net = dev_net(skb->dev);
 
 		while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol,
 						iph->daddr, iph->saddr,
@@ -506,7 +499,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 	ipc.oif = sk->sk_bound_dev_if;
 
 	if (msg->msg_controllen) {
-		err = ip_cmsg_send(msg, &ipc);
+		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
 		if (err)
 			goto out;
 		if (ipc.opt)
@@ -560,7 +553,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		}
 
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1);
+		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1);
 	}
 	if (err)
 		goto done;
@@ -627,7 +620,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
 	if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in))
 		goto out;
-	chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr);
+	chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
 	ret = -EADDRNOTAVAIL;
 	if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL &&
 	    chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST)
@@ -825,8 +818,6 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
 	}
 }
 
-DEFINE_PROTO_INUSE(raw)
-
 struct proto raw_prot = {
 	.name		   = "RAW",
 	.owner		   = THIS_MODULE,
@@ -841,14 +832,14 @@ struct proto raw_prot = {
 	.recvmsg	   = raw_recvmsg,
 	.bind		   = raw_bind,
 	.backlog_rcv	   = raw_rcv_skb,
-	.hash		   = raw_v4_hash,
-	.unhash		   = raw_v4_unhash,
+	.hash		   = raw_hash_sk,
+	.unhash		   = raw_unhash_sk,
 	.obj_size	   = sizeof(struct raw_sock),
+	.h.raw_hash	   = &raw_v4_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_raw_setsockopt,
 	.compat_getsockopt = compat_raw_getsockopt,
 #endif
-	REF_PROTO_INUSE(raw)
 };
 
 #ifdef CONFIG_PROC_FS
@@ -862,7 +853,7 @@ static struct sock *raw_get_first(struct seq_file *seq)
 		struct hlist_node *node;
 
 		sk_for_each(sk, node, &state->h->ht[state->bucket])
-			if (sk->sk_net == state->p.net)
+			if (sock_net(sk) == seq_file_net(seq))
 				goto found;
 	}
 	sk = NULL;
@@ -878,7 +869,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
 		sk = sk_next(sk);
 try_again:
 		;
-	} while (sk && sk->sk_net != state->p.net);
+	} while (sk && sock_net(sk) != seq_file_net(seq));
 
 	if (!sk && ++state->bucket < RAW_HTABLE_SIZE) {
 		sk = sk_head(&state->h->ht[state->bucket]);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 7b5e8e1d94be..230716c2dfe0 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -118,21 +118,19 @@
 #define RT_GC_TIMEOUT (300*HZ)
 
 static int ip_rt_max_size;
-static int ip_rt_gc_timeout		= RT_GC_TIMEOUT;
-static int ip_rt_gc_interval		= 60 * HZ;
-static int ip_rt_gc_min_interval	= HZ / 2;
-static int ip_rt_redirect_number	= 9;
-static int ip_rt_redirect_load		= HZ / 50;
-static int ip_rt_redirect_silence	= ((HZ / 50) << (9 + 1));
-static int ip_rt_error_cost		= HZ;
-static int ip_rt_error_burst		= 5 * HZ;
-static int ip_rt_gc_elasticity		= 8;
-static int ip_rt_mtu_expires		= 10 * 60 * HZ;
-static int ip_rt_min_pmtu		= 512 + 20 + 20;
-static int ip_rt_min_advmss		= 256;
-static int ip_rt_secret_interval	= 10 * 60 * HZ;
-
-#define RTprint(a...)	printk(KERN_DEBUG a)
+static int ip_rt_gc_timeout __read_mostly	= RT_GC_TIMEOUT;
+static int ip_rt_gc_interval __read_mostly	= 60 * HZ;
+static int ip_rt_gc_min_interval __read_mostly	= HZ / 2;
+static int ip_rt_redirect_number __read_mostly	= 9;
+static int ip_rt_redirect_load __read_mostly	= HZ / 50;
+static int ip_rt_redirect_silence __read_mostly	= ((HZ / 50) << (9 + 1));
+static int ip_rt_error_cost __read_mostly	= HZ;
+static int ip_rt_error_burst __read_mostly	= 5 * HZ;
+static int ip_rt_gc_elasticity __read_mostly	= 8;
+static int ip_rt_mtu_expires __read_mostly	= 10 * 60 * HZ;
+static int ip_rt_min_pmtu __read_mostly		= 512 + 20 + 20;
+static int ip_rt_min_advmss __read_mostly	= 256;
+static int ip_rt_secret_interval __read_mostly	= 10 * 60 * HZ;
 
 static void rt_worker_func(struct work_struct *work);
 static DECLARE_DELAYED_WORK(expires_work, rt_worker_func);
@@ -252,10 +250,10 @@ static inline void rt_hash_lock_init(void)
 }
 #endif
 
-static struct rt_hash_bucket 	*rt_hash_table;
-static unsigned			rt_hash_mask;
-static unsigned int		rt_hash_log;
-static atomic_t			rt_genid;
+static struct rt_hash_bucket 	*rt_hash_table __read_mostly;
+static unsigned			rt_hash_mask __read_mostly;
+static unsigned int		rt_hash_log  __read_mostly;
+static atomic_t			rt_genid __read_mostly;
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
 #define RT_CACHE_STAT_INC(field) \
@@ -273,19 +271,22 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
 
 #ifdef CONFIG_PROC_FS
 struct rt_cache_iter_state {
+	struct seq_net_private p;
 	int bucket;
 	int genid;
 };
 
-static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st)
+static struct rtable *rt_cache_get_first(struct seq_file *seq)
 {
+	struct rt_cache_iter_state *st = seq->private;
 	struct rtable *r = NULL;
 
 	for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) {
 		rcu_read_lock_bh();
 		r = rcu_dereference(rt_hash_table[st->bucket].chain);
 		while (r) {
-			if (r->rt_genid == st->genid)
+			if (dev_net(r->u.dst.dev) == seq_file_net(seq) &&
+			    r->rt_genid == st->genid)
 				return r;
 			r = rcu_dereference(r->u.dst.rt_next);
 		}
@@ -294,8 +295,10 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st)
 	return r;
 }
 
-static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r)
+static struct rtable *__rt_cache_get_next(struct seq_file *seq,
+					  struct rtable *r)
 {
+	struct rt_cache_iter_state *st = seq->private;
 	r = r->u.dst.rt_next;
 	while (!r) {
 		rcu_read_unlock_bh();
@@ -307,25 +310,34 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct r
 	return rcu_dereference(r);
 }
 
-static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos)
+static struct rtable *rt_cache_get_next(struct seq_file *seq,
+					struct rtable *r)
 {
-	struct rtable *r = rt_cache_get_first(st);
+	struct rt_cache_iter_state *st = seq->private;
+	while ((r = __rt_cache_get_next(seq, r)) != NULL) {
+		if (dev_net(r->u.dst.dev) != seq_file_net(seq))
+			continue;
+		if (r->rt_genid == st->genid)
+			break;
+	}
+	return r;
+}
+
+static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct rtable *r = rt_cache_get_first(seq);
 
 	if (r)
-		while (pos && (r = rt_cache_get_next(st, r))) {
-			if (r->rt_genid != st->genid)
-				continue;
+		while (pos && (r = rt_cache_get_next(seq, r)))
 			--pos;
-		}
 	return pos ? NULL : r;
 }
 
 static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct rt_cache_iter_state *st = seq->private;
-
 	if (*pos)
-		return rt_cache_get_idx(st, *pos - 1);
+		return rt_cache_get_idx(seq, *pos - 1);
 	st->genid = atomic_read(&rt_genid);
 	return SEQ_START_TOKEN;
 }
@@ -333,12 +345,11 @@ static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
 static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct rtable *r;
-	struct rt_cache_iter_state *st = seq->private;
 
 	if (v == SEQ_START_TOKEN)
-		r = rt_cache_get_first(st);
+		r = rt_cache_get_first(seq);
 	else
-		r = rt_cache_get_next(st, v);
+		r = rt_cache_get_next(seq, v);
 	++*pos;
 	return r;
 }
@@ -390,7 +401,7 @@ static const struct seq_operations rt_cache_seq_ops = {
 
 static int rt_cache_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &rt_cache_seq_ops,
+	return seq_open_net(inode, file, &rt_cache_seq_ops,
 			sizeof(struct rt_cache_iter_state));
 }
 
@@ -399,7 +410,7 @@ static const struct file_operations rt_cache_seq_fops = {
 	.open	 = rt_cache_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release_net,
 };
 
 
@@ -533,7 +544,7 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset,
 }
 #endif
 
-static __init int ip_rt_proc_init(struct net *net)
+static int __net_init ip_rt_do_proc_init(struct net *net)
 {
 	struct proc_dir_entry *pde;
 
@@ -564,8 +575,26 @@ err2:
 err1:
 	return -ENOMEM;
 }
+
+static void __net_exit ip_rt_do_proc_exit(struct net *net)
+{
+	remove_proc_entry("rt_cache", net->proc_net_stat);
+	remove_proc_entry("rt_cache", net->proc_net);
+	remove_proc_entry("rt_acct", net->proc_net);
+}
+
+static struct pernet_operations ip_rt_proc_ops __net_initdata =  {
+	.init = ip_rt_do_proc_init,
+	.exit = ip_rt_do_proc_exit,
+};
+
+static int __init ip_rt_proc_init(void)
+{
+	return register_pernet_subsys(&ip_rt_proc_ops);
+}
+
 #else
-static inline int ip_rt_proc_init(struct net *net)
+static inline int ip_rt_proc_init(void)
 {
 	return 0;
 }
@@ -652,7 +681,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
 
 static inline int compare_netns(struct rtable *rt1, struct rtable *rt2)
 {
-	return rt1->u.dst.dev->nd_net == rt2->u.dst.dev->nd_net;
+	return dev_net(rt1->u.dst.dev) == dev_net(rt2->u.dst.dev);
 }
 
 /*
@@ -1131,10 +1160,12 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 	__be32  skeys[2] = { saddr, 0 };
 	int  ikeys[2] = { dev->ifindex, 0 };
 	struct netevent_redirect netevent;
+	struct net *net;
 
 	if (!in_dev)
 		return;
 
+	net = dev_net(dev);
 	if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev)
 	    || ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw)
 	    || ipv4_is_zeronet(new_gw))
@@ -1146,7 +1177,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 		if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev))
 			goto reject_redirect;
 	} else {
-		if (inet_addr_type(&init_net, new_gw) != RTN_UNICAST)
+		if (inet_addr_type(net, new_gw) != RTN_UNICAST)
 			goto reject_redirect;
 	}
 
@@ -1164,7 +1195,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
 				    rth->fl.fl4_src != skeys[i] ||
 				    rth->fl.oif != ikeys[k] ||
 				    rth->fl.iif != 0 ||
-				    rth->rt_genid != atomic_read(&rt_genid)) {
+				    rth->rt_genid != atomic_read(&rt_genid) ||
+				    !net_eq(dev_net(rth->u.dst.dev), net)) {
 					rthp = &rth->u.dst.rt_next;
 					continue;
 				}
@@ -1256,7 +1288,7 @@ reject_redirect:
 
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 {
-	struct rtable *rt = (struct rtable*)dst;
+	struct rtable *rt = (struct rtable *)dst;
 	struct dst_entry *ret = dst;
 
 	if (rt) {
@@ -1297,7 +1329,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
 
 void ip_rt_send_redirect(struct sk_buff *skb)
 {
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct in_device *in_dev = in_dev_get(rt->u.dst.dev);
 
 	if (!in_dev)
@@ -1346,7 +1378,7 @@ out:
 
 static int ip_error(struct sk_buff *skb)
 {
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	unsigned long now;
 	int code;
 
@@ -1423,7 +1455,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
 			    rth->rt_src  == iph->saddr &&
 			    rth->fl.iif == 0 &&
 			    !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
-			    rth->u.dst.dev->nd_net == net &&
+			    net_eq(dev_net(rth->u.dst.dev), net) &&
 			    rth->rt_genid == atomic_read(&rt_genid)) {
 				unsigned short mtu = new_mtu;
 
@@ -1499,9 +1531,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 {
 	struct rtable *rt = (struct rtable *) dst;
 	struct in_device *idev = rt->idev;
-	if (dev != dev->nd_net->loopback_dev && idev && idev->dev == dev) {
+	if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) {
 		struct in_device *loopback_idev =
-			in_dev_get(dev->nd_net->loopback_dev);
+			in_dev_get(dev_net(dev)->loopback_dev);
 		if (loopback_idev) {
 			rt->idev = loopback_idev;
 			in_dev_put(idev);
@@ -1515,7 +1547,7 @@ static void ipv4_link_failure(struct sk_buff *skb)
 
 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0);
 
-	rt = (struct rtable *) skb->dst;
+	rt = skb->rtable;
 	if (rt)
 		dst_set_expires(&rt->u.dst, 0);
 }
@@ -1545,7 +1577,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
 
 	if (rt->fl.iif == 0)
 		src = rt->rt_src;
-	else if (fib_lookup(rt->u.dst.dev->nd_net, &rt->fl, &res) == 0) {
+	else if (fib_lookup(dev_net(rt->u.dst.dev), &rt->fl, &res) == 0) {
 		src = FIB_RES_PREFSRC(res);
 		fib_res_put(&res);
 	} else
@@ -1675,7 +1707,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 
 	in_dev_put(in_dev);
 	hash = rt_hash(daddr, saddr, dev->ifindex);
-	return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
+	return rt_intern_hash(hash, rth, &skb->rtable);
 
 e_nobufs:
 	in_dev_put(in_dev);
@@ -1836,7 +1868,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
 
 	/* put it into the cache */
 	hash = rt_hash(daddr, saddr, fl->iif);
-	return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+	return rt_intern_hash(hash, rth, &skb->rtable);
 }
 
 /*
@@ -1869,7 +1901,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	__be32		spec_dst;
 	int		err = -EINVAL;
 	int		free_res = 0;
-	struct net    * net = dev->nd_net;
+	struct net    * net = dev_net(dev);
 
 	/* IP on this device is disabled. */
 
@@ -1992,7 +2024,7 @@ local_input:
 	}
 	rth->rt_type	= res.type;
 	hash = rt_hash(daddr, saddr, fl.iif);
-	err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
+	err = rt_intern_hash(hash, rth, &skb->rtable);
 	goto done;
 
 no_route:
@@ -2040,7 +2072,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 	int iif = dev->ifindex;
 	struct net *net;
 
-	net = dev->nd_net;
+	net = dev_net(dev);
 	tos &= IPTOS_RT_MASK;
 	hash = rt_hash(daddr, saddr, iif);
 
@@ -2053,12 +2085,12 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 		    rth->fl.oif == 0 &&
 		    rth->fl.mark == skb->mark &&
 		    rth->fl.fl4_tos == tos &&
-		    rth->u.dst.dev->nd_net == net &&
+		    net_eq(dev_net(rth->u.dst.dev), net) &&
 		    rth->rt_genid == atomic_read(&rt_genid)) {
 			dst_use(&rth->u.dst, jiffies);
 			RT_CACHE_STAT_INC(in_hit);
 			rcu_read_unlock();
-			skb->dst = (struct dst_entry*)rth;
+			skb->rtable = rth;
 			return 0;
 		}
 		RT_CACHE_STAT_INC(in_hlist_search);
@@ -2455,7 +2487,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp,
 		    rth->fl.mark == flp->mark &&
 		    !((rth->fl.fl4_tos ^ flp->fl4_tos) &
 			    (IPTOS_RT_MASK | RTO_ONLINK)) &&
-		    rth->u.dst.dev->nd_net == net &&
+		    net_eq(dev_net(rth->u.dst.dev), net) &&
 		    rth->rt_genid == atomic_read(&rt_genid)) {
 			dst_use(&rth->u.dst, jiffies);
 			RT_CACHE_STAT_INC(out_hit);
@@ -2487,7 +2519,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
 };
 
 
-static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk)
+static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp)
 {
 	struct rtable *ort = *rp;
 	struct rtable *rt = (struct rtable *)
@@ -2547,7 +2579,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
 		err = __xfrm_lookup((struct dst_entry **)rp, flp, sk,
 				    flags ? XFRM_LOOKUP_WAIT : 0);
 		if (err == -EREMOTE)
-			err = ipv4_dst_blackhole(rp, flp, sk);
+			err = ipv4_dst_blackhole(rp, flp);
 
 		return err;
 	}
@@ -2565,7 +2597,7 @@ int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp)
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 			int nowait, unsigned int flags)
 {
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct rtmsg *r;
 	struct nlmsghdr *nlh;
 	long expires;
@@ -2658,7 +2690,7 @@ nla_put_failure:
 
 static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = in_skb->sk->sk_net;
+	struct net *net = sock_net(in_skb->sk);
 	struct rtmsg *rtm;
 	struct nlattr *tb[RTA_MAX+1];
 	struct rtable *rt = NULL;
@@ -2668,9 +2700,6 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	int err;
 	struct sk_buff *skb;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy);
 	if (err < 0)
 		goto errout;
@@ -2700,7 +2729,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	if (iif) {
 		struct net_device *dev;
 
-		dev = __dev_get_by_index(&init_net, iif);
+		dev = __dev_get_by_index(net, iif);
 		if (dev == NULL) {
 			err = -ENODEV;
 			goto errout_free;
@@ -2712,7 +2741,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 		err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev);
 		local_bh_enable();
 
-		rt = (struct rtable*) skb->dst;
+		rt = skb->rtable;
 		if (err == 0 && rt->u.dst.error)
 			err = -rt->u.dst.error;
 	} else {
@@ -2726,22 +2755,22 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 			},
 			.oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0,
 		};
-		err = ip_route_output_key(&init_net, &rt, &fl);
+		err = ip_route_output_key(net, &rt, &fl);
 	}
 
 	if (err)
 		goto errout_free;
 
-	skb->dst = &rt->u.dst;
+	skb->rtable = rt;
 	if (rtm->rtm_flags & RTM_F_NOTIFY)
 		rt->rt_flags |= RTCF_NOTIFY;
 
 	err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq,
-				RTM_NEWROUTE, 0, 0);
+			   RTM_NEWROUTE, 0, 0);
 	if (err <= 0)
 		goto errout_free;
 
-	err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
 errout:
 	return err;
 
@@ -2755,6 +2784,9 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
 	struct rtable *rt;
 	int h, s_h;
 	int idx, s_idx;
+	struct net *net;
+
+	net = sock_net(skb->sk);
 
 	s_h = cb->args[0];
 	if (s_h < 0)
@@ -2764,7 +2796,7 @@ int ip_rt_dump(struct sk_buff *skb,  struct netlink_callback *cb)
 		rcu_read_lock_bh();
 		for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt;
 		     rt = rcu_dereference(rt->u.dst.rt_next), idx++) {
-			if (idx < s_idx)
+			if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx)
 				continue;
 			if (rt->rt_genid != atomic_read(&rt_genid))
 				continue;
@@ -3040,7 +3072,7 @@ int __init ip_rt_init(void)
 		ip_rt_secret_interval;
 	add_timer(&rt_secret_timer);
 
-	if (ip_rt_proc_init(&init_net))
+	if (ip_rt_proc_init())
 		printk(KERN_ERR "Unable to create route proc files\n");
 #ifdef CONFIG_XFRM
 	xfrm_init();
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index f470fe4511db..abc752d45cf7 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -10,8 +10,6 @@
  *      2 of the License, or (at your option) any later version.
  *
  *  $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $
- *
- *  Missing: IPv6 support.
  */
 
 #include <linux/tcp.h>
@@ -23,24 +21,27 @@
 
 extern int sysctl_tcp_syncookies;
 
-static __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS];
+__u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
+EXPORT_SYMBOL(syncookie_secret);
 
 static __init int init_syncookies(void)
 {
 	get_random_bytes(syncookie_secret, sizeof(syncookie_secret));
 	return 0;
 }
-module_init(init_syncookies);
+__initcall(init_syncookies);
 
 #define COOKIEBITS 24	/* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
+static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+
 static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
 		       u32 count, int c)
 {
-	__u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS];
+	__u32 *tmp = __get_cpu_var(cookie_scratch);
 
-	memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c]));
+	memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c]));
 	tmp[0] = (__force u32)saddr;
 	tmp[1] = (__force u32)daddr;
 	tmp[2] = ((__force u32)sport << 16) + (__force u32)dport;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 88286f35d1e2..c437f804ee38 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -404,38 +404,6 @@ static struct ctl_table ipv4_table[] = {
 		.strategy	= &ipv4_sysctl_local_port_range,
 	},
 	{
-		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_ALL,
-		.procname	= "icmp_echo_ignore_all",
-		.data		= &sysctl_icmp_echo_ignore_all,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,
-		.procname	= "icmp_echo_ignore_broadcasts",
-		.data		= &sysctl_icmp_echo_ignore_broadcasts,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,
-		.procname	= "icmp_ignore_bogus_error_responses",
-		.data		= &sysctl_icmp_ignore_bogus_error_responses,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
-		.procname	= "icmp_errors_use_inbound_ifaddr",
-		.data		= &sysctl_icmp_errors_use_inbound_ifaddr,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
 		.ctl_name	= NET_IPV4_ROUTE,
 		.procname	= "route",
 		.maxlen		= 0,
@@ -586,22 +554,6 @@ static struct ctl_table ipv4_table[] = {
 		.proc_handler	= &proc_dointvec
 	},
 	{
-		.ctl_name	= NET_IPV4_ICMP_RATELIMIT,
-		.procname	= "icmp_ratelimit",
-		.data		= &sysctl_icmp_ratelimit,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
-		.ctl_name	= NET_IPV4_ICMP_RATEMASK,
-		.procname	= "icmp_ratemask",
-		.data		= &sysctl_icmp_ratemask,
-		.maxlen		= sizeof(int),
-		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
-	},
-	{
 		.ctl_name	= NET_TCP_TW_REUSE,
 		.procname	= "tcp_tw_reuse",
 		.data		= &sysctl_tcp_tw_reuse,
@@ -804,6 +756,58 @@ static struct ctl_table ipv4_table[] = {
 	{ .ctl_name = 0 }
 };
 
+static struct ctl_table ipv4_net_table[] = {
+	{
+		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_ALL,
+		.procname	= "icmp_echo_ignore_all",
+		.data		= &init_net.ipv4.sysctl_icmp_echo_ignore_all,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,
+		.procname	= "icmp_echo_ignore_broadcasts",
+		.data		= &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,
+		.procname	= "icmp_ignore_bogus_error_responses",
+		.data		= &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
+		.procname	= "icmp_errors_use_inbound_ifaddr",
+		.data		= &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_ICMP_RATELIMIT,
+		.procname	= "icmp_ratelimit",
+		.data		= &init_net.ipv4.sysctl_icmp_ratelimit,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{
+		.ctl_name	= NET_IPV4_ICMP_RATEMASK,
+		.procname	= "icmp_ratemask",
+		.data		= &init_net.ipv4.sysctl_icmp_ratemask,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
+	{ }
+};
+
 struct ctl_path net_ipv4_ctl_path[] = {
 	{ .procname = "net", .ctl_name = CTL_NET, },
 	{ .procname = "ipv4", .ctl_name = NET_IPV4, },
@@ -811,12 +815,72 @@ struct ctl_path net_ipv4_ctl_path[] = {
 };
 EXPORT_SYMBOL_GPL(net_ipv4_ctl_path);
 
+static __net_init int ipv4_sysctl_init_net(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = ipv4_net_table;
+	if (net != &init_net) {
+		table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL);
+		if (table == NULL)
+			goto err_alloc;
+
+		table[0].data =
+			&net->ipv4.sysctl_icmp_echo_ignore_all;
+		table[1].data =
+			&net->ipv4.sysctl_icmp_echo_ignore_broadcasts;
+		table[2].data =
+			&net->ipv4.sysctl_icmp_ignore_bogus_error_responses;
+		table[3].data =
+			&net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr;
+		table[4].data =
+			&net->ipv4.sysctl_icmp_ratelimit;
+		table[5].data =
+			&net->ipv4.sysctl_icmp_ratemask;
+	}
+
+	net->ipv4.ipv4_hdr = register_net_sysctl_table(net,
+			net_ipv4_ctl_path, table);
+	if (net->ipv4.ipv4_hdr == NULL)
+		goto err_reg;
+
+	return 0;
+
+err_reg:
+	if (net != &init_net)
+		kfree(table);
+err_alloc:
+	return -ENOMEM;
+}
+
+static __net_exit void ipv4_sysctl_exit_net(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = net->ipv4.ipv4_hdr->ctl_table_arg;
+	unregister_net_sysctl_table(net->ipv4.ipv4_hdr);
+	kfree(table);
+}
+
+static __net_initdata struct pernet_operations ipv4_sysctl_ops = {
+	.init = ipv4_sysctl_init_net,
+	.exit = ipv4_sysctl_exit_net,
+};
+
 static __init int sysctl_ipv4_init(void)
 {
 	struct ctl_table_header *hdr;
 
 	hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table);
-	return hdr == NULL ? -ENOMEM : 0;
+	if (hdr == NULL)
+		return -ENOMEM;
+
+	if (register_pernet_subsys(&ipv4_sysctl_ops)) {
+		unregister_sysctl_table(hdr);
+		return -ENOMEM;
+	}
+
+	return 0;
 }
 
 __initcall(sysctl_ipv4_init);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 39b629ac2404..58ac838bf460 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2105,15 +2105,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
 		break;
 
 	case TCP_DEFER_ACCEPT:
-		icsk->icsk_accept_queue.rskq_defer_accept = 0;
-		if (val > 0) {
-			/* Translate value in seconds to number of
-			 * retransmits */
-			while (icsk->icsk_accept_queue.rskq_defer_accept < 32 &&
-			       val > ((TCP_TIMEOUT_INIT / HZ) <<
-				       icsk->icsk_accept_queue.rskq_defer_accept))
-				icsk->icsk_accept_queue.rskq_defer_accept++;
-			icsk->icsk_accept_queue.rskq_defer_accept++;
+		if (val < 0) {
+			err = -EINVAL;
+		} else {
+			if (val > MAX_TCP_ACCEPT_DEFERRED)
+				val = MAX_TCP_ACCEPT_DEFERRED;
+			icsk->icsk_accept_queue.rskq_defer_accept = val;
 		}
 		break;
 
@@ -2295,8 +2292,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
 			val = (val ? : sysctl_tcp_fin_timeout) / HZ;
 		break;
 	case TCP_DEFER_ACCEPT:
-		val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 :
-			((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1));
+		val = icsk->icsk_accept_queue.rskq_defer_accept;
 		break;
 	case TCP_WINDOW_CLAMP:
 		val = tp->window_clamp;
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index 3aa0b23c1ea0..eb5b9854c8c7 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -1,12 +1,13 @@
 /*
- * TCP CUBIC: Binary Increase Congestion control for TCP v2.1
- *
+ * TCP CUBIC: Binary Increase Congestion control for TCP v2.2
+ * Home page:
+ *      http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC
  * This is from the implementation of CUBIC TCP in
  * Injong Rhee, Lisong Xu.
  *  "CUBIC: A New TCP-Friendly High-Speed TCP Variant
  *  in PFLDnet 2005
  * Available from:
- *  http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf
+ *  http://netsrv.csc.ncsu.edu/export/cubic-paper.pdf
  *
  * Unless CUBIC is enabled and congestion window is large
  * this behaves the same as the original Reno.
@@ -20,15 +21,10 @@
 #define BICTCP_BETA_SCALE    1024	/* Scale factor beta calculation
 					 * max_cwnd = snd_cwnd * beta
 					 */
-#define BICTCP_B		4	 /*
-					  * In binary search,
-					  * go to point (max+min)/N
-					  */
 #define	BICTCP_HZ		10	/* BIC HZ 2^10 = 1024 */
 
 static int fast_convergence __read_mostly = 1;
-static int max_increment __read_mostly = 16;
-static int beta __read_mostly = 819;	/* = 819/1024 (BICTCP_BETA_SCALE) */
+static int beta __read_mostly = 717;	/* = 717/1024 (BICTCP_BETA_SCALE) */
 static int initial_ssthresh __read_mostly;
 static int bic_scale __read_mostly = 41;
 static int tcp_friendliness __read_mostly = 1;
@@ -40,9 +36,7 @@ static u64 cube_factor __read_mostly;
 /* Note parameters that are used for precomputing scale factors are read-only */
 module_param(fast_convergence, int, 0644);
 MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence");
-module_param(max_increment, int, 0644);
-MODULE_PARM_DESC(max_increment, "Limit on increment allowed during binary search");
-module_param(beta, int, 0444);
+module_param(beta, int, 0644);
 MODULE_PARM_DESC(beta, "beta for multiplicative increase");
 module_param(initial_ssthresh, int, 0644);
 MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
@@ -145,7 +139,7 @@ static u32 cubic_root(u64 a)
 static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 {
 	u64 offs;
-	u32 delta, t, bic_target, min_cnt, max_cnt;
+	u32 delta, t, bic_target, max_cnt;
 
 	ca->ack_cnt++;	/* count the number of ACKs */
 
@@ -211,19 +205,6 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 		ca->cnt = 100 * cwnd;              /* very small increment*/
 	}
 
-	if (ca->delay_min > 0) {
-		/* max increment = Smax * rtt / 0.1  */
-		min_cnt = (cwnd * HZ * 8)/(10 * max_increment * ca->delay_min);
-
-		/* use concave growth when the target is above the origin */
-		if (ca->cnt < min_cnt && t >= ca->bic_K)
-			ca->cnt = min_cnt;
-	}
-
-	/* slow start and low utilization  */
-	if (ca->loss_cwnd == 0)		/* could be aggressive in slow start */
-		ca->cnt = 50;
-
 	/* TCP Friendly */
 	if (tcp_friendliness) {
 		u32 scale = beta_scale;
@@ -391,4 +372,4 @@ module_exit(cubictcp_unregister);
 MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("CUBIC TCP");
-MODULE_VERSION("2.1");
+MODULE_VERSION("2.2");
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7facdb0f6960..6e46b4c0f28c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3561,7 +3561,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
 		 * cases we should never reach this piece of code.
 		 */
 		printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n",
-		       __FUNCTION__, sk->sk_state);
+		       __func__, sk->sk_state);
 		break;
 	}
 
@@ -4451,6 +4451,49 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th)
 	}
 }
 
+static int tcp_defer_accept_check(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (tp->defer_tcp_accept.request) {
+		int queued_data =  tp->rcv_nxt - tp->copied_seq;
+		int hasfin =  !skb_queue_empty(&sk->sk_receive_queue) ?
+			tcp_hdr((struct sk_buff *)
+				sk->sk_receive_queue.prev)->fin : 0;
+
+		if (queued_data && hasfin)
+			queued_data--;
+
+		if (queued_data &&
+		    tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) {
+			if (sock_flag(sk, SOCK_KEEPOPEN)) {
+				inet_csk_reset_keepalive_timer(sk,
+							       keepalive_time_when(tp));
+			} else {
+				inet_csk_delete_keepalive_timer(sk);
+			}
+
+			inet_csk_reqsk_queue_add(
+				tp->defer_tcp_accept.listen_sk,
+				tp->defer_tcp_accept.request,
+				sk);
+
+			tp->defer_tcp_accept.listen_sk->sk_data_ready(
+				tp->defer_tcp_accept.listen_sk, 0);
+
+			sock_put(tp->defer_tcp_accept.listen_sk);
+			sock_put(sk);
+			tp->defer_tcp_accept.listen_sk = NULL;
+			tp->defer_tcp_accept.request = NULL;
+		} else if (hasfin ||
+			   tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) {
+			tcp_reset(sk);
+			return -1;
+		}
+	}
+	return 0;
+}
+
 static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen)
 {
 	struct tcp_sock *tp = tcp_sk(sk);
@@ -4811,6 +4854,9 @@ step5:
 
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
+
+	if (tcp_defer_accept_check(sk))
+		return -1;
 	return 0;
 
 csum_error:
@@ -5330,6 +5376,7 @@ discard:
 
 EXPORT_SYMBOL(sysctl_tcp_ecn);
 EXPORT_SYMBOL(sysctl_tcp_reordering);
+EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
 EXPORT_SYMBOL(tcp_parse_options);
 EXPORT_SYMBOL(tcp_rcv_established);
 EXPORT_SYMBOL(tcp_rcv_state_process);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 00156bf421ca..ef141b841d2f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -353,7 +353,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
 		return;
 	}
 
-	sk = inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->daddr, th->dest,
+	sk = inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest,
 			iph->saddr, th->source, inet_iif(skb));
 	if (!sk) {
 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
@@ -552,7 +552,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
 	if (th->rst)
 		return;
 
-	if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
+	if (skb->rtable->rt_type != RTN_LOCAL)
 		return;
 
 	/* Swap the send and the receive. */
@@ -723,8 +723,8 @@ static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
  *	This still operates on a request_sock only, not on a big
  *	socket.
  */
-static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
-			      struct dst_entry *dst)
+static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
+				struct dst_entry *dst)
 {
 	const struct inet_request_sock *ireq = inet_rsk(req);
 	int err = -1;
@@ -732,7 +732,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
 
 	/* First, grab a route. */
 	if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL)
-		goto out;
+		return -1;
 
 	skb = tcp_make_synack(sk, dst, req);
 
@@ -751,11 +751,15 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req,
 		err = net_xmit_eval(err);
 	}
 
-out:
 	dst_release(dst);
 	return err;
 }
 
+static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req)
+{
+	return __tcp_v4_send_synack(sk, req, NULL);
+}
+
 /*
  *	IPv4 request_sock destructor.
  */
@@ -1258,8 +1262,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 #endif
 
 	/* Never answer to SYNs send to broadcast or multicast */
-	if (((struct rtable *)skb->dst)->rt_flags &
-	    (RTCF_BROADCAST | RTCF_MULTICAST))
+	if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
 		goto drop;
 
 	/* TW buckets are converted to open requests without
@@ -1351,8 +1354,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 			    (s32)(peer->tcp_ts - req->ts_recent) >
 							TCP_PAWS_WINDOW) {
 				NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED);
-				dst_release(dst);
-				goto drop_and_free;
+				goto drop_and_release;
 			}
 		}
 		/* Kill the following clause, if you dislike this way. */
@@ -1372,24 +1374,21 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
 				       "request from %u.%u.%u.%u/%u\n",
 				       NIPQUAD(saddr),
 				       ntohs(tcp_hdr(skb)->source));
-			dst_release(dst);
-			goto drop_and_free;
+			goto drop_and_release;
 		}
 
 		isn = tcp_v4_init_sequence(skb);
 	}
 	tcp_rsk(req)->snt_isn = isn;
 
-	if (tcp_v4_send_synack(sk, req, dst))
+	if (__tcp_v4_send_synack(sk, req, dst) || want_cookie)
 		goto drop_and_free;
 
-	if (want_cookie) {
-		reqsk_free(req);
-	} else {
-		inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-	}
+	inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
 	return 0;
 
+drop_and_release:
+	dst_release(dst);
 drop_and_free:
 	reqsk_free(req);
 drop:
@@ -1487,7 +1486,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
-	nsk = inet_lookup_established(sk->sk_net, &tcp_hashinfo, iph->saddr,
+	nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr,
 			th->source, iph->daddr, th->dest, inet_iif(skb));
 
 	if (nsk) {
@@ -1645,7 +1644,7 @@ int tcp_v4_rcv(struct sk_buff *skb)
 	TCP_SKB_CB(skb)->flags	 = iph->tos;
 	TCP_SKB_CB(skb)->sacked	 = 0;
 
-	sk = __inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->saddr,
+	sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->saddr,
 			th->source, iph->daddr, th->dest, inet_iif(skb));
 	if (!sk)
 		goto no_tcp_socket;
@@ -1719,7 +1718,7 @@ do_time_wait:
 	}
 	switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
 	case TCP_TW_SYN: {
-		struct sock *sk2 = inet_lookup_listener(skb->dev->nd_net,
+		struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev),
 							&tcp_hashinfo,
 							iph->daddr, th->dest,
 							inet_iif(skb));
@@ -1921,6 +1920,14 @@ int tcp_v4_destroy_sock(struct sock *sk)
 		sk->sk_sndmsg_page = NULL;
 	}
 
+	if (tp->defer_tcp_accept.request) {
+		reqsk_free(tp->defer_tcp_accept.request);
+		sock_put(tp->defer_tcp_accept.listen_sk);
+		sock_put(sk);
+		tp->defer_tcp_accept.listen_sk = NULL;
+		tp->defer_tcp_accept.request = NULL;
+	}
+
 	atomic_dec(&tcp_sockets_allocated);
 
 	return 0;
@@ -1949,6 +1956,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
 	struct hlist_node *node;
 	struct sock *sk = cur;
 	struct tcp_iter_state* st = seq->private;
+	struct net *net = st->net;
 
 	if (!sk) {
 		st->bucket = 0;
@@ -1965,7 +1973,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
 		req = req->dl_next;
 		while (1) {
 			while (req) {
-				if (req->rsk_ops->family == st->family) {
+				if (req->rsk_ops->family == st->family &&
+				    net_eq(sock_net(req->sk), net)) {
 					cur = req;
 					goto out;
 				}
@@ -1989,7 +1998,7 @@ get_req:
 	}
 get_sk:
 	sk_for_each_from(sk, node) {
-		if (sk->sk_family == st->family) {
+		if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) {
 			cur = sk;
 			goto out;
 		}
@@ -2028,6 +2037,7 @@ static void *listening_get_idx(struct seq_file *seq, loff_t *pos)
 static void *established_get_first(struct seq_file *seq)
 {
 	struct tcp_iter_state* st = seq->private;
+	struct net *net = st->net;
 	void *rc = NULL;
 
 	for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
@@ -2038,7 +2048,8 @@ static void *established_get_first(struct seq_file *seq)
 
 		read_lock_bh(lock);
 		sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
-			if (sk->sk_family != st->family) {
+			if (sk->sk_family != st->family ||
+			    !net_eq(sock_net(sk), net)) {
 				continue;
 			}
 			rc = sk;
@@ -2047,7 +2058,8 @@ static void *established_get_first(struct seq_file *seq)
 		st->state = TCP_SEQ_STATE_TIME_WAIT;
 		inet_twsk_for_each(tw, node,
 				   &tcp_hashinfo.ehash[st->bucket].twchain) {
-			if (tw->tw_family != st->family) {
+			if (tw->tw_family != st->family ||
+			    !net_eq(twsk_net(tw), net)) {
 				continue;
 			}
 			rc = tw;
@@ -2066,6 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
 	struct inet_timewait_sock *tw;
 	struct hlist_node *node;
 	struct tcp_iter_state* st = seq->private;
+	struct net *net = st->net;
 
 	++st->num;
 
@@ -2073,7 +2086,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
 		tw = cur;
 		tw = tw_next(tw);
 get_tw:
-		while (tw && tw->tw_family != st->family) {
+		while (tw && (tw->tw_family != st->family || !net_eq(twsk_net(tw), net))) {
 			tw = tw_next(tw);
 		}
 		if (tw) {
@@ -2094,7 +2107,7 @@ get_tw:
 		sk = sk_next(sk);
 
 	sk_for_each_from(sk, node) {
-		if (sk->sk_family == st->family)
+		if (sk->sk_family == st->family && net_eq(sock_net(sk), net))
 			goto found;
 	}
 
@@ -2202,6 +2215,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file)
 	struct tcp_seq_afinfo *afinfo = PDE(inode)->data;
 	struct seq_file *seq;
 	struct tcp_iter_state *s;
+	struct net *net;
 	int rc;
 
 	if (unlikely(afinfo == NULL))
@@ -2210,25 +2224,44 @@ static int tcp_seq_open(struct inode *inode, struct file *file)
 	s = kzalloc(sizeof(*s), GFP_KERNEL);
 	if (!s)
 		return -ENOMEM;
+
+	rc = -ENXIO;
+	net = get_proc_net(inode);
+	if (!net)
+		goto out_kfree;
+
 	s->family		= afinfo->family;
 	s->seq_ops.start	= tcp_seq_start;
 	s->seq_ops.next		= tcp_seq_next;
 	s->seq_ops.show		= afinfo->seq_show;
 	s->seq_ops.stop		= tcp_seq_stop;
+	s->net                  = net;
 
 	rc = seq_open(file, &s->seq_ops);
 	if (rc)
-		goto out_kfree;
-	seq	     = file->private_data;
+		goto out_put_net;
+	seq = file->private_data;
 	seq->private = s;
 out:
 	return rc;
+out_put_net:
+	put_net(net);
 out_kfree:
 	kfree(s);
 	goto out;
 }
 
-int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
+static int tcp_seq_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct tcp_iter_state *s = seq->private;
+
+	put_net(s->net);
+	seq_release_private(inode, file);
+	return 0;
+}
+
+int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo)
 {
 	int rc = 0;
 	struct proc_dir_entry *p;
@@ -2239,9 +2272,9 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
 	afinfo->seq_fops->open		= tcp_seq_open;
 	afinfo->seq_fops->read		= seq_read;
 	afinfo->seq_fops->llseek	= seq_lseek;
-	afinfo->seq_fops->release	= seq_release_private;
+	afinfo->seq_fops->release	= tcp_seq_release;
 
-	p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
+	p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops);
 	if (p)
 		p->data = afinfo;
 	else
@@ -2249,11 +2282,11 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
 	return rc;
 }
 
-void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo)
+void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo)
 {
 	if (!afinfo)
 		return;
-	proc_net_remove(&init_net, afinfo->name);
+	proc_net_remove(net, afinfo->name);
 	memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
 }
 
@@ -2392,19 +2425,32 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = {
 	.seq_fops	= &tcp4_seq_fops,
 };
 
+static int tcp4_proc_init_net(struct net *net)
+{
+	return tcp_proc_register(net, &tcp4_seq_afinfo);
+}
+
+static void tcp4_proc_exit_net(struct net *net)
+{
+	tcp_proc_unregister(net, &tcp4_seq_afinfo);
+}
+
+static struct pernet_operations tcp4_net_ops = {
+	.init = tcp4_proc_init_net,
+	.exit = tcp4_proc_exit_net,
+};
+
 int __init tcp4_proc_init(void)
 {
-	return tcp_proc_register(&tcp4_seq_afinfo);
+	return register_pernet_subsys(&tcp4_net_ops);
 }
 
 void tcp4_proc_exit(void)
 {
-	tcp_proc_unregister(&tcp4_seq_afinfo);
+	unregister_pernet_subsys(&tcp4_net_ops);
 }
 #endif /* CONFIG_PROC_FS */
 
-DEFINE_PROTO_INUSE(tcp)
-
 struct proto tcp_prot = {
 	.name			= "TCP",
 	.owner			= THIS_MODULE,
@@ -2435,15 +2481,14 @@ struct proto tcp_prot = {
 	.obj_size		= sizeof(struct tcp_sock),
 	.twsk_prot		= &tcp_timewait_sock_ops,
 	.rsk_prot		= &tcp_request_sock_ops,
-	.hashinfo		= &tcp_hashinfo,
+	.h.hashinfo		= &tcp_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
 #endif
-	REF_PROTO_INUSE(tcp)
 };
 
-void __init tcp_v4_init(struct net_proto_family *ops)
+void __init tcp_v4_init(void)
 {
 	if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW,
 				     IPPROTO_TCP) < 0)
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b61b76847ad9..019c8c16e5cc 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -35,6 +35,8 @@
 #endif
 
 int sysctl_tcp_syncookies __read_mostly = SYNC_INIT;
+EXPORT_SYMBOL(sysctl_tcp_syncookies);
+
 int sysctl_tcp_abort_on_overflow __read_mostly;
 
 struct inet_timewait_death_row tcp_death_row = {
@@ -536,7 +538,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 		 * Enforce "SYN-ACK" according to figure 8, figure 6
 		 * of RFC793, fixed by RFC1122.
 		 */
-		req->rsk_ops->rtx_syn_ack(sk, req, NULL);
+		req->rsk_ops->rtx_syn_ack(sk, req);
 		return NULL;
 	}
 
@@ -569,10 +571,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 	   does sequence test, SYN is truncated, and thus we consider
 	   it a bare ACK.
 
-	   If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this
-	   bare ACK.  Otherwise, we create an established connection.  Both
-	   ends (listening sockets) accept the new incoming connection and try
-	   to talk to each other. 8-)
+	   Both ends (listening sockets) accept the new incoming
+	   connection and try to talk to each other. 8-)
 
 	   Note: This case is both harmless, and rare.  Possibility is about the
 	   same as us discovering intelligent life on another plant tomorrow.
@@ -640,13 +640,6 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 		if (!(flg & TCP_FLAG_ACK))
 			return NULL;
 
-		/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
-		if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
-		    TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
-			inet_rsk(req)->acked = 1;
-			return NULL;
-		}
-
 		/* OK, ACK is valid, create big socket and
 		 * feed this segment to it. It will repeat all
 		 * the tests. THIS SEGMENT MUST MOVE SOCKET TO
@@ -685,7 +678,24 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb,
 		inet_csk_reqsk_queue_unlink(sk, req, prev);
 		inet_csk_reqsk_queue_removed(sk, req);
 
-		inet_csk_reqsk_queue_add(sk, req, child);
+		if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept &&
+		    TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) {
+
+			/* the accept queue handling is done is est recv slow
+			 * path so lets make sure to start there
+			 */
+			tcp_sk(child)->pred_flags = 0;
+			sock_hold(sk);
+			sock_hold(child);
+			tcp_sk(child)->defer_tcp_accept.listen_sk = sk;
+			tcp_sk(child)->defer_tcp_accept.request = req;
+
+			inet_csk_reset_keepalive_timer(child,
+						       inet_csk(sk)->icsk_accept_queue.rskq_defer_accept * HZ);
+		} else {
+			inet_csk_reqsk_queue_add(sk, req, child);
+		}
+
 		return child;
 
 	listen_overflow:
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 72b9350006fe..a627616314ba 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -998,7 +998,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
 	xmit_size_goal = mss_now;
 
 	if (doing_tso) {
-		xmit_size_goal = (65535 -
+		xmit_size_goal = ((sk->sk_gso_max_size - 1) -
 				  inet_csk(sk)->icsk_af_ops->net_header_len -
 				  inet_csk(sk)->icsk_ext_hdr_len -
 				  tp->tcp_header_len);
@@ -1282,7 +1282,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
 	limit = min(send_win, cong_win);
 
 	/* If a full-sized TSO skb can be sent, do it. */
-	if (limit >= 65536)
+	if (limit >= sk->sk_gso_max_size)
 		goto send_now;
 
 	if (sysctl_tcp_tso_win_divisor) {
@@ -2568,6 +2568,7 @@ void tcp_send_probe0(struct sock *sk)
 	}
 }
 
+EXPORT_SYMBOL(tcp_select_initial_window);
 EXPORT_SYMBOL(tcp_connect);
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_simple_retransmit);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 803d758a2b12..160d16f9f4fc 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -481,6 +481,11 @@ static void tcp_keepalive_timer (unsigned long data)
 		goto death;
 	}
 
+	if (tp->defer_tcp_accept.request && sk->sk_state == TCP_ESTABLISHED) {
+		tcp_send_active_reset(sk, GFP_ATOMIC);
+		goto death;
+	}
+
 	if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE)
 		goto out;
 
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 1704c1474ea1..7b7fcacec4a0 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -137,29 +137,28 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
 	struct hlist_node *node;
 
 	sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
-		if (sk->sk_net == net && sk->sk_hash == num)
+		if (net_eq(sock_net(sk), net) && sk->sk_hash == num)
 			return 1;
 	return 0;
 }
 
 /**
- *  __udp_lib_get_port  -  UDP/-Lite port lookup for IPv4 and IPv6
+ *  udp_lib_get_port  -  UDP/-Lite port lookup for IPv4 and IPv6
  *
  *  @sk:          socket struct in question
  *  @snum:        port number to look up
- *  @udptable:    hash list table, must be of UDP_HTABLE_SIZE
  *  @saddr_comp:  AF-dependent comparison of bound local IP addresses
  */
-int __udp_lib_get_port(struct sock *sk, unsigned short snum,
-		       struct hlist_head udptable[],
+int udp_lib_get_port(struct sock *sk, unsigned short snum,
 		       int (*saddr_comp)(const struct sock *sk1,
 					 const struct sock *sk2 )    )
 {
+	struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
 	struct hlist_node *node;
 	struct hlist_head *head;
 	struct sock *sk2;
 	int    error = 1;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 
 	write_lock_bh(&udp_hash_lock);
 
@@ -219,7 +218,7 @@ gotit:
 		sk_for_each(sk2, node, head)
 			if (sk2->sk_hash == snum                             &&
 			    sk2 != sk                                        &&
-			    sk2->sk_net == net				     &&
+			    net_eq(sock_net(sk2), net)			     &&
 			    (!sk2->sk_reuse        || !sk->sk_reuse)         &&
 			    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
 			     || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
@@ -232,7 +231,7 @@ gotit:
 	if (sk_unhashed(sk)) {
 		head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
 		sk_add_node(sk, head);
-		sock_prot_inuse_add(sk->sk_prot, 1);
+		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	}
 	error = 0;
 fail:
@@ -240,13 +239,7 @@ fail:
 	return error;
 }
 
-int udp_get_port(struct sock *sk, unsigned short snum,
-			int (*scmp)(const struct sock *, const struct sock *))
-{
-	return  __udp_lib_get_port(sk, snum, udp_hash, scmp);
-}
-
-int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 {
 	struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
 
@@ -255,9 +248,9 @@ int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
 		   inet1->rcv_saddr == inet2->rcv_saddr      ));
 }
 
-static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
+int udp_v4_get_port(struct sock *sk, unsigned short snum)
 {
-	return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+	return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal);
 }
 
 /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@@ -276,7 +269,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
 	sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
 		struct inet_sock *inet = inet_sk(sk);
 
-		if (sk->sk_net == net && sk->sk_hash == hnum &&
+		if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
 				!ipv6_only_sock(sk)) {
 			int score = (sk->sk_family == PF_INET ? 1 : 0);
 			if (inet->rcv_saddr) {
@@ -364,7 +357,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[])
 	int harderr;
 	int err;
 
-	sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest,
+	sk = __udp4_lib_lookup(dev_net(skb->dev), iph->daddr, uh->dest,
 			iph->saddr, uh->source, skb->dev->ifindex, udptable);
 	if (sk == NULL) {
 		ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
@@ -614,7 +607,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
 	ipc.oif = sk->sk_bound_dev_if;
 	if (msg->msg_controllen) {
-		err = ip_cmsg_send(msg, &ipc);
+		err = ip_cmsg_send(sock_net(sk), msg, &ipc);
 		if (err)
 			return err;
 		if (ipc.opt)
@@ -663,7 +656,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 					       { .sport = inet->sport,
 						 .dport = dport } } };
 		security_sk_classify_flow(sk, &fl);
-		err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1);
+		err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1);
 		if (err) {
 			if (err == -ENETUNREACH)
 				IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
@@ -1188,7 +1181,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
 		return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
 
-	sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr,
+	sk = __udp4_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr,
 			uh->dest, inet_iif(skb), udptable);
 
 	if (sk != NULL) {
@@ -1474,8 +1467,6 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
 
 }
 
-DEFINE_PROTO_INUSE(udp)
-
 struct proto udp_prot = {
 	.name		   = "UDP",
 	.owner		   = THIS_MODULE,
@@ -1498,11 +1489,11 @@ struct proto udp_prot = {
 	.sysctl_wmem	   = &sysctl_udp_wmem_min,
 	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp_sock),
+	.h.udp_hash	   = udp_hash,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
 	.compat_getsockopt = compat_udp_getsockopt,
 #endif
-	REF_PROTO_INUSE(udp)
 };
 
 /* ------------------------------------------------------------------------ */
@@ -1512,10 +1503,13 @@ static struct sock *udp_get_first(struct seq_file *seq)
 {
 	struct sock *sk;
 	struct udp_iter_state *state = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
 		struct hlist_node *node;
 		sk_for_each(sk, node, state->hashtable + state->bucket) {
+			if (!net_eq(sock_net(sk), net))
+				continue;
 			if (sk->sk_family == state->family)
 				goto found;
 		}
@@ -1528,12 +1522,13 @@ found:
 static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
 {
 	struct udp_iter_state *state = seq->private;
+	struct net *net = seq_file_net(seq);
 
 	do {
 		sk = sk_next(sk);
 try_again:
 		;
-	} while (sk && sk->sk_family != state->family);
+	} while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family));
 
 	if (!sk && ++state->bucket < UDP_HTABLE_SIZE) {
 		sk = sk_head(state->hashtable + state->bucket);
@@ -1581,47 +1576,36 @@ static void udp_seq_stop(struct seq_file *seq, void *v)
 static int udp_seq_open(struct inode *inode, struct file *file)
 {
 	struct udp_seq_afinfo *afinfo = PDE(inode)->data;
-	struct seq_file *seq;
-	int rc = -ENOMEM;
-	struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
+	struct udp_iter_state *s;
+	int err;
 
-	if (!s)
-		goto out;
+	err = seq_open_net(inode, file, &afinfo->seq_ops,
+			   sizeof(struct udp_iter_state));
+	if (err < 0)
+		return err;
+
+	s = ((struct seq_file *)file->private_data)->private;
 	s->family		= afinfo->family;
 	s->hashtable		= afinfo->hashtable;
-	s->seq_ops.start	= udp_seq_start;
-	s->seq_ops.next		= udp_seq_next;
-	s->seq_ops.show		= afinfo->seq_show;
-	s->seq_ops.stop		= udp_seq_stop;
-
-	rc = seq_open(file, &s->seq_ops);
-	if (rc)
-		goto out_kfree;
-
-	seq	     = file->private_data;
-	seq->private = s;
-out:
-	return rc;
-out_kfree:
-	kfree(s);
-	goto out;
+	return err;
 }
 
 /* ------------------------------------------------------------------------ */
-int udp_proc_register(struct udp_seq_afinfo *afinfo)
+int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo)
 {
 	struct proc_dir_entry *p;
 	int rc = 0;
 
-	if (!afinfo)
-		return -EINVAL;
-	afinfo->seq_fops->owner		= afinfo->owner;
-	afinfo->seq_fops->open		= udp_seq_open;
-	afinfo->seq_fops->read		= seq_read;
-	afinfo->seq_fops->llseek	= seq_lseek;
-	afinfo->seq_fops->release	= seq_release_private;
+	afinfo->seq_fops.open		= udp_seq_open;
+	afinfo->seq_fops.read		= seq_read;
+	afinfo->seq_fops.llseek		= seq_lseek;
+	afinfo->seq_fops.release	= seq_release_net;
+
+	afinfo->seq_ops.start		= udp_seq_start;
+	afinfo->seq_ops.next		= udp_seq_next;
+	afinfo->seq_ops.stop		= udp_seq_stop;
 
-	p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops);
+	p = proc_net_fops_create(net, afinfo->name, S_IRUGO, &afinfo->seq_fops);
 	if (p)
 		p->data = afinfo;
 	else
@@ -1629,12 +1613,9 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo)
 	return rc;
 }
 
-void udp_proc_unregister(struct udp_seq_afinfo *afinfo)
+void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo)
 {
-	if (!afinfo)
-		return;
-	proc_net_remove(&init_net, afinfo->name);
-	memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
+	proc_net_remove(net, afinfo->name);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -1673,24 +1654,41 @@ int udp4_seq_show(struct seq_file *seq, void *v)
 }
 
 /* ------------------------------------------------------------------------ */
-static struct file_operations udp4_seq_fops;
 static struct udp_seq_afinfo udp4_seq_afinfo = {
-	.owner		= THIS_MODULE,
 	.name		= "udp",
 	.family		= AF_INET,
 	.hashtable	= udp_hash,
-	.seq_show	= udp4_seq_show,
-	.seq_fops	= &udp4_seq_fops,
+	.seq_fops	= {
+		.owner	=	THIS_MODULE,
+	},
+	.seq_ops	= {
+		.show		= udp4_seq_show,
+	},
+};
+
+static int udp4_proc_init_net(struct net *net)
+{
+	return udp_proc_register(net, &udp4_seq_afinfo);
+}
+
+static void udp4_proc_exit_net(struct net *net)
+{
+	udp_proc_unregister(net, &udp4_seq_afinfo);
+}
+
+static struct pernet_operations udp4_net_ops = {
+	.init = udp4_proc_init_net,
+	.exit = udp4_proc_exit_net,
 };
 
 int __init udp4_proc_init(void)
 {
-	return udp_proc_register(&udp4_seq_afinfo);
+	return register_pernet_subsys(&udp4_net_ops);
 }
 
 void udp4_proc_exit(void)
 {
-	udp_proc_unregister(&udp4_seq_afinfo);
+	unregister_pernet_subsys(&udp4_net_ops);
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -1717,12 +1715,12 @@ EXPORT_SYMBOL(udp_disconnect);
 EXPORT_SYMBOL(udp_hash);
 EXPORT_SYMBOL(udp_hash_lock);
 EXPORT_SYMBOL(udp_ioctl);
-EXPORT_SYMBOL(udp_get_port);
 EXPORT_SYMBOL(udp_prot);
 EXPORT_SYMBOL(udp_sendmsg);
 EXPORT_SYMBOL(udp_lib_getsockopt);
 EXPORT_SYMBOL(udp_lib_setsockopt);
 EXPORT_SYMBOL(udp_poll);
+EXPORT_SYMBOL(udp_lib_get_port);
 
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(udp_proc_register);
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index 6c55828e41ba..7288bf7977fb 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -8,11 +8,7 @@
 extern int  	__udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
 extern void 	__udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
 
-extern int	__udp_lib_get_port(struct sock *sk, unsigned short snum,
-				   struct hlist_head udptable[],
-				   int (*)(const struct sock*,const struct sock*));
-extern int	ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
-
+extern int	udp_v4_get_port(struct sock *sk, unsigned short snum);
 
 extern int	udp_setsockopt(struct sock *sk, int level, int optname,
 			       char __user *optval, int optlen);
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 001b881ca36f..72ce26b6c4d3 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -17,17 +17,6 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics)	__read_mostly;
 
 struct hlist_head 	udplite_hash[UDP_HTABLE_SIZE];
 
-int udplite_get_port(struct sock *sk, unsigned short p,
-		     int (*c)(const struct sock *, const struct sock *))
-{
-	return  __udp_lib_get_port(sk, p, udplite_hash, c);
-}
-
-static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
-{
-	return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal);
-}
-
 static int udplite_rcv(struct sk_buff *skb)
 {
 	return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE);
@@ -42,10 +31,9 @@ static	struct net_protocol udplite_protocol = {
 	.handler	= udplite_rcv,
 	.err_handler	= udplite_err,
 	.no_policy	= 1,
+	.netns_ok	= 1,
 };
 
-DEFINE_PROTO_INUSE(udplite)
-
 struct proto 	udplite_prot = {
 	.name		   = "UDP-Lite",
 	.owner		   = THIS_MODULE,
@@ -63,13 +51,13 @@ struct proto 	udplite_prot = {
 	.backlog_rcv	   = udp_queue_rcv_skb,
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
-	.get_port	   = udplite_v4_get_port,
+	.get_port	   = udp_v4_get_port,
 	.obj_size	   = sizeof(struct udp_sock),
+	.h.udp_hash	   = udplite_hash,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
 	.compat_getsockopt = compat_udp_getsockopt,
 #endif
-	REF_PROTO_INUSE(udplite)
 };
 
 static struct inet_protosw udplite4_protosw = {
@@ -83,15 +71,42 @@ static struct inet_protosw udplite4_protosw = {
 };
 
 #ifdef CONFIG_PROC_FS
-static struct file_operations udplite4_seq_fops;
 static struct udp_seq_afinfo udplite4_seq_afinfo = {
-	.owner		= THIS_MODULE,
 	.name		= "udplite",
 	.family		= AF_INET,
 	.hashtable	= udplite_hash,
-	.seq_show	= udp4_seq_show,
-	.seq_fops	= &udplite4_seq_fops,
+	.seq_fops	= {
+		.owner	=	THIS_MODULE,
+	},
+	.seq_ops	= {
+		.show		= udp4_seq_show,
+	},
+};
+
+static int udplite4_proc_init_net(struct net *net)
+{
+	return udp_proc_register(net, &udplite4_seq_afinfo);
+}
+
+static void udplite4_proc_exit_net(struct net *net)
+{
+	udp_proc_unregister(net, &udplite4_seq_afinfo);
+}
+
+static struct pernet_operations udplite4_net_ops = {
+	.init = udplite4_proc_init_net,
+	.exit = udplite4_proc_exit_net,
 };
+
+static __init int udplite4_proc_init(void)
+{
+	return register_pernet_subsys(&udplite4_net_ops);
+}
+#else
+static inline int udplite4_proc_init(void)
+{
+	return 0;
+}
 #endif
 
 void __init udplite4_register(void)
@@ -104,18 +119,15 @@ void __init udplite4_register(void)
 
 	inet_register_protosw(&udplite4_protosw);
 
-#ifdef CONFIG_PROC_FS
-	if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */
-		printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__);
-#endif
+	if (udplite4_proc_init())
+		printk(KERN_ERR "%s: Cannot register /proc!\n", __func__);
 	return;
 
 out_unregister_proto:
 	proto_unregister(&udplite_prot);
 out_register_err:
-	printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__);
+	printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__);
 }
 
 EXPORT_SYMBOL(udplite_hash);
 EXPORT_SYMBOL(udplite_prot);
-EXPORT_SYMBOL(udplite_get_port);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 10ed70491434..c63de0a72aba 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -221,7 +221,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 	xdst = (struct xfrm_dst *)dst;
 	if (xdst->u.rt.idev->dev == dev) {
 		struct in_device *loopback_idev =
-			in_dev_get(dev->nd_net->loopback_dev);
+			in_dev_get(dev_net(dev)->loopback_dev);
 		BUG_ON(!loopback_idev);
 
 		do {
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 24f3aa0f2a35..ae14617e607f 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -16,6 +16,7 @@ ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
 ipv6-$(CONFIG_NETFILTER) += netfilter.o
 ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
 ipv6-$(CONFIG_PROC_FS) += proc.o
+ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
 
 ipv6-objs += $(ipv6-y)
 
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e7a1882db048..87f688857ade 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -335,7 +335,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 
 	rwlock_init(&ndev->lock);
 	ndev->dev = dev;
-	memcpy(&ndev->cnf, dev->nd_net->ipv6.devconf_dflt, sizeof(ndev->cnf));
+	memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
 	ndev->cnf.mtu6 = dev->mtu;
 	ndev->cnf.sysctl = NULL;
 	ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
@@ -349,7 +349,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 	if (snmp6_alloc_dev(ndev) < 0) {
 		ADBG((KERN_WARNING
 			"%s(): cannot allocate memory for statistics; dev=%s.\n",
-			__FUNCTION__, dev->name));
+			__func__, dev->name));
 		neigh_parms_release(&nd_tbl, ndev->nd_parms);
 		ndev->dead = 1;
 		in6_dev_finish_destroy(ndev);
@@ -359,7 +359,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 	if (snmp6_register_dev(ndev) < 0) {
 		ADBG((KERN_WARNING
 			"%s(): cannot create /proc/net/dev_snmp6/%s\n",
-			__FUNCTION__, dev->name));
+			__func__, dev->name));
 		neigh_parms_release(&nd_tbl, ndev->nd_parms);
 		ndev->dead = 1;
 		in6_dev_finish_destroy(ndev);
@@ -493,7 +493,7 @@ static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
 		dev_forward_change((struct inet6_dev *)table->extra1);
 
 	if (*p)
-		rt6_purge_dflt_routers();
+		rt6_purge_dflt_routers(net);
 }
 #endif
 
@@ -561,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 	write_lock(&addrconf_hash_lock);
 
 	/* Ignore adding duplicate addresses on an interface */
-	if (ipv6_chk_same_addr(&init_net, addr, idev->dev)) {
+	if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
 		ADBG(("ipv6_add_addr: already assigned\n"));
 		err = -EEXIST;
 		goto out;
@@ -751,9 +751,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 	if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
 		struct in6_addr prefix;
 		struct rt6_info *rt;
-
+		struct net *net = dev_net(ifp->idev->dev);
 		ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
-		rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1);
+		rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
 
 		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 			if (onlink == 0) {
@@ -893,20 +893,40 @@ out:
 /*
  *	Choose an appropriate source address (RFC3484)
  */
+enum {
+	IPV6_SADDR_RULE_INIT = 0,
+	IPV6_SADDR_RULE_LOCAL,
+	IPV6_SADDR_RULE_SCOPE,
+	IPV6_SADDR_RULE_PREFERRED,
+#ifdef CONFIG_IPV6_MIP6
+	IPV6_SADDR_RULE_HOA,
+#endif
+	IPV6_SADDR_RULE_OIF,
+	IPV6_SADDR_RULE_LABEL,
+#ifdef CONFIG_IPV6_PRIVACY
+	IPV6_SADDR_RULE_PRIVACY,
+#endif
+	IPV6_SADDR_RULE_ORCHID,
+	IPV6_SADDR_RULE_PREFIX,
+	IPV6_SADDR_RULE_MAX
+};
+
 struct ipv6_saddr_score {
-	int		addr_type;
-	unsigned int	attrs;
-	int		matchlen;
-	int		scope;
-	unsigned int	rule;
+	int			rule;
+	int			addr_type;
+	struct inet6_ifaddr	*ifa;
+	DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX);
+	int			scopedist;
+	int			matchlen;
 };
 
-#define IPV6_SADDR_SCORE_LOCAL		0x0001
-#define IPV6_SADDR_SCORE_PREFERRED	0x0004
-#define IPV6_SADDR_SCORE_HOA		0x0008
-#define IPV6_SADDR_SCORE_OIF		0x0010
-#define IPV6_SADDR_SCORE_LABEL		0x0020
-#define IPV6_SADDR_SCORE_PRIVACY	0x0040
+struct ipv6_saddr_dst {
+	struct in6_addr *addr;
+	int ifindex;
+	int scope;
+	int label;
+	unsigned int prefs;
+};
 
 static inline int ipv6_saddr_preferred(int type)
 {
@@ -916,27 +936,152 @@ static inline int ipv6_saddr_preferred(int type)
 	return 0;
 }
 
-int ipv6_dev_get_saddr(struct net_device *daddr_dev,
-		       struct in6_addr *daddr, struct in6_addr *saddr)
+static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
+			       struct ipv6_saddr_dst *dst,
+			       int i)
 {
-	struct ipv6_saddr_score hiscore;
-	struct inet6_ifaddr *ifa_result = NULL;
-	int daddr_type = __ipv6_addr_type(daddr);
-	int daddr_scope = __ipv6_addr_src_scope(daddr_type);
-	int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
-	u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex);
+	int ret;
+
+	if (i <= score->rule) {
+		switch (i) {
+		case IPV6_SADDR_RULE_SCOPE:
+			ret = score->scopedist;
+			break;
+		case IPV6_SADDR_RULE_PREFIX:
+			ret = score->matchlen;
+			break;
+		default:
+			ret = !!test_bit(i, score->scorebits);
+		}
+		goto out;
+	}
+
+	switch (i) {
+	case IPV6_SADDR_RULE_INIT:
+		/* Rule 0: remember if hiscore is not ready yet */
+		ret = !!score->ifa;
+		break;
+	case IPV6_SADDR_RULE_LOCAL:
+		/* Rule 1: Prefer same address */
+		ret = ipv6_addr_equal(&score->ifa->addr, dst->addr);
+		break;
+	case IPV6_SADDR_RULE_SCOPE:
+		/* Rule 2: Prefer appropriate scope
+		 *
+		 *      ret
+		 *       ^
+		 *    -1 |  d 15
+		 *    ---+--+-+---> scope
+		 *       |
+		 *       |             d is scope of the destination.
+		 *  B-d  |  \
+		 *       |   \      <- smaller scope is better if
+		 *  B-15 |    \        if scope is enough for destinaion.
+		 *       |             ret = B - scope (-1 <= scope >= d <= 15).
+		 * d-C-1 | /
+		 *       |/         <- greater is better
+		 *   -C  /             if scope is not enough for destination.
+		 *      /|             ret = scope - C (-1 <= d < scope <= 15).
+		 *
+		 * d - C - 1 < B -15 (for all -1 <= d <= 15).
+		 * C > d + 14 - B >= 15 + 14 - B = 29 - B.
+		 * Assume B = 0 and we get C > 29.
+		 */
+		ret = __ipv6_addr_src_scope(score->addr_type);
+		if (ret >= dst->scope)
+			ret = -ret;
+		else
+			ret -= 128;	/* 30 is enough */
+		score->scopedist = ret;
+		break;
+	case IPV6_SADDR_RULE_PREFERRED:
+		/* Rule 3: Avoid deprecated and optimistic addresses */
+		ret = ipv6_saddr_preferred(score->addr_type) ||
+		      !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC));
+		break;
+#ifdef CONFIG_IPV6_MIP6
+	case IPV6_SADDR_RULE_HOA:
+	    {
+		/* Rule 4: Prefer home address */
+		int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA);
+		ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome;
+		break;
+	    }
+#endif
+	case IPV6_SADDR_RULE_OIF:
+		/* Rule 5: Prefer outgoing interface */
+		ret = (!dst->ifindex ||
+		       dst->ifindex == score->ifa->idev->dev->ifindex);
+		break;
+	case IPV6_SADDR_RULE_LABEL:
+		/* Rule 6: Prefer matching label */
+		ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
+				      score->ifa->idev->dev->ifindex) == dst->label;
+		break;
+#ifdef CONFIG_IPV6_PRIVACY
+	case IPV6_SADDR_RULE_PRIVACY:
+	    {
+		/* Rule 7: Prefer public address
+		 * Note: prefer temprary address if use_tempaddr >= 2
+		 */
+		int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ?
+				!!(dst->prefs & IPV6_PREFER_SRC_TMP) :
+				score->ifa->idev->cnf.use_tempaddr >= 2;
+		ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp;
+		break;
+	    }
+#endif
+	case IPV6_SADDR_RULE_ORCHID:
+		/* Rule 8-: Prefer ORCHID vs ORCHID or
+		 *	    non-ORCHID vs non-ORCHID
+		 */
+		ret = !(ipv6_addr_orchid(&score->ifa->addr) ^
+			ipv6_addr_orchid(dst->addr));
+		break;
+	case IPV6_SADDR_RULE_PREFIX:
+		/* Rule 8: Use longest matching prefix */
+		score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr,
+						       dst->addr);
+		break;
+	default:
+		ret = 0;
+	}
+
+	if (ret)
+		__set_bit(i, score->scorebits);
+	score->rule = i;
+out:
+	return ret;
+}
+
+int ipv6_dev_get_saddr(struct net_device *dst_dev,
+		       struct in6_addr *daddr, unsigned int prefs,
+		       struct in6_addr *saddr)
+{
+	struct ipv6_saddr_score scores[2],
+				*score = &scores[0], *hiscore = &scores[1];
+	struct net *net = dev_net(dst_dev);
+	struct ipv6_saddr_dst dst;
 	struct net_device *dev;
+	int dst_type;
+
+	dst_type = __ipv6_addr_type(daddr);
+	dst.addr = daddr;
+	dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
+	dst.scope = __ipv6_addr_src_scope(dst_type);
+	dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
+	dst.prefs = prefs;
 
-	memset(&hiscore, 0, sizeof(hiscore));
+	hiscore->rule = -1;
+	hiscore->ifa = NULL;
 
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
 
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		struct inet6_dev *idev;
-		struct inet6_ifaddr *ifa;
 
-		/* Rule 0: Candidate Source Address (section 4)
+		/* Candidate Source Address (section 4)
 		 *  - multicast and link-local destination address,
 		 *    the set of candidate source address MUST only
 		 *    include addresses assigned to interfaces
@@ -948,9 +1093,9 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 		 *    belonging to the same site as the outgoing
 		 *    interface.)
 		 */
-		if ((daddr_type & IPV6_ADDR_MULTICAST ||
-		     daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
-		    daddr_dev && dev != daddr_dev)
+		if (((dst_type & IPV6_ADDR_MULTICAST) ||
+		     dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
+		    dst.ifindex && dev->ifindex != dst.ifindex)
 			continue;
 
 		idev = __in6_dev_get(dev);
@@ -958,12 +1103,10 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 			continue;
 
 		read_lock_bh(&idev->lock);
-		for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
-			struct ipv6_saddr_score score;
-
-			score.addr_type = __ipv6_addr_type(&ifa->addr);
+		for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
+			int i;
 
-			/* Rule 0:
+			/*
 			 * - Tentative Address (RFC2462 section 5.4)
 			 *  - A tentative address is not considered
 			 *    "assigned to an interface" in the traditional
@@ -973,11 +1116,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 			 *    addresses, and the unspecified address MUST
 			 *    NOT be included in a candidate set.
 			 */
-			if ((ifa->flags & IFA_F_TENTATIVE) &&
-			    (!(ifa->flags & IFA_F_OPTIMISTIC)))
+			if ((score->ifa->flags & IFA_F_TENTATIVE) &&
+			    (!(score->ifa->flags & IFA_F_OPTIMISTIC)))
 				continue;
-			if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
-				     score.addr_type & IPV6_ADDR_MULTICAST)) {
+
+			score->addr_type = __ipv6_addr_type(&score->ifa->addr);
+
+			if (unlikely(score->addr_type == IPV6_ADDR_ANY ||
+				     score->addr_type & IPV6_ADDR_MULTICAST)) {
 				LIMIT_NETDEBUG(KERN_DEBUG
 					       "ADDRCONF: unspecified / multicast address "
 					       "assigned as unicast address on %s",
@@ -985,207 +1131,63 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
 				continue;
 			}
 
-			score.attrs = 0;
-			score.matchlen = 0;
-			score.scope = 0;
-			score.rule = 0;
-
-			if (ifa_result == NULL) {
-				/* record it if the first available entry */
-				goto record_it;
-			}
-
-			/* Rule 1: Prefer same address */
-			if (hiscore.rule < 1) {
-				if (ipv6_addr_equal(&ifa_result->addr, daddr))
-					hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;
-				hiscore.rule++;
-			}
-			if (ipv6_addr_equal(&ifa->addr, daddr)) {
-				score.attrs |= IPV6_SADDR_SCORE_LOCAL;
-				if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {
-					score.rule = 1;
-					goto record_it;
-				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)
-					continue;
-			}
-
-			/* Rule 2: Prefer appropriate scope */
-			if (hiscore.rule < 2) {
-				hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
-				hiscore.rule++;
-			}
-			score.scope = __ipv6_addr_src_scope(score.addr_type);
-			if (hiscore.scope < score.scope) {
-				if (hiscore.scope < daddr_scope) {
-					score.rule = 2;
-					goto record_it;
-				} else
-					continue;
-			} else if (score.scope < hiscore.scope) {
-				if (score.scope < daddr_scope)
-					break; /* addresses sorted by scope */
-				else {
-					score.rule = 2;
-					goto record_it;
-				}
-			}
+			score->rule = -1;
+			bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX);
+
+			for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
+				int minihiscore, miniscore;
+
+				minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
+				miniscore = ipv6_get_saddr_eval(score, &dst, i);
+
+				if (minihiscore > miniscore) {
+					if (i == IPV6_SADDR_RULE_SCOPE &&
+					    score->scopedist > 0) {
+						/*
+						 * special case:
+						 * each remaining entry
+						 * has too small (not enough)
+						 * scope, because ifa entries
+						 * are sorted by their scope
+						 * values.
+						 */
+						goto try_nextdev;
+					}
+					break;
+				} else if (minihiscore < miniscore) {
+					struct ipv6_saddr_score *tmp;
 
-			/* Rule 3: Avoid deprecated and optimistic addresses */
-			if (hiscore.rule < 3) {
-				if (ipv6_saddr_preferred(hiscore.addr_type) ||
-				   (((ifa_result->flags &
-				    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
-					hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
-				hiscore.rule++;
-			}
-			if (ipv6_saddr_preferred(score.addr_type) ||
-			   (((ifa->flags &
-			    (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
-				score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
-				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
-					score.rule = 3;
-					goto record_it;
-				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)
-					continue;
-			}
+					if (hiscore->ifa)
+						in6_ifa_put(hiscore->ifa);
 
-			/* Rule 4: Prefer home address */
-#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-			if (hiscore.rule < 4) {
-				if (ifa_result->flags & IFA_F_HOMEADDRESS)
-					hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
-				hiscore.rule++;
-			}
-			if (ifa->flags & IFA_F_HOMEADDRESS) {
-				score.attrs |= IPV6_SADDR_SCORE_HOA;
-				if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
-					score.rule = 4;
-					goto record_it;
-				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
-					continue;
-			}
-#else
-			if (hiscore.rule < 4)
-				hiscore.rule++;
-#endif
+					in6_ifa_hold(score->ifa);
 
-			/* Rule 5: Prefer outgoing interface */
-			if (hiscore.rule < 5) {
-				if (daddr_dev == NULL ||
-				    daddr_dev == ifa_result->idev->dev)
-					hiscore.attrs |= IPV6_SADDR_SCORE_OIF;
-				hiscore.rule++;
-			}
-			if (daddr_dev == NULL ||
-			    daddr_dev == ifa->idev->dev) {
-				score.attrs |= IPV6_SADDR_SCORE_OIF;
-				if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {
-					score.rule = 5;
-					goto record_it;
-				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_OIF)
-					continue;
-			}
+					tmp = hiscore;
+					hiscore = score;
+					score = tmp;
 
-			/* Rule 6: Prefer matching label */
-			if (hiscore.rule < 6) {
-				if (ipv6_addr_label(&ifa_result->addr,
-						    hiscore.addr_type,
-						    ifa_result->idev->dev->ifindex) == daddr_label)
-					hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
-				hiscore.rule++;
-			}
-			if (ipv6_addr_label(&ifa->addr,
-					    score.addr_type,
-					    ifa->idev->dev->ifindex) == daddr_label) {
-				score.attrs |= IPV6_SADDR_SCORE_LABEL;
-				if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
-					score.rule = 6;
-					goto record_it;
-				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL)
-					continue;
-			}
+					/* restore our iterator */
+					score->ifa = hiscore->ifa;
 
-#ifdef CONFIG_IPV6_PRIVACY
-			/* Rule 7: Prefer public address
-			 * Note: prefer temprary address if use_tempaddr >= 2
-			 */
-			if (hiscore.rule < 7) {
-				if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^
-				    (ifa_result->idev->cnf.use_tempaddr >= 2))
-					hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY;
-				hiscore.rule++;
-			}
-			if ((!(ifa->flags & IFA_F_TEMPORARY)) ^
-			    (ifa->idev->cnf.use_tempaddr >= 2)) {
-				score.attrs |= IPV6_SADDR_SCORE_PRIVACY;
-				if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) {
-					score.rule = 7;
-					goto record_it;
+					break;
 				}
-			} else {
-				if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
-					continue;
-			}
-#else
-			if (hiscore.rule < 7)
-				hiscore.rule++;
-#endif
-			/* Rule 8: Use longest matching prefix */
-			if (hiscore.rule < 8) {
-				hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
-				hiscore.rule++;
-			}
-			score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
-			if (score.matchlen > hiscore.matchlen) {
-				score.rule = 8;
-				goto record_it;
 			}
-#if 0
-			else if (score.matchlen < hiscore.matchlen)
-				continue;
-#endif
-
-			/* Final Rule: choose first available one */
-			continue;
-record_it:
-			if (ifa_result)
-				in6_ifa_put(ifa_result);
-			in6_ifa_hold(ifa);
-			ifa_result = ifa;
-			hiscore = score;
 		}
+try_nextdev:
 		read_unlock_bh(&idev->lock);
 	}
 	rcu_read_unlock();
 	read_unlock(&dev_base_lock);
 
-	if (!ifa_result)
+	if (!hiscore->ifa)
 		return -EADDRNOTAVAIL;
 
-	ipv6_addr_copy(saddr, &ifa_result->addr);
-	in6_ifa_put(ifa_result);
+	ipv6_addr_copy(saddr, &hiscore->ifa->addr);
+	in6_ifa_put(hiscore->ifa);
 	return 0;
 }
 
-
-int ipv6_get_saddr(struct dst_entry *dst,
-		   struct in6_addr *daddr, struct in6_addr *saddr)
-{
-	return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr);
-}
-
-EXPORT_SYMBOL(ipv6_get_saddr);
+EXPORT_SYMBOL(ipv6_dev_get_saddr);
 
 int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
 		    unsigned char banned_flags)
@@ -1231,7 +1233,7 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
 
 	read_lock_bh(&addrconf_hash_lock);
 	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
-		if (ifp->idev->dev->nd_net != net)
+		if (!net_eq(dev_net(ifp->idev->dev), net))
 			continue;
 		if (ipv6_addr_equal(&ifp->addr, addr) &&
 		    !(ifp->flags&IFA_F_TENTATIVE)) {
@@ -1253,7 +1255,7 @@ int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
 	u8 hash = ipv6_addr_hash(addr);
 
 	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
-		if (ifp->idev->dev->nd_net != net)
+		if (!net_eq(dev_net(ifp->idev->dev), net))
 			continue;
 		if (ipv6_addr_equal(&ifp->addr, addr)) {
 			if (dev == NULL || ifp->idev->dev == dev)
@@ -1271,7 +1273,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr,
 
 	read_lock_bh(&addrconf_hash_lock);
 	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
-		if (ifp->idev->dev->nd_net != net)
+		if (!net_eq(dev_net(ifp->idev->dev), net))
 			continue;
 		if (ipv6_addr_equal(&ifp->addr, addr)) {
 			if (dev == NULL || ifp->idev->dev == dev ||
@@ -1573,7 +1575,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
 		.fc_expires = expires,
 		.fc_dst_len = plen,
 		.fc_flags = RTF_UP | flags,
-		.fc_nlinfo.nl_net = &init_net,
+		.fc_nlinfo.nl_net = dev_net(dev),
 	};
 
 	ipv6_addr_copy(&cfg.fc_dst, pfx);
@@ -1600,7 +1602,7 @@ static void addrconf_add_mroute(struct net_device *dev)
 		.fc_ifindex = dev->ifindex,
 		.fc_dst_len = 8,
 		.fc_flags = RTF_UP,
-		.fc_nlinfo.nl_net = &init_net,
+		.fc_nlinfo.nl_net = dev_net(dev),
 	};
 
 	ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0);
@@ -1617,7 +1619,7 @@ static void sit_route_add(struct net_device *dev)
 		.fc_ifindex = dev->ifindex,
 		.fc_dst_len = 96,
 		.fc_flags = RTF_UP | RTF_NONEXTHOP,
-		.fc_nlinfo.nl_net = &init_net,
+		.fc_nlinfo.nl_net = dev_net(dev),
 	};
 
 	/* prefix length - 96 bits "::d.d.d.d" */
@@ -1718,7 +1720,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 
 	if (pinfo->onlink) {
 		struct rt6_info *rt;
-		rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1);
+		rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
+				dev->ifindex, 1);
 
 		if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 			if (rt->rt6i_flags&RTF_EXPIRES) {
@@ -1761,7 +1764,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
 
 ok:
 
-		ifp = ipv6_get_ifaddr(&init_net, &addr, dev, 1);
+		ifp = ipv6_get_ifaddr(dev_net(dev), &addr, dev, 1);
 
 		if (ifp == NULL && valid_lft) {
 			int max_addresses = in6_dev->cnf.max_addresses;
@@ -1887,7 +1890,7 @@ ok:
  *	Special case for SIT interfaces where we create a new "virtual"
  *	device.
  */
-int addrconf_set_dstaddr(void __user *arg)
+int addrconf_set_dstaddr(struct net *net, void __user *arg)
 {
 	struct in6_ifreq ireq;
 	struct net_device *dev;
@@ -1899,7 +1902,7 @@ int addrconf_set_dstaddr(void __user *arg)
 	if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
 		goto err_exit;
 
-	dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex);
+	dev = __dev_get_by_index(net, ireq.ifr6_ifindex);
 
 	err = -ENODEV;
 	if (dev == NULL)
@@ -1930,7 +1933,8 @@ int addrconf_set_dstaddr(void __user *arg)
 
 		if (err == 0) {
 			err = -ENOBUFS;
-			if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL)
+			dev = __dev_get_by_name(net, p.name);
+			if (!dev)
 				goto err_exit;
 			err = dev_open(dev);
 		}
@@ -1945,8 +1949,9 @@ err_exit:
 /*
  *	Manual configuration of address on an interface
  */
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
-			  __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft)
+static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx,
+			  int plen, __u8 ifa_flags, __u32 prefered_lft,
+			  __u32 valid_lft)
 {
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev;
@@ -1960,7 +1965,8 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
 	if (!valid_lft || prefered_lft > valid_lft)
 		return -EINVAL;
 
-	if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
+	dev = __dev_get_by_index(net, ifindex);
+	if (!dev)
 		return -ENODEV;
 
 	if ((idev = addrconf_add_dev(dev)) == NULL)
@@ -2005,13 +2011,15 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
 	return PTR_ERR(ifp);
 }
 
-static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
+static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
+			  int plen)
 {
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev;
 	struct net_device *dev;
 
-	if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
+	dev = __dev_get_by_index(net, ifindex);
+	if (!dev)
 		return -ENODEV;
 
 	if ((idev = __in6_dev_get(dev)) == NULL)
@@ -2039,7 +2047,7 @@ static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
 }
 
 
-int addrconf_add_ifaddr(void __user *arg)
+int addrconf_add_ifaddr(struct net *net, void __user *arg)
 {
 	struct in6_ifreq ireq;
 	int err;
@@ -2051,13 +2059,14 @@ int addrconf_add_ifaddr(void __user *arg)
 		return -EFAULT;
 
 	rtnl_lock();
-	err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
-			     IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+	err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr,
+			     ireq.ifr6_prefixlen, IFA_F_PERMANENT,
+			     INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
 	rtnl_unlock();
 	return err;
 }
 
-int addrconf_del_ifaddr(void __user *arg)
+int addrconf_del_ifaddr(struct net *net, void __user *arg)
 {
 	struct in6_ifreq ireq;
 	int err;
@@ -2069,7 +2078,8 @@ int addrconf_del_ifaddr(void __user *arg)
 		return -EFAULT;
 
 	rtnl_lock();
-	err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
+	err = inet6_addr_del(net, ireq.ifr6_ifindex, &ireq.ifr6_addr,
+			     ireq.ifr6_prefixlen);
 	rtnl_unlock();
 	return err;
 }
@@ -2080,6 +2090,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
 	struct inet6_ifaddr * ifp;
 	struct in6_addr addr;
 	struct net_device *dev;
+	struct net *net = dev_net(idev->dev);
 	int scope;
 
 	ASSERT_RTNL();
@@ -2106,7 +2117,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
 		return;
 	}
 
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		struct in_device * in_dev = __in_dev_get_rtnl(dev);
 		if (in_dev && (dev->flags & IFF_UP)) {
 			struct in_ifaddr * ifa;
@@ -2269,15 +2280,16 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
 static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
 {
 	struct net_device *link_dev;
+	struct net *net = dev_net(idev->dev);
 
 	/* first try to inherit the link-local address from the link device */
 	if (idev->dev->iflink &&
-	    (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) {
+	    (link_dev = __dev_get_by_index(net, idev->dev->iflink))) {
 		if (!ipv6_inherit_linklocal(idev, link_dev))
 			return;
 	}
 	/* then try to inherit it from any device */
-	for_each_netdev(&init_net, link_dev) {
+	for_each_netdev(net, link_dev) {
 		if (!ipv6_inherit_linklocal(idev, link_dev))
 			return;
 	}
@@ -2310,9 +2322,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
 	int run_pending = 0;
 	int err;
 
-	if (dev->nd_net != &init_net)
-		return NOTIFY_DONE;
-
 	switch(event) {
 	case NETDEV_REGISTER:
 		if (!idev && dev->mtu >= IPV6_MIN_MTU) {
@@ -2452,6 +2461,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 {
 	struct inet6_dev *idev;
 	struct inet6_ifaddr *ifa, **bifa;
+	struct net *net = dev_net(dev);
 	int i;
 
 	ASSERT_RTNL();
@@ -2459,7 +2469,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 	if (dev == init_net.loopback_dev && how == 1)
 		how = 0;
 
-	rt6_ifdown(dev);
+	rt6_ifdown(net, dev);
 	neigh_ifdown(&nd_tbl, dev);
 
 	idev = __in6_dev_get(dev);
@@ -2775,12 +2785,12 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
 {
 	struct inet6_ifaddr *ifa = NULL;
 	struct if6_iter_state *state = seq->private;
-	struct net *net = state->p.net;
+	struct net *net = seq_file_net(seq);
 
 	for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
 		ifa = inet6_addr_lst[state->bucket];
 
-		while (ifa && ifa->idev->dev->nd_net != net)
+		while (ifa && !net_eq(dev_net(ifa->idev->dev), net))
 			ifa = ifa->lst_next;
 		if (ifa)
 			break;
@@ -2791,12 +2801,12 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)
 static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa)
 {
 	struct if6_iter_state *state = seq->private;
-	struct net *net = state->p.net;
+	struct net *net = seq_file_net(seq);
 
 	ifa = ifa->lst_next;
 try_again:
 	if (ifa) {
-		if (ifa->idev->dev->nd_net != net) {
+		if (!net_eq(dev_net(ifa->idev->dev), net)) {
 			ifa = ifa->lst_next;
 			goto try_again;
 		}
@@ -2914,7 +2924,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
 	u8 hash = ipv6_addr_hash(addr);
 	read_lock_bh(&addrconf_hash_lock);
 	for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
-		if (ifp->idev->dev->nd_net != net)
+		if (!net_eq(dev_net(ifp->idev->dev), net))
 			continue;
 		if (ipv6_addr_cmp(&ifp->addr, addr) == 0 &&
 		    (ifp->flags & IFA_F_HOMEADDRESS)) {
@@ -3063,15 +3073,12 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
 static int
 inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifaddrmsg *ifm;
 	struct nlattr *tb[IFA_MAX+1];
 	struct in6_addr *pfx;
 	int err;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
 	if (err < 0)
 		return err;
@@ -3081,7 +3088,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	if (pfx == NULL)
 		return -EINVAL;
 
-	return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
+	return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen);
 }
 
 static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
@@ -3124,7 +3131,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags,
 static int
 inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifaddrmsg *ifm;
 	struct nlattr *tb[IFA_MAX+1];
 	struct in6_addr *pfx;
@@ -3134,9 +3141,6 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 	u8 ifa_flags;
 	int err;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
 	if (err < 0)
 		return err;
@@ -3157,7 +3161,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 		valid_lft = INFINITY_LIFE_TIME;
 	}
 
-	dev =  __dev_get_by_index(&init_net, ifm->ifa_index);
+	dev =  __dev_get_by_index(net, ifm->ifa_index);
 	if (dev == NULL)
 		return -ENODEV;
 
@@ -3170,8 +3174,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 		 * It would be best to check for !NLM_F_CREATE here but
 		 * userspace alreay relies on not having to provide this.
 		 */
-		return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
-				      ifa_flags, preferred_lft, valid_lft);
+		return inet6_addr_add(net, ifm->ifa_index, pfx,
+				      ifm->ifa_prefixlen, ifa_flags,
+				      preferred_lft, valid_lft);
 	}
 
 	if (nlh->nlmsg_flags & NLM_F_EXCL ||
@@ -3336,12 +3341,13 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
 	struct inet6_ifaddr *ifa;
 	struct ifmcaddr6 *ifmca;
 	struct ifacaddr6 *ifaca;
+	struct net *net = sock_net(skb->sk);
 
 	s_idx = cb->args[0];
 	s_ip_idx = ip_idx = cb->args[1];
 
 	idx = 0;
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		if (idx < s_idx)
 			goto cont;
 		if (idx > s_idx)
@@ -3408,42 +3414,30 @@ cont:
 
 static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
 	enum addr_type_t type = UNICAST_ADDR;
 
-	if (net != &init_net)
-		return 0;
-
 	return inet6_dump_addr(skb, cb, type);
 }
 
 static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
 	enum addr_type_t type = MULTICAST_ADDR;
 
-	if (net != &init_net)
-		return 0;
-
 	return inet6_dump_addr(skb, cb, type);
 }
 
 
 static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
 	enum addr_type_t type = ANYCAST_ADDR;
 
-	if (net != &init_net)
-		return 0;
-
 	return inet6_dump_addr(skb, cb, type);
 }
 
 static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 			     void *arg)
 {
-	struct net *net = in_skb->sk->sk_net;
+	struct net *net = sock_net(in_skb->sk);
 	struct ifaddrmsg *ifm;
 	struct nlattr *tb[IFA_MAX+1];
 	struct in6_addr *addr = NULL;
@@ -3452,9 +3446,6 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 	struct sk_buff *skb;
 	int err;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy);
 	if (err < 0)
 		goto errout;
@@ -3467,7 +3458,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 
 	ifm = nlmsg_data(nlh);
 	if (ifm->ifa_index)
-		dev = __dev_get_by_index(&init_net, ifm->ifa_index);
+		dev = __dev_get_by_index(net, ifm->ifa_index);
 
 	if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
 		err = -EADDRNOTAVAIL;
@@ -3487,7 +3478,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 		kfree_skb(skb);
 		goto errout_ifa;
 	}
-	err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
 errout_ifa:
 	in6_ifa_put(ifa);
 errout:
@@ -3497,6 +3488,7 @@ errout:
 static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 {
 	struct sk_buff *skb;
+	struct net *net = dev_net(ifa->idev->dev);
 	int err = -ENOBUFS;
 
 	skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC);
@@ -3510,10 +3502,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
 		kfree_skb(skb);
 		goto errout;
 	}
-	err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+	err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
-		rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
+		rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
 }
 
 static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
@@ -3672,18 +3664,15 @@ nla_put_failure:
 
 static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int idx, err;
 	int s_idx = cb->args[0];
 	struct net_device *dev;
 	struct inet6_dev *idev;
 
-	if (net != &init_net)
-		return 0;
-
 	read_lock(&dev_base_lock);
 	idx = 0;
-	for_each_netdev(&init_net, dev) {
+	for_each_netdev(net, dev) {
 		if (idx < s_idx)
 			goto cont;
 		if ((idev = in6_dev_get(dev)) == NULL)
@@ -3705,6 +3694,7 @@ cont:
 void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
 {
 	struct sk_buff *skb;
+	struct net *net = dev_net(idev->dev);
 	int err = -ENOBUFS;
 
 	skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC);
@@ -3718,10 +3708,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
 		kfree_skb(skb);
 		goto errout;
 	}
-	err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+	err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
-		rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err);
+		rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
 }
 
 static inline size_t inet6_prefix_nlmsg_size(void)
@@ -3774,6 +3764,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
 			 struct prefix_info *pinfo)
 {
 	struct sk_buff *skb;
+	struct net *net = dev_net(idev->dev);
 	int err = -ENOBUFS;
 
 	skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC);
@@ -3787,10 +3778,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
 		kfree_skb(skb);
 		goto errout;
 	}
-	err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+	err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
 errout:
 	if (err < 0)
-		rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err);
+		rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
 }
 
 static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
@@ -4185,7 +4176,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev)
 			      NET_IPV6_NEIGH, "ipv6",
 			      &ndisc_ifinfo_sysctl_change,
 			      NULL);
-	__addrconf_sysctl_register(idev->dev->nd_net, idev->dev->name,
+	__addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name,
 			idev->dev->ifindex, idev, &idev->cnf);
 }
 
@@ -4280,6 +4271,32 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
 
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
+
+static int addrconf_net_init(struct net *net)
+{
+	return 0;
+}
+
+static void addrconf_net_exit(struct net *net)
+{
+	struct net_device *dev;
+
+	rtnl_lock();
+	/* clean dev list */
+	for_each_netdev(net, dev) {
+		if (__in6_dev_get(dev) == NULL)
+			continue;
+		addrconf_ifdown(dev, 1);
+	}
+	addrconf_ifdown(net->loopback_dev, 2);
+	rtnl_unlock();
+}
+
+static struct pernet_operations addrconf_net_ops = {
+	.init = addrconf_net_init,
+	.exit = addrconf_net_exit,
+};
+
 /*
  *	Init / cleanup code
  */
@@ -4321,14 +4338,9 @@ int __init addrconf_init(void)
 	if (err)
 		goto errlo;
 
-	ip6_null_entry.u.dst.dev = init_net.loopback_dev;
-	ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
-#ifdef CONFIG_IPV6_MULTIPLE_TABLES
-	ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev;
-	ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
-	ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev;
-	ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
-#endif
+	err = register_pernet_device(&addrconf_net_ops);
+	if (err)
+		return err;
 
 	register_netdevice_notifier(&ipv6_dev_notf);
 
@@ -4358,31 +4370,19 @@ errlo:
 
 void addrconf_cleanup(void)
 {
-	struct net_device *dev;
 	struct inet6_ifaddr *ifa;
 	int i;
 
 	unregister_netdevice_notifier(&ipv6_dev_notf);
+	unregister_pernet_device(&addrconf_net_ops);
 
 	unregister_pernet_subsys(&addrconf_ops);
 
 	rtnl_lock();
 
 	/*
-	 *	clean dev list.
-	 */
-
-	for_each_netdev(&init_net, dev) {
-		if (__in6_dev_get(dev) == NULL)
-			continue;
-		addrconf_ifdown(dev, 1);
-	}
-	addrconf_ifdown(init_net.loopback_dev, 2);
-
-	/*
 	 *	Check hash table.
 	 */
-
 	write_lock_bh(&addrconf_hash_lock);
 	for (i=0; i < IN6_ADDR_HSIZE; i++) {
 		for (ifa=inet6_addr_lst[i]; ifa; ) {
@@ -4399,6 +4399,7 @@ void addrconf_cleanup(void)
 	write_unlock_bh(&addrconf_hash_lock);
 
 	del_timer(&addr_chk_timer);
-
 	rtnl_unlock();
+
+	unregister_pernet_subsys(&addrconf_net_ops);
 }
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index a3c5a72218fd..9bfa8846f262 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -58,6 +58,7 @@ static struct ip6addrlbl_table
  * ::ffff:0:0/96	V4MAPPED	4
  * fc00::/7		N/A		5		ULA (RFC 4193)
  * 2001::/32		N/A		6		Teredo (RFC 4380)
+ * 2001:10::/28		N/A		7		ORCHID (RFC 4843)
  *
  * Note: 0xffffffff is used if we do not have any policies.
  */
@@ -85,6 +86,10 @@ static const __initdata struct ip6addrlbl_init_table
 		.prefix = &(struct in6_addr){{{ 0x20, 0x01 }}},
 		.prefixlen = 32,
 		.label = 6,
+	},{	/* 2001:10::/28 */
+		.prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}},
+		.prefixlen = 28,
+		.label = 7,
 	},{	/* ::ffff:0:0 */
 		.prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}},
 		.prefixlen = 96,
@@ -161,7 +166,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
 	rcu_read_unlock();
 
 	ADDRLABEL(KERN_DEBUG "%s(addr=" NIP6_FMT ", type=%d, ifindex=%d) => %08x\n",
-			__FUNCTION__,
+			__func__,
 			NIP6(*addr), type, ifindex,
 			label);
 
@@ -177,7 +182,7 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
 	int addrtype;
 
 	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u)\n",
-			__FUNCTION__,
+			__func__,
 			NIP6(*prefix), prefixlen,
 			ifindex,
 			(unsigned int)label);
@@ -221,7 +226,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
 	int ret = 0;
 
 	ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
-			__FUNCTION__,
+			__func__,
 			newp, replace);
 
 	if (hlist_empty(&ip6addrlbl_table.head)) {
@@ -263,7 +268,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
 	int ret = 0;
 
 	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n",
-			__FUNCTION__,
+			__func__,
 			NIP6(*prefix), prefixlen,
 			ifindex,
 			(unsigned int)label,
@@ -289,7 +294,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
 	int ret = -ESRCH;
 
 	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
-			__FUNCTION__,
+			__func__,
 			NIP6(*prefix), prefixlen,
 			ifindex);
 
@@ -313,7 +318,7 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
 	int ret;
 
 	ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n",
-			__FUNCTION__,
+			__func__,
 			NIP6(*prefix), prefixlen,
 			ifindex);
 
@@ -330,7 +335,7 @@ static __init int ip6addrlbl_init(void)
 	int err = 0;
 	int i;
 
-	ADDRLABEL(KERN_DEBUG "%s()\n", __FUNCTION__);
+	ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
 
 	for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
 		int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix,
@@ -359,7 +364,7 @@ static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
 static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
 			     void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ifaddrlblmsg *ifal;
 	struct nlattr *tb[IFAL_MAX+1];
 	struct in6_addr *pfx;
@@ -447,7 +452,7 @@ static int ip6addrlbl_fill(struct sk_buff *skb,
 
 static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct ip6addrlbl_entry *p;
 	struct hlist_node *pos;
 	int idx = 0, s_idx = cb->args[0];
@@ -485,7 +490,7 @@ static inline int ip6addrlbl_msgsize(void)
 static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 			  void *arg)
 {
-	struct net *net = in_skb->sk->sk_net;
+	struct net *net = sock_net(in_skb->sk);
 	struct ifaddrlblmsg *ifal;
 	struct nlattr *tb[IFAL_MAX+1];
 	struct in6_addr *addr;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index f0aa97738746..1731b0abf7f5 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -92,9 +92,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol)
 	int try_loading_module = 0;
 	int err;
 
-	if (net != &init_net)
-		return -EAFNOSUPPORT;
-
 	if (sock->type != SOCK_RAW &&
 	    sock->type != SOCK_DGRAM &&
 	    !inet_ehash_secret)
@@ -248,6 +245,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	struct sock *sk = sock->sk;
 	struct inet_sock *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net *net = sock_net(sk);
 	__be32 v4addr = 0;
 	unsigned short snum;
 	int addr_type = 0;
@@ -278,7 +276,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	/* Check if the address belongs to the host. */
 	if (addr_type == IPV6_ADDR_MAPPED) {
 		v4addr = addr->sin6_addr.s6_addr32[3];
-		if (inet_addr_type(&init_net, v4addr) != RTN_LOCAL) {
+		if (inet_addr_type(net, v4addr) != RTN_LOCAL) {
 			err = -EADDRNOTAVAIL;
 			goto out;
 		}
@@ -300,7 +298,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 					err = -EINVAL;
 					goto out;
 				}
-				dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+				dev = dev_get_by_index(net, sk->sk_bound_dev_if);
 				if (!dev) {
 					err = -ENODEV;
 					goto out;
@@ -312,7 +310,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 			 */
 			v4addr = LOOPBACK4_IPV6;
 			if (!(addr_type & IPV6_ADDR_MULTICAST))	{
-				if (!ipv6_chk_addr(&init_net, &addr->sin6_addr,
+				if (!ipv6_chk_addr(net, &addr->sin6_addr,
 						   dev, 0)) {
 					if (dev)
 						dev_put(dev);
@@ -440,6 +438,7 @@ EXPORT_SYMBOL(inet6_getname);
 int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
+	struct net *net = sock_net(sk);
 
 	switch(cmd)
 	{
@@ -452,14 +451,14 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	case SIOCADDRT:
 	case SIOCDELRT:
 
-		return(ipv6_route_ioctl(cmd,(void __user *)arg));
+		return(ipv6_route_ioctl(net, cmd, (void __user *)arg));
 
 	case SIOCSIFADDR:
-		return addrconf_add_ifaddr((void __user *) arg);
+		return addrconf_add_ifaddr(net, (void __user *) arg);
 	case SIOCDIFADDR:
-		return addrconf_del_ifaddr((void __user *) arg);
+		return addrconf_del_ifaddr(net, (void __user *) arg);
 	case SIOCSIFDSTADDR:
-		return addrconf_set_dstaddr((void __user *) arg);
+		return addrconf_set_dstaddr(net, (void __user *) arg);
 	default:
 		if (!sk->sk_prot->ioctl)
 			return -ENOIOCTLCMD;
@@ -678,6 +677,129 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb)
 
 EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
 
+static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb,
+						    int proto)
+{
+	struct inet6_protocol *ops = NULL;
+
+	for (;;) {
+		struct ipv6_opt_hdr *opth;
+		int len;
+
+		if (proto != NEXTHDR_HOP) {
+			ops = rcu_dereference(inet6_protos[proto]);
+
+			if (unlikely(!ops))
+				break;
+
+			if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
+				break;
+		}
+
+		if (unlikely(!pskb_may_pull(skb, 8)))
+			break;
+
+		opth = (void *)skb->data;
+		len = ipv6_optlen(opth);
+
+		if (unlikely(!pskb_may_pull(skb, len)))
+			break;
+
+		proto = opth->nexthdr;
+		__skb_pull(skb, len);
+	}
+
+	return ops;
+}
+
+static int ipv6_gso_send_check(struct sk_buff *skb)
+{
+	struct ipv6hdr *ipv6h;
+	struct inet6_protocol *ops;
+	int err = -EINVAL;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+		goto out;
+
+	ipv6h = ipv6_hdr(skb);
+	__skb_pull(skb, sizeof(*ipv6h));
+	err = -EPROTONOSUPPORT;
+
+	rcu_read_lock();
+	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+	if (likely(ops && ops->gso_send_check)) {
+		skb_reset_transport_header(skb);
+		err = ops->gso_send_check(skb);
+	}
+	rcu_read_unlock();
+
+out:
+	return err;
+}
+
+static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
+{
+	struct sk_buff *segs = ERR_PTR(-EINVAL);
+	struct ipv6hdr *ipv6h;
+	struct inet6_protocol *ops;
+
+	if (!(features & NETIF_F_V6_CSUM))
+		features &= ~NETIF_F_SG;
+
+	if (unlikely(skb_shinfo(skb)->gso_type &
+		     ~(SKB_GSO_UDP |
+		       SKB_GSO_DODGY |
+		       SKB_GSO_TCP_ECN |
+		       SKB_GSO_TCPV6 |
+		       0)))
+		goto out;
+
+	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
+		goto out;
+
+	ipv6h = ipv6_hdr(skb);
+	__skb_pull(skb, sizeof(*ipv6h));
+	segs = ERR_PTR(-EPROTONOSUPPORT);
+
+	rcu_read_lock();
+	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
+	if (likely(ops && ops->gso_segment)) {
+		skb_reset_transport_header(skb);
+		segs = ops->gso_segment(skb, features);
+	}
+	rcu_read_unlock();
+
+	if (unlikely(IS_ERR(segs)))
+		goto out;
+
+	for (skb = segs; skb; skb = skb->next) {
+		ipv6h = ipv6_hdr(skb);
+		ipv6h->payload_len = htons(skb->len - skb->mac_len -
+					   sizeof(*ipv6h));
+	}
+
+out:
+	return segs;
+}
+
+static struct packet_type ipv6_packet_type = {
+	.type = __constant_htons(ETH_P_IPV6),
+	.func = ipv6_rcv,
+	.gso_send_check = ipv6_gso_send_check,
+	.gso_segment = ipv6_gso_segment,
+};
+
+static int __init ipv6_packet_init(void)
+{
+	dev_add_pack(&ipv6_packet_type);
+	return 0;
+}
+
+static void ipv6_packet_cleanup(void)
+{
+	dev_remove_pack(&ipv6_packet_type);
+}
+
 static int __init init_ipv6_mibs(void)
 {
 	if (snmp_mib_init((void **)ipv6_statistics,
@@ -720,6 +842,8 @@ static void cleanup_ipv6_mibs(void)
 
 static int inet6_net_init(struct net *net)
 {
+	int err = 0;
+
 	net->ipv6.sysctl.bindv6only = 0;
 	net->ipv6.sysctl.flush_delay = 0;
 	net->ipv6.sysctl.ip6_rt_max_size = 4096;
@@ -731,12 +855,36 @@ static int inet6_net_init(struct net *net)
 	net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40;
 	net->ipv6.sysctl.icmpv6_time = 1*HZ;
 
-	return 0;
+#ifdef CONFIG_PROC_FS
+	err = udp6_proc_init(net);
+	if (err)
+		goto out;
+	err = tcp6_proc_init(net);
+	if (err)
+		goto proc_tcp6_fail;
+	err = ac6_proc_init(net);
+	if (err)
+		goto proc_ac6_fail;
+out:
+#endif
+	return err;
+
+#ifdef CONFIG_PROC_FS
+proc_ac6_fail:
+	tcp6_proc_exit(net);
+proc_tcp6_fail:
+	udp6_proc_exit(net);
+	goto out;
+#endif
 }
 
 static void inet6_net_exit(struct net *net)
 {
-	return;
+#ifdef CONFIG_PROC_FS
+	udp6_proc_exit(net);
+	tcp6_proc_exit(net);
+	ac6_proc_exit(net);
+#endif
 }
 
 static struct pernet_operations inet6_net_ops = {
@@ -802,19 +950,13 @@ static int __init inet6_init(void)
 	err = register_pernet_subsys(&inet6_net_ops);
 	if (err)
 		goto register_pernet_fail;
-
-#ifdef CONFIG_SYSCTL
-	err = ipv6_sysctl_register();
-	if (err)
-		goto sysctl_fail;
-#endif
-	err = icmpv6_init(&inet6_family_ops);
+	err = icmpv6_init();
 	if (err)
 		goto icmp_fail;
-	err = ndisc_init(&inet6_family_ops);
+	err = ndisc_init();
 	if (err)
 		goto ndisc_fail;
-	err = igmp6_init(&inet6_family_ops);
+	err = igmp6_init();
 	if (err)
 		goto igmp_fail;
 	err = ipv6_netfilter_init();
@@ -825,17 +967,10 @@ static int __init inet6_init(void)
 	err = -ENOMEM;
 	if (raw6_proc_init())
 		goto proc_raw6_fail;
-	if (tcp6_proc_init())
-		goto proc_tcp6_fail;
-	if (udp6_proc_init())
-		goto proc_udp6_fail;
 	if (udplite6_proc_init())
 		goto proc_udplite6_fail;
 	if (ipv6_misc_proc_init())
 		goto proc_misc6_fail;
-
-	if (ac6_proc_init())
-		goto proc_anycast6_fail;
 	if (if6_proc_init())
 		goto proc_if6_fail;
 #endif
@@ -874,9 +1009,19 @@ static int __init inet6_init(void)
 	err = ipv6_packet_init();
 	if (err)
 		goto ipv6_packet_fail;
+
+#ifdef CONFIG_SYSCTL
+	err = ipv6_sysctl_register();
+	if (err)
+		goto sysctl_fail;
+#endif
 out:
 	return err;
 
+#ifdef CONFIG_SYSCTL
+sysctl_fail:
+	ipv6_packet_cleanup();
+#endif
 ipv6_packet_fail:
 	tcpv6_exit();
 tcpv6_fail:
@@ -897,16 +1042,10 @@ ip6_route_fail:
 #ifdef CONFIG_PROC_FS
 	if6_proc_exit();
 proc_if6_fail:
-	ac6_proc_exit();
-proc_anycast6_fail:
 	ipv6_misc_proc_exit();
 proc_misc6_fail:
 	udplite6_proc_exit();
 proc_udplite6_fail:
-	udp6_proc_exit();
-proc_udp6_fail:
-	tcp6_proc_exit();
-proc_tcp6_fail:
 	raw6_proc_exit();
 proc_raw6_fail:
 #endif
@@ -918,10 +1057,6 @@ igmp_fail:
 ndisc_fail:
 	icmpv6_cleanup();
 icmp_fail:
-#ifdef CONFIG_SYSCTL
-	ipv6_sysctl_unregister();
-sysctl_fail:
-#endif
 	unregister_pernet_subsys(&inet6_net_ops);
 register_pernet_fail:
 	cleanup_ipv6_mibs();
@@ -949,6 +1084,9 @@ static void __exit inet6_exit(void)
 	/* Disallow any further netlink messages */
 	rtnl_unregister_all(PF_INET6);
 
+#ifdef CONFIG_SYSCTL
+	ipv6_sysctl_unregister();
+#endif
 	udpv6_exit();
 	udplitev6_exit();
 	tcpv6_exit();
@@ -964,11 +1102,8 @@ static void __exit inet6_exit(void)
 
 	/* Cleanup code parts. */
 	if6_proc_exit();
-	ac6_proc_exit();
 	ipv6_misc_proc_exit();
 	udplite6_proc_exit();
-	udp6_proc_exit();
-	tcp6_proc_exit();
 	raw6_proc_exit();
 #endif
 	ipv6_netfilter_fini();
@@ -976,9 +1111,7 @@ static void __exit inet6_exit(void)
 	ndisc_cleanup();
 	icmpv6_cleanup();
 	rawv6_exit();
-#ifdef CONFIG_SYSCTL
-	ipv6_sysctl_unregister();
-#endif
+
 	unregister_pernet_subsys(&inet6_net_ops);
 	cleanup_ipv6_mibs();
 	proto_unregister(&rawv6_prot);
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 9c7f83fbc3a1..463bd95d6b13 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -82,6 +82,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 	struct net_device *dev = NULL;
 	struct inet6_dev *idev;
 	struct ipv6_ac_socklist *pac;
+	struct net *net = sock_net(sk);
 	int	ishost = !ipv6_devconf.forwarding;
 	int	err = 0;
 
@@ -89,7 +90,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 		return -EPERM;
 	if (ipv6_addr_is_multicast(addr))
 		return -EINVAL;
-	if (ipv6_chk_addr(&init_net, addr, NULL, 0))
+	if (ipv6_chk_addr(net, addr, NULL, 0))
 		return -EINVAL;
 
 	pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL);
@@ -101,7 +102,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 	if (ifindex == 0) {
 		struct rt6_info *rt;
 
-		rt = rt6_lookup(addr, NULL, 0, 0);
+		rt = rt6_lookup(net, addr, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
 			dev_hold(dev);
@@ -112,10 +113,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 		} else {
 			/* router, no matching interface: just pick one */
 
-			dev = dev_get_by_flags(&init_net, IFF_UP, IFF_UP|IFF_LOOPBACK);
+			dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK);
 		}
 	} else
-		dev = dev_get_by_index(&init_net, ifindex);
+		dev = dev_get_by_index(net, ifindex);
 
 	if (dev == NULL) {
 		err = -ENODEV;
@@ -176,6 +177,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct net_device *dev;
 	struct ipv6_ac_socklist *pac, *prev_pac;
+	struct net *net = sock_net(sk);
 
 	write_lock_bh(&ipv6_sk_ac_lock);
 	prev_pac = NULL;
@@ -196,7 +198,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 
 	write_unlock_bh(&ipv6_sk_ac_lock);
 
-	dev = dev_get_by_index(&init_net, pac->acl_ifindex);
+	dev = dev_get_by_index(net, pac->acl_ifindex);
 	if (dev) {
 		ipv6_dev_ac_dec(dev, &pac->acl_addr);
 		dev_put(dev);
@@ -210,6 +212,7 @@ void ipv6_sock_ac_close(struct sock *sk)
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct net_device *dev = NULL;
 	struct ipv6_ac_socklist *pac;
+	struct net *net = sock_net(sk);
 	int	prev_index;
 
 	write_lock_bh(&ipv6_sk_ac_lock);
@@ -224,7 +227,7 @@ void ipv6_sock_ac_close(struct sock *sk)
 		if (pac->acl_ifindex != prev_index) {
 			if (dev)
 				dev_put(dev);
-			dev = dev_get_by_index(&init_net, pac->acl_ifindex);
+			dev = dev_get_by_index(net, pac->acl_ifindex);
 			prev_index = pac->acl_ifindex;
 		}
 		if (dev)
@@ -422,14 +425,15 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
 /*
  *	check if given interface (or any, if dev==0) has this anycast address
  */
-int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
+int ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
+			struct in6_addr *addr)
 {
 	int found = 0;
 
 	if (dev)
 		return ipv6_chk_acast_dev(dev, addr);
 	read_lock(&dev_base_lock);
-	for_each_netdev(&init_net, dev)
+	for_each_netdev(net, dev)
 		if (ipv6_chk_acast_dev(dev, addr)) {
 			found = 1;
 			break;
@@ -441,6 +445,7 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
 
 #ifdef CONFIG_PROC_FS
 struct ac6_iter_state {
+	struct seq_net_private p;
 	struct net_device *dev;
 	struct inet6_dev *idev;
 };
@@ -451,9 +456,10 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
 {
 	struct ifacaddr6 *im = NULL;
 	struct ac6_iter_state *state = ac6_seq_private(seq);
+	struct net *net = seq_file_net(seq);
 
 	state->idev = NULL;
-	for_each_netdev(&init_net, state->dev) {
+	for_each_netdev(net, state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (!idev)
@@ -551,8 +557,8 @@ static const struct seq_operations ac6_seq_ops = {
 
 static int ac6_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ac6_seq_ops,
-			sizeof(struct ac6_iter_state));
+	return seq_open_net(inode, file, &ac6_seq_ops,
+			    sizeof(struct ac6_iter_state));
 }
 
 static const struct file_operations ac6_seq_fops = {
@@ -560,20 +566,20 @@ static const struct file_operations ac6_seq_fops = {
 	.open		=	ac6_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
 };
 
-int __init ac6_proc_init(void)
+int ac6_proc_init(struct net *net)
 {
-	if (!proc_net_fops_create(&init_net, "anycast6", S_IRUGO, &ac6_seq_fops))
+	if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops))
 		return -ENOMEM;
 
 	return 0;
 }
 
-void ac6_proc_exit(void)
+void ac6_proc_exit(struct net *net)
 {
-	proc_net_remove(&init_net, "anycast6");
+	proc_net_remove(net, "anycast6");
 }
 #endif
 
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 695c0ca8a417..cac580749ebe 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -29,24 +29,22 @@ struct fib6_rule
 	u8			tclass;
 };
 
-static struct fib_rules_ops fib6_rules_ops;
-
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
-				   pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+				   int flags, pol_lookup_t lookup)
 {
 	struct fib_lookup_arg arg = {
 		.lookup_ptr = lookup,
 	};
 
-	fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg);
+	fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg);
 	if (arg.rule)
 		fib_rule_put(arg.rule);
 
 	if (arg.result)
 		return arg.result;
 
-	dst_hold(&ip6_null_entry.u.dst);
-	return &ip6_null_entry.u.dst;
+	dst_hold(&net->ipv6.ip6_null_entry->u.dst);
+	return &net->ipv6.ip6_null_entry->u.dst;
 }
 
 static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
@@ -54,28 +52,29 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 {
 	struct rt6_info *rt = NULL;
 	struct fib6_table *table;
+	struct net *net = rule->fr_net;
 	pol_lookup_t lookup = arg->lookup_ptr;
 
 	switch (rule->action) {
 	case FR_ACT_TO_TBL:
 		break;
 	case FR_ACT_UNREACHABLE:
-		rt = &ip6_null_entry;
+		rt = net->ipv6.ip6_null_entry;
 		goto discard_pkt;
 	default:
 	case FR_ACT_BLACKHOLE:
-		rt = &ip6_blk_hole_entry;
+		rt = net->ipv6.ip6_blk_hole_entry;
 		goto discard_pkt;
 	case FR_ACT_PROHIBIT:
-		rt = &ip6_prohibit_entry;
+		rt = net->ipv6.ip6_prohibit_entry;
 		goto discard_pkt;
 	}
 
-	table = fib6_get_table(rule->table);
+	table = fib6_get_table(net, rule->table);
 	if (table)
-		rt = lookup(table, flp, flags);
+		rt = lookup(net, table, flp, flags);
 
-	if (rt != &ip6_null_entry) {
+	if (rt != net->ipv6.ip6_null_entry) {
 		struct fib6_rule *r = (struct fib6_rule *)rule;
 
 		/*
@@ -85,8 +84,18 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp,
 		if ((rule->flags & FIB_RULE_FIND_SADDR) &&
 		    r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) {
 			struct in6_addr saddr;
-			if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst,
-					   &saddr))
+			unsigned int srcprefs = 0;
+
+			if (flags & RT6_LOOKUP_F_SRCPREF_TMP)
+				srcprefs |= IPV6_PREFER_SRC_TMP;
+			if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC)
+				srcprefs |= IPV6_PREFER_SRC_PUBLIC;
+			if (flags & RT6_LOOKUP_F_SRCPREF_COA)
+				srcprefs |= IPV6_PREFER_SRC_COA;
+
+			if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+					       &flp->fl6_dst, srcprefs,
+					       &saddr))
 				goto again;
 			if (!ipv6_prefix_equal(&saddr, &r->src.addr,
 					       r->src.plen))
@@ -145,13 +154,14 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 			       struct nlattr **tb)
 {
 	int err = -EINVAL;
+	struct net *net = sock_net(skb->sk);
 	struct fib6_rule *rule6 = (struct fib6_rule *) rule;
 
 	if (rule->action == FR_ACT_TO_TBL) {
 		if (rule->table == RT6_TABLE_UNSPEC)
 			goto errout;
 
-		if (fib6_new_table(rule->table) == NULL) {
+		if (fib6_new_table(net, rule->table) == NULL) {
 			err = -ENOBUFS;
 			goto errout;
 		}
@@ -234,7 +244,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
 	       + nla_total_size(16); /* src */
 }
 
-static struct fib_rules_ops fib6_rules_ops = {
+static struct fib_rules_ops fib6_rules_ops_template = {
 	.family			= AF_INET6,
 	.rule_size		= sizeof(struct fib6_rule),
 	.addr_size		= sizeof(struct in6_addr),
@@ -247,45 +257,64 @@ static struct fib_rules_ops fib6_rules_ops = {
 	.nlmsg_payload		= fib6_rule_nlmsg_payload,
 	.nlgroup		= RTNLGRP_IPV6_RULE,
 	.policy			= fib6_rule_policy,
-	.rules_list		= LIST_HEAD_INIT(fib6_rules_ops.rules_list),
 	.owner			= THIS_MODULE,
 	.fro_net		= &init_net,
 };
 
-static int __init fib6_default_rules_init(void)
+static int fib6_rules_net_init(struct net *net)
 {
-	int err;
+	int err = -ENOMEM;
 
-	err = fib_default_rule_add(&fib6_rules_ops, 0,
-				   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
-	if (err < 0)
-		return err;
-	err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0);
-	if (err < 0)
-		return err;
-	return 0;
-}
+	net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template,
+					   sizeof(*net->ipv6.fib6_rules_ops),
+					   GFP_KERNEL);
+	if (!net->ipv6.fib6_rules_ops)
+		goto out;
 
-int __init fib6_rules_init(void)
-{
-	int ret;
+	net->ipv6.fib6_rules_ops->fro_net = net;
+	INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list);
 
-	ret = fib6_default_rules_init();
-	if (ret)
-		goto out;
+	err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0,
+				   RT6_TABLE_LOCAL, FIB_RULE_PERMANENT);
+	if (err)
+		goto out_fib6_rules_ops;
 
-	ret = fib_rules_register(&fib6_rules_ops);
-	if (ret)
-		goto out_default_rules_init;
+	err = fib_default_rule_add(net->ipv6.fib6_rules_ops,
+				   0x7FFE, RT6_TABLE_MAIN, 0);
+	if (err)
+		goto out_fib6_default_rule_add;
+
+	err = fib_rules_register(net->ipv6.fib6_rules_ops);
+	if (err)
+		goto out_fib6_default_rule_add;
 out:
-	return ret;
+	return err;
 
-out_default_rules_init:
-	fib_rules_cleanup_ops(&fib6_rules_ops);
+out_fib6_default_rule_add:
+	fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops);
+out_fib6_rules_ops:
+	kfree(net->ipv6.fib6_rules_ops);
 	goto out;
 }
 
+static void fib6_rules_net_exit(struct net *net)
+{
+	fib_rules_unregister(net->ipv6.fib6_rules_ops);
+	kfree(net->ipv6.fib6_rules_ops);
+}
+
+static struct pernet_operations fib6_rules_net_ops = {
+	.init = fib6_rules_net_init,
+	.exit = fib6_rules_net_exit,
+};
+
+int __init fib6_rules_init(void)
+{
+	return register_pernet_subsys(&fib6_rules_net_ops);
+}
+
+
 void fib6_rules_cleanup(void)
 {
-	fib_rules_unregister(&fib6_rules_ops);
+	return unregister_pernet_subsys(&fib6_rules_net_ops);
 }
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index f204a7275a0d..227ce3d2339d 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -80,8 +80,10 @@ EXPORT_SYMBOL(icmpv6msg_statistics);
  *
  *	On SMP we have one ICMP socket per-cpu.
  */
-static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL;
-#define icmpv6_socket	__get_cpu_var(__icmpv6_socket)
+static inline struct sock *icmpv6_sk(struct net *net)
+{
+	return net->ipv6.icmp_sk[smp_processor_id()];
+}
 
 static int icmpv6_rcv(struct sk_buff *skb);
 
@@ -90,11 +92,11 @@ static struct inet6_protocol icmpv6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static __inline__ int icmpv6_xmit_lock(void)
+static __inline__ int icmpv6_xmit_lock(struct sock *sk)
 {
 	local_bh_disable();
 
-	if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) {
+	if (unlikely(!spin_trylock(&sk->sk_lock.slock))) {
 		/* This can happen if the output path (f.e. SIT or
 		 * ip6ip6 tunnel) signals dst_link_failure() for an
 		 * outgoing ICMP6 packet.
@@ -105,9 +107,9 @@ static __inline__ int icmpv6_xmit_lock(void)
 	return 0;
 }
 
-static __inline__ void icmpv6_xmit_unlock(void)
+static __inline__ void icmpv6_xmit_unlock(struct sock *sk)
 {
-	spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock);
+	spin_unlock_bh(&sk->sk_lock.slock);
 }
 
 /*
@@ -161,6 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
 				     struct flowi *fl)
 {
 	struct dst_entry *dst;
+	struct net *net = sock_net(sk);
 	int res = 0;
 
 	/* Informational messages are not limited. */
@@ -176,7 +179,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
 	 * XXX: perhaps the expire for routing entries cloned by
 	 * this lookup should be more aggressive (not longer than timeout).
 	 */
-	dst = ip6_route_output(sk, fl);
+	dst = ip6_route_output(net, sk, fl);
 	if (dst->error) {
 		IP6_INC_STATS(ip6_dst_idev(dst),
 			      IPSTATS_MIB_OUTNOROUTES);
@@ -184,7 +187,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
 		res = 1;
 	} else {
 		struct rt6_info *rt = (struct rt6_info *)dst;
-		int tmo = init_net.ipv6.sysctl.icmpv6_time;
+		int tmo = net->ipv6.sysctl.icmpv6_time;
 
 		/* Give more bandwidth to wider prefixes. */
 		if (rt->rt6i_dst.plen < 128)
@@ -303,6 +306,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {}
 void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 		 struct net_device *dev)
 {
+	struct net *net = dev_net(skb->dev);
 	struct inet6_dev *idev = NULL;
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct sock *sk;
@@ -332,7 +336,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 	 */
 	addr_type = ipv6_addr_type(&hdr->daddr);
 
-	if (ipv6_chk_addr(&init_net, &hdr->daddr, skb->dev, 0))
+	if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0))
 		saddr = &hdr->daddr;
 
 	/*
@@ -389,12 +393,12 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
 	fl.fl_icmp_code = code;
 	security_skb_classify_flow(skb, &fl);
 
-	if (icmpv6_xmit_lock())
-		return;
-
-	sk = icmpv6_socket->sk;
+	sk = icmpv6_sk(net);
 	np = inet6_sk(sk);
 
+	if (icmpv6_xmit_lock(sk))
+		return;
+
 	if (!icmpv6_xrlim_allow(sk, type, &fl))
 		goto out;
 
@@ -460,9 +464,7 @@ route_done:
 	else
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
-		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
-	if (hlimit < 0)
-		hlimit = ipv6_get_hoplimit(dst->dev);
+		hlimit = ip6_dst_hoplimit(dst);
 
 	tclass = np->tclass;
 	if (tclass < 0)
@@ -498,13 +500,14 @@ out_put:
 out_dst_release:
 	dst_release(dst);
 out:
-	icmpv6_xmit_unlock();
+	icmpv6_xmit_unlock(sk);
 }
 
 EXPORT_SYMBOL(icmpv6_send);
 
 static void icmpv6_echo_reply(struct sk_buff *skb)
 {
+	struct net *net = dev_net(skb->dev);
 	struct sock *sk;
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *np;
@@ -535,12 +538,12 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 	fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
 	security_skb_classify_flow(skb, &fl);
 
-	if (icmpv6_xmit_lock())
-		return;
-
-	sk = icmpv6_socket->sk;
+	sk = icmpv6_sk(net);
 	np = inet6_sk(sk);
 
+	if (icmpv6_xmit_lock(sk))
+		return;
+
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
@@ -555,9 +558,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 	else
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
-		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
-	if (hlimit < 0)
-		hlimit = ipv6_get_hoplimit(dst->dev);
+		hlimit = ip6_dst_hoplimit(dst);
 
 	tclass = np->tclass;
 	if (tclass < 0)
@@ -584,7 +585,7 @@ out_put:
 		in6_dev_put(idev);
 	dst_release(dst);
 out:
-	icmpv6_xmit_unlock();
+	icmpv6_xmit_unlock(sk);
 }
 
 static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
@@ -775,19 +776,41 @@ drop_no_count:
 	return 0;
 }
 
+void icmpv6_flow_init(struct sock *sk, struct flowi *fl,
+		      u8 type,
+		      const struct in6_addr *saddr,
+		      const struct in6_addr *daddr,
+		      int oif)
+{
+	memset(fl, 0, sizeof(*fl));
+	ipv6_addr_copy(&fl->fl6_src, saddr);
+	ipv6_addr_copy(&fl->fl6_dst, daddr);
+	fl->proto	 	= IPPROTO_ICMPV6;
+	fl->fl_icmp_type	= type;
+	fl->fl_icmp_code	= 0;
+	fl->oif			= oif;
+	security_sk_classify_flow(sk, fl);
+}
+
 /*
- * Special lock-class for __icmpv6_socket:
+ * Special lock-class for __icmpv6_sk:
  */
 static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
 
-int __init icmpv6_init(struct net_proto_family *ops)
+static int __net_init icmpv6_sk_init(struct net *net)
 {
 	struct sock *sk;
 	int err, i, j;
 
+	net->ipv6.icmp_sk =
+		kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL);
+	if (net->ipv6.icmp_sk == NULL)
+		return -ENOMEM;
+
 	for_each_possible_cpu(i) {
+		struct socket *sock;
 		err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
-				       &per_cpu(__icmpv6_socket, i));
+				       &sock);
 		if (err < 0) {
 			printk(KERN_ERR
 			       "Failed to initialize the ICMP6 control socket "
@@ -796,12 +819,14 @@ int __init icmpv6_init(struct net_proto_family *ops)
 			goto fail;
 		}
 
-		sk = per_cpu(__icmpv6_socket, i)->sk;
+		net->ipv6.icmp_sk[i] = sk = sock->sk;
+		sk_change_net(sk, net);
+
 		sk->sk_allocation = GFP_ATOMIC;
 		/*
 		 * Split off their lock-class, because sk->sk_dst_lock
 		 * gets used from softirqs, which is safe for
-		 * __icmpv6_socket (because those never get directly used
+		 * __icmpv6_sk (because those never get directly used
 		 * via userspace syscalls), but unsafe for normal sockets.
 		 */
 		lockdep_set_class(&sk->sk_dst_lock,
@@ -815,36 +840,56 @@ int __init icmpv6_init(struct net_proto_family *ops)
 
 		sk->sk_prot->unhash(sk);
 	}
-
-
-	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
-		printk(KERN_ERR "Failed to register ICMP6 protocol\n");
-		err = -EAGAIN;
-		goto fail;
-	}
-
 	return 0;
 
  fail:
-	for (j = 0; j < i; j++) {
-		if (!cpu_possible(j))
-			continue;
-		sock_release(per_cpu(__icmpv6_socket, j));
-	}
-
+	for (j = 0; j < i; j++)
+		sk_release_kernel(net->ipv6.icmp_sk[j]);
+	kfree(net->ipv6.icmp_sk);
 	return err;
 }
 
-void icmpv6_cleanup(void)
+static void __net_exit icmpv6_sk_exit(struct net *net)
 {
 	int i;
 
 	for_each_possible_cpu(i) {
-		sock_release(per_cpu(__icmpv6_socket, i));
+		sk_release_kernel(net->ipv6.icmp_sk[i]);
 	}
+	kfree(net->ipv6.icmp_sk);
+}
+
+static struct pernet_operations icmpv6_sk_ops = {
+       .init = icmpv6_sk_init,
+       .exit = icmpv6_sk_exit,
+};
+
+int __init icmpv6_init(void)
+{
+	int err;
+
+	err = register_pernet_subsys(&icmpv6_sk_ops);
+	if (err < 0)
+		return err;
+
+	err = -EAGAIN;
+	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
+		goto fail;
+	return 0;
+
+fail:
+	printk(KERN_ERR "Failed to register ICMP6 protocol\n");
+	unregister_pernet_subsys(&icmpv6_sk_ops);
+	return err;
+}
+
+void icmpv6_cleanup(void)
+{
+	unregister_pernet_subsys(&icmpv6_sk_ops);
 	inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
 }
 
+
 static const struct icmp6_err {
 	int err;
 	int fatal;
@@ -925,6 +970,10 @@ struct ctl_table *ipv6_icmp_sysctl_init(struct net *net)
 	table = kmemdup(ipv6_icmp_table_template,
 			sizeof(ipv6_icmp_table_template),
 			GFP_KERNEL);
+
+	if (table)
+		table[0].data = &net->ipv6.sysctl.icmpv6_time;
+
 	return table;
 }
 #endif
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 99fd25f7f005..580014aea4d6 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -24,7 +24,7 @@
 
 void __inet6_hash(struct sock *sk)
 {
-	struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo;
+	struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
 	struct hlist_head *list;
 	rwlock_t *lock;
 
@@ -43,7 +43,7 @@ void __inet6_hash(struct sock *sk)
 	}
 
 	__sk_add_node(sk, list);
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock(lock);
 }
 EXPORT_SYMBOL(__inet6_hash);
@@ -105,7 +105,7 @@ struct sock *inet6_lookup_listener(struct net *net,
 
 	read_lock(&hashinfo->lhash_lock);
 	sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
-		if (sk->sk_net == net && inet_sk(sk)->num == hnum &&
+		if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum &&
 				sk->sk_family == PF_INET6) {
 			const struct ipv6_pinfo *np = inet6_sk(sk);
 
@@ -172,7 +172,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
 	struct sock *sk2;
 	const struct hlist_node *node;
 	struct inet_timewait_sock *tw;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 
 	prefetch(head->chain.first);
 	write_lock(lock);
@@ -204,7 +204,7 @@ unique:
 	BUG_TRAP(sk_unhashed(sk));
 	__sk_add_node(sk, &head->chain);
 	sk->sk_hash = hash;
-	sock_prot_inuse_add(sk->sk_prot, 1);
+	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
 	write_unlock(lock);
 
 	if (twp != NULL) {
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index bab72b6f1444..b3f6e03c454c 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -48,8 +48,6 @@
 #define RT6_TRACE(x...) do { ; } while (0)
 #endif
 
-struct rt6_statistics	rt6_stats;
-
 static struct kmem_cache * fib6_node_kmem __read_mostly;
 
 enum fib_walk_state_t
@@ -66,6 +64,7 @@ enum fib_walk_state_t
 struct fib6_cleaner_t
 {
 	struct fib6_walker_t w;
+	struct net *net;
 	int (*func)(struct rt6_info *, void *arg);
 	void *arg;
 };
@@ -78,9 +77,10 @@ static DEFINE_RWLOCK(fib6_walker_lock);
 #define FWS_INIT FWS_L
 #endif
 
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
-static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
-static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+			      struct rt6_info *rt);
+static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn);
+static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn);
 static int fib6_walk(struct fib6_walker_t *w);
 static int fib6_walk_continue(struct fib6_walker_t *w);
 
@@ -93,7 +93,7 @@ static int fib6_walk_continue(struct fib6_walker_t *w);
 
 static __u32 rt_sernum;
 
-static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
+static void fib6_gc_timer_cb(unsigned long arg);
 
 static struct fib6_walker_t fib6_walker_list = {
 	.prev	= &fib6_walker_list,
@@ -166,22 +166,13 @@ static __inline__ void rt6_release(struct rt6_info *rt)
 		dst_free(&rt->u.dst);
 }
 
-static struct fib6_table fib6_main_tbl = {
-	.tb6_id		= RT6_TABLE_MAIN,
-	.tb6_root	= {
-		.leaf		= &ip6_null_entry,
-		.fn_flags	= RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
-	},
-};
-
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
 #define FIB_TABLE_HASHSZ 256
 #else
 #define FIB_TABLE_HASHSZ 1
 #endif
-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
 
-static void fib6_link_table(struct fib6_table *tb)
+static void fib6_link_table(struct net *net, struct fib6_table *tb)
 {
 	unsigned int h;
 
@@ -197,52 +188,46 @@ static void fib6_link_table(struct fib6_table *tb)
 	 * No protection necessary, this is the only list mutatation
 	 * operation, tables never disappear once they exist.
 	 */
-	hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
+	hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]);
 }
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-static struct fib6_table fib6_local_tbl = {
-	.tb6_id		= RT6_TABLE_LOCAL,
-	.tb6_root 	= {
-		.leaf		= &ip6_null_entry,
-		.fn_flags	= RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
-	},
-};
 
-static struct fib6_table *fib6_alloc_table(u32 id)
+static struct fib6_table *fib6_alloc_table(struct net *net, u32 id)
 {
 	struct fib6_table *table;
 
 	table = kzalloc(sizeof(*table), GFP_ATOMIC);
 	if (table != NULL) {
 		table->tb6_id = id;
-		table->tb6_root.leaf = &ip6_null_entry;
+		table->tb6_root.leaf = net->ipv6.ip6_null_entry;
 		table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
 	}
 
 	return table;
 }
 
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
 {
 	struct fib6_table *tb;
 
 	if (id == 0)
 		id = RT6_TABLE_MAIN;
-	tb = fib6_get_table(id);
+	tb = fib6_get_table(net, id);
 	if (tb)
 		return tb;
 
-	tb = fib6_alloc_table(id);
+	tb = fib6_alloc_table(net, id);
 	if (tb != NULL)
-		fib6_link_table(tb);
+		fib6_link_table(net, tb);
 
 	return tb;
 }
 
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
 {
 	struct fib6_table *tb;
+	struct hlist_head *head;
 	struct hlist_node *node;
 	unsigned int h;
 
@@ -250,7 +235,8 @@ struct fib6_table *fib6_get_table(u32 id)
 		id = RT6_TABLE_MAIN;
 	h = id & (FIB_TABLE_HASHSZ - 1);
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
+	head = &net->ipv6.fib_table_hash[h];
+	hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) {
 		if (tb->tb6_id == id) {
 			rcu_read_unlock();
 			return tb;
@@ -261,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id)
 	return NULL;
 }
 
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
 {
-	fib6_link_table(&fib6_main_tbl);
-	fib6_link_table(&fib6_local_tbl);
+	fib6_link_table(net, net->ipv6.fib6_main_tbl);
+	fib6_link_table(net, net->ipv6.fib6_local_tbl);
 }
-
 #else
 
-struct fib6_table *fib6_new_table(u32 id)
+struct fib6_table *fib6_new_table(struct net *net, u32 id)
 {
-	return fib6_get_table(id);
+	return fib6_get_table(net, id);
 }
 
-struct fib6_table *fib6_get_table(u32 id)
+struct fib6_table *fib6_get_table(struct net *net, u32 id)
 {
-	return &fib6_main_tbl;
+	  return net->ipv6.fib6_main_tbl;
 }
 
-struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
-				   pol_lookup_t lookup)
+struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl,
+				   int flags, pol_lookup_t lookup)
 {
-	return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
+	return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags);
 }
 
-static void __init fib6_tables_init(void)
+static void fib6_tables_init(struct net *net)
 {
-	fib6_link_table(&fib6_main_tbl);
+	fib6_link_table(net, net->ipv6.fib6_main_tbl);
 }
 
 #endif
@@ -361,18 +346,16 @@ end:
 
 static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	unsigned int h, s_h;
 	unsigned int e = 0, s_e;
 	struct rt6_rtnl_dump_arg arg;
 	struct fib6_walker_t *w;
 	struct fib6_table *tb;
 	struct hlist_node *node;
+	struct hlist_head *head;
 	int res = 0;
 
-	if (net != &init_net)
-		return 0;
-
 	s_h = cb->args[0];
 	s_e = cb->args[1];
 
@@ -401,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
 
 	for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
 		e = 0;
-		hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
+		head = &net->ipv6.fib_table_hash[h];
+		hlist_for_each_entry(tb, node, head, tb6_hlist) {
 			if (e < s_e)
 				goto next;
 			res = fib6_dump_table(tb, skb, cb);
@@ -667,29 +651,29 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
 	rt->rt6i_node = fn;
 	atomic_inc(&rt->rt6i_ref);
 	inet6_rt_notify(RTM_NEWROUTE, rt, info);
-	rt6_stats.fib_rt_entries++;
+	info->nl_net->ipv6.rt6_stats->fib_rt_entries++;
 
 	if ((fn->fn_flags & RTN_RTINFO) == 0) {
-		rt6_stats.fib_route_nodes++;
+		info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
 		fn->fn_flags |= RTN_RTINFO;
 	}
 
 	return 0;
 }
 
-static __inline__ void fib6_start_gc(struct rt6_info *rt)
+static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt)
 {
-	if (ip6_fib_timer.expires == 0 &&
+	if (net->ipv6.ip6_fib_timer->expires == 0 &&
 	    (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE)))
-		mod_timer(&ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
-void fib6_force_start_gc(void)
+void fib6_force_start_gc(struct net *net)
 {
-	if (ip6_fib_timer.expires == 0)
-		mod_timer(&ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+	if (net->ipv6.ip6_fib_timer->expires == 0)
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 }
 
 /*
@@ -733,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 			if (sfn == NULL)
 				goto st_failure;
 
-			sfn->leaf = &ip6_null_entry;
-			atomic_inc(&ip6_null_entry.rt6i_ref);
+			sfn->leaf = info->nl_net->ipv6.ip6_null_entry;
+			atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref);
 			sfn->fn_flags = RTN_ROOT;
 			sfn->fn_sernum = fib6_new_sernum();
 
@@ -776,9 +760,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
 	err = fib6_add_rt2node(fn, rt, info);
 
 	if (err == 0) {
-		fib6_start_gc(rt);
+		fib6_start_gc(info->nl_net, rt);
 		if (!(rt->rt6i_flags&RTF_CACHE))
-			fib6_prune_clones(pn, rt);
+			fib6_prune_clones(info->nl_net, pn, rt);
 	}
 
 out:
@@ -789,11 +773,11 @@ out:
 		 * super-tree leaf node we have to find a new one for it.
 		 */
 		if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) {
-			pn->leaf = fib6_find_prefix(pn);
+			pn->leaf = fib6_find_prefix(info->nl_net, pn);
 #if RT6_DEBUG >= 2
 			if (!pn->leaf) {
 				BUG_TRAP(pn->leaf != NULL);
-				pn->leaf = &ip6_null_entry;
+				pn->leaf = info->nl_net->ipv6.ip6_null_entry;
 			}
 #endif
 			atomic_inc(&pn->leaf->rt6i_ref);
@@ -809,7 +793,7 @@ out:
 	 */
 st_failure:
 	if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT)))
-		fib6_repair_tree(fn);
+		fib6_repair_tree(info->nl_net, fn);
 	dst_free(&rt->u.dst);
 	return err;
 #endif
@@ -975,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root,
  *
  */
 
-static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
+static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn)
 {
 	if (fn->fn_flags&RTN_ROOT)
-		return &ip6_null_entry;
+		return net->ipv6.ip6_null_entry;
 
 	while(fn) {
 		if(fn->left)
@@ -997,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
  *	is the node we want to try and remove.
  */
 
-static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
+static struct fib6_node *fib6_repair_tree(struct net *net,
+					   struct fib6_node *fn)
 {
 	int children;
 	int nstate;
@@ -1024,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
 		    || (children && fn->fn_flags&RTN_ROOT)
 #endif
 		    ) {
-			fn->leaf = fib6_find_prefix(fn);
+			fn->leaf = fib6_find_prefix(net, fn);
 #if RT6_DEBUG >= 2
 			if (fn->leaf==NULL) {
 				BUG_TRAP(fn->leaf);
-				fn->leaf = &ip6_null_entry;
+				fn->leaf = net->ipv6.ip6_null_entry;
 			}
 #endif
 			atomic_inc(&fn->leaf->rt6i_ref);
@@ -1101,14 +1086,15 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 {
 	struct fib6_walker_t *w;
 	struct rt6_info *rt = *rtp;
+	struct net *net = info->nl_net;
 
 	RT6_TRACE("fib6_del_route\n");
 
 	/* Unlink it */
 	*rtp = rt->u.dst.rt6_next;
 	rt->rt6i_node = NULL;
-	rt6_stats.fib_rt_entries--;
-	rt6_stats.fib_discarded_routes++;
+	net->ipv6.rt6_stats->fib_rt_entries--;
+	net->ipv6.rt6_stats->fib_discarded_routes++;
 
 	/* Reset round-robin state, if necessary */
 	if (fn->rr_ptr == rt)
@@ -1131,8 +1117,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 	/* If it was last route, expunge its radix tree node */
 	if (fn->leaf == NULL) {
 		fn->fn_flags &= ~RTN_RTINFO;
-		rt6_stats.fib_route_nodes--;
-		fn = fib6_repair_tree(fn);
+		net->ipv6.rt6_stats->fib_route_nodes--;
+		fn = fib6_repair_tree(net, fn);
 	}
 
 	if (atomic_read(&rt->rt6i_ref) != 1) {
@@ -1144,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 		 */
 		while (fn) {
 			if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
-				fn->leaf = fib6_find_prefix(fn);
+				fn->leaf = fib6_find_prefix(net, fn);
 				atomic_inc(&fn->leaf->rt6i_ref);
 				rt6_release(rt);
 			}
@@ -1160,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
 
 int fib6_del(struct rt6_info *rt, struct nl_info *info)
 {
+	struct net *net = info->nl_net;
 	struct fib6_node *fn = rt->rt6i_node;
 	struct rt6_info **rtp;
 
@@ -1169,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
 		return -ENOENT;
 	}
 #endif
-	if (fn == NULL || rt == &ip6_null_entry)
+	if (fn == NULL || rt == net->ipv6.ip6_null_entry)
 		return -ENOENT;
 
 	BUG_TRAP(fn->fn_flags&RTN_RTINFO);
@@ -1184,7 +1171,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
 			pn = pn->parent;
 		}
 #endif
-		fib6_prune_clones(pn, rt);
+		fib6_prune_clones(info->nl_net, pn, rt);
 	}
 
 	/*
@@ -1314,12 +1301,12 @@ static int fib6_walk(struct fib6_walker_t *w)
 
 static int fib6_clean_node(struct fib6_walker_t *w)
 {
-	struct nl_info info = {
-		.nl_net = &init_net,
-	};
 	int res;
 	struct rt6_info *rt;
 	struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w);
+	struct nl_info info = {
+		.nl_net = c->net,
+	};
 
 	for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) {
 		res = c->func(rt, c->arg);
@@ -1351,7 +1338,7 @@ static int fib6_clean_node(struct fib6_walker_t *w)
  *	ignoring pure split nodes) will be scanned.
  */
 
-static void fib6_clean_tree(struct fib6_node *root,
+static void fib6_clean_tree(struct net *net, struct fib6_node *root,
 			    int (*func)(struct rt6_info *, void *arg),
 			    int prune, void *arg)
 {
@@ -1362,23 +1349,26 @@ static void fib6_clean_tree(struct fib6_node *root,
 	c.w.prune = prune;
 	c.func = func;
 	c.arg = arg;
+	c.net = net;
 
 	fib6_walk(&c.w);
 }
 
-void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
+void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg),
 		    int prune, void *arg)
 {
 	struct fib6_table *table;
 	struct hlist_node *node;
+	struct hlist_head *head;
 	unsigned int h;
 
 	rcu_read_lock();
 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
-		hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
-					 tb6_hlist) {
+		head = &net->ipv6.fib_table_hash[h];
+		hlist_for_each_entry_rcu(table, node, head, tb6_hlist) {
 			write_lock_bh(&table->tb6_lock);
-			fib6_clean_tree(&table->tb6_root, func, prune, arg);
+			fib6_clean_tree(net, &table->tb6_root,
+					func, prune, arg);
 			write_unlock_bh(&table->tb6_lock);
 		}
 	}
@@ -1395,9 +1385,10 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg)
 	return 0;
 }
 
-static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt)
+static void fib6_prune_clones(struct net *net, struct fib6_node *fn,
+			      struct rt6_info *rt)
 {
-	fib6_clean_tree(fn, fib6_prune_clone, 1, rt);
+	fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt);
 }
 
 /*
@@ -1447,54 +1438,145 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 
 static DEFINE_SPINLOCK(fib6_gc_lock);
 
-void fib6_run_gc(unsigned long dummy)
+void fib6_run_gc(unsigned long expires, struct net *net)
 {
-	if (dummy != ~0UL) {
+	if (expires != ~0UL) {
 		spin_lock_bh(&fib6_gc_lock);
-		gc_args.timeout = dummy ? (int)dummy :
-			init_net.ipv6.sysctl.ip6_rt_gc_interval;
+		gc_args.timeout = expires ? (int)expires :
+			net->ipv6.sysctl.ip6_rt_gc_interval;
 	} else {
 		local_bh_disable();
 		if (!spin_trylock(&fib6_gc_lock)) {
-			mod_timer(&ip6_fib_timer, jiffies + HZ);
+			mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ);
 			local_bh_enable();
 			return;
 		}
-		gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval;
+		gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
 	}
 	gc_args.more = 0;
 
-	ndisc_dst_gc(&gc_args.more);
-	fib6_clean_all(fib6_age, 0, NULL);
+	icmp6_dst_gc(&gc_args.more);
+
+	fib6_clean_all(net, fib6_age, 0, NULL);
 
 	if (gc_args.more)
-		mod_timer(&ip6_fib_timer, jiffies +
-			  init_net.ipv6.sysctl.ip6_rt_gc_interval);
+		mod_timer(net->ipv6.ip6_fib_timer, jiffies +
+			  net->ipv6.sysctl.ip6_rt_gc_interval);
 	else {
-		del_timer(&ip6_fib_timer);
-		ip6_fib_timer.expires = 0;
+		del_timer(net->ipv6.ip6_fib_timer);
+		net->ipv6.ip6_fib_timer->expires = 0;
 	}
 	spin_unlock_bh(&fib6_gc_lock);
 }
 
-int __init fib6_init(void)
+static void fib6_gc_timer_cb(unsigned long arg)
+{
+	fib6_run_gc(0, (struct net *)arg);
+}
+
+static int fib6_net_init(struct net *net)
 {
 	int ret;
+	struct timer_list *timer;
+
+	ret = -ENOMEM;
+	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
+	if (!timer)
+		goto out;
+
+	setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net);
+	net->ipv6.ip6_fib_timer = timer;
+
+	net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL);
+	if (!net->ipv6.rt6_stats)
+		goto out_timer;
+
+	net->ipv6.fib_table_hash =
+		kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ,
+			GFP_KERNEL);
+	if (!net->ipv6.fib_table_hash)
+		goto out_rt6_stats;
+
+	net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl),
+					  GFP_KERNEL);
+	if (!net->ipv6.fib6_main_tbl)
+		goto out_fib_table_hash;
+
+	net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN;
+	net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
+	net->ipv6.fib6_main_tbl->tb6_root.fn_flags =
+		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl),
+					   GFP_KERNEL);
+	if (!net->ipv6.fib6_local_tbl)
+		goto out_fib6_main_tbl;
+	net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL;
+	net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry;
+	net->ipv6.fib6_local_tbl->tb6_root.fn_flags =
+		RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
+#endif
+	fib6_tables_init(net);
+
+	ret = 0;
+out:
+	return ret;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+out_fib6_main_tbl:
+	kfree(net->ipv6.fib6_main_tbl);
+#endif
+out_fib_table_hash:
+	kfree(net->ipv6.fib_table_hash);
+out_rt6_stats:
+	kfree(net->ipv6.rt6_stats);
+out_timer:
+	kfree(timer);
+	goto out;
+ }
+
+static void fib6_net_exit(struct net *net)
+{
+	rt6_ifdown(net, NULL);
+	del_timer(net->ipv6.ip6_fib_timer);
+	kfree(net->ipv6.ip6_fib_timer);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	kfree(net->ipv6.fib6_local_tbl);
+#endif
+	kfree(net->ipv6.fib6_main_tbl);
+	kfree(net->ipv6.fib_table_hash);
+	kfree(net->ipv6.rt6_stats);
+}
+
+static struct pernet_operations fib6_net_ops = {
+	.init = fib6_net_init,
+	.exit = fib6_net_exit,
+};
+
+int __init fib6_init(void)
+{
+	int ret = -ENOMEM;
+
 	fib6_node_kmem = kmem_cache_create("fib6_nodes",
 					   sizeof(struct fib6_node),
 					   0, SLAB_HWCACHE_ALIGN,
 					   NULL);
 	if (!fib6_node_kmem)
-		return -ENOMEM;
+		goto out;
 
-	fib6_tables_init();
+	ret = register_pernet_subsys(&fib6_net_ops);
+	if (ret)
+		goto out_kmem_cache_create;
 
 	ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib);
 	if (ret)
-		goto out_kmem_cache_create;
+		goto out_unregister_subsys;
 out:
 	return ret;
 
+out_unregister_subsys:
+	unregister_pernet_subsys(&fib6_net_ops);
 out_kmem_cache_create:
 	kmem_cache_destroy(fib6_node_kmem);
 	goto out;
@@ -1502,6 +1584,6 @@ out_kmem_cache_create:
 
 void fib6_gc_cleanup(void)
 {
-	del_timer(&ip6_fib_timer);
+	unregister_pernet_subsys(&fib6_net_ops);
 	kmem_cache_destroy(fib6_node_kmem);
 }
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 2b7d9ee98832..eb7a940310f4 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -62,23 +62,23 @@ static DEFINE_RWLOCK(ip6_fl_lock);
 static DEFINE_RWLOCK(ip6_sk_fl_lock);
 
 
-static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label)
+static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label)
 {
 	struct ip6_flowlabel *fl;
 
 	for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) {
-		if (fl->label == label)
+		if (fl->label == label && fl->fl_net == net)
 			return fl;
 	}
 	return NULL;
 }
 
-static struct ip6_flowlabel * fl_lookup(__be32 label)
+static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label)
 {
 	struct ip6_flowlabel *fl;
 
 	read_lock_bh(&ip6_fl_lock);
-	fl = __fl_lookup(label);
+	fl = __fl_lookup(net, label);
 	if (fl)
 		atomic_inc(&fl->users);
 	read_unlock_bh(&ip6_fl_lock);
@@ -88,8 +88,10 @@ static struct ip6_flowlabel * fl_lookup(__be32 label)
 
 static void fl_free(struct ip6_flowlabel *fl)
 {
-	if (fl)
+	if (fl) {
+		release_net(fl->fl_net);
 		kfree(fl->opt);
+	}
 	kfree(fl);
 }
 
@@ -112,7 +114,6 @@ static void fl_release(struct ip6_flowlabel *fl)
 		    time_after(ip6_fl_gc_timer.expires, ttd))
 			mod_timer(&ip6_fl_gc_timer, ttd);
 	}
-
 	write_unlock_bh(&ip6_fl_lock);
 }
 
@@ -148,13 +149,34 @@ static void ip6_fl_gc(unsigned long dummy)
 	if (!sched && atomic_read(&fl_size))
 		sched = now + FL_MAX_LINGER;
 	if (sched) {
-		ip6_fl_gc_timer.expires = sched;
-		add_timer(&ip6_fl_gc_timer);
+		mod_timer(&ip6_fl_gc_timer, sched);
+	}
+	write_unlock(&ip6_fl_lock);
+}
+
+static void ip6_fl_purge(struct net *net)
+{
+	int i;
+
+	write_lock(&ip6_fl_lock);
+	for (i = 0; i <= FL_HASH_MASK; i++) {
+		struct ip6_flowlabel *fl, **flp;
+		flp = &fl_ht[i];
+		while ((fl = *flp) != NULL) {
+			if (fl->fl_net == net && atomic_read(&fl->users) == 0) {
+				*flp = fl->next;
+				fl_free(fl);
+				atomic_dec(&fl_size);
+				continue;
+			}
+			flp = &fl->next;
+		}
 	}
 	write_unlock(&ip6_fl_lock);
 }
 
-static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label)
+static struct ip6_flowlabel *fl_intern(struct net *net,
+				       struct ip6_flowlabel *fl, __be32 label)
 {
 	struct ip6_flowlabel *lfl;
 
@@ -165,7 +187,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label)
 		for (;;) {
 			fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK;
 			if (fl->label) {
-				lfl = __fl_lookup(fl->label);
+				lfl = __fl_lookup(net, fl->label);
 				if (lfl == NULL)
 					break;
 			}
@@ -179,7 +201,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label)
 		 * done in ipv6_flowlabel_opt - sock is locked, so new entry
 		 * with the same label can only appear on another sock
 		 */
-		lfl = __fl_lookup(fl->label);
+		lfl = __fl_lookup(net, fl->label);
 		if (lfl != NULL) {
 			atomic_inc(&lfl->users);
 			write_unlock_bh(&ip6_fl_lock);
@@ -298,7 +320,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo
 }
 
 static struct ip6_flowlabel *
-fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *err_p)
+fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval,
+	  int optlen, int *err_p)
 {
 	struct ip6_flowlabel *fl;
 	int olen;
@@ -343,6 +366,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *
 		}
 	}
 
+	fl->fl_net = hold_net(net);
 	fl->expires = jiffies;
 	err = fl6_renew(fl, freq->flr_linger, freq->flr_expires);
 	if (err)
@@ -441,6 +465,7 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl,
 int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 {
 	int err;
+	struct net *net = sock_net(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct in6_flowlabel_req freq;
 	struct ipv6_fl_socklist *sfl1=NULL;
@@ -483,7 +508,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 		read_unlock_bh(&ip6_sk_fl_lock);
 
 		if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) {
-			fl = fl_lookup(freq.flr_label);
+			fl = fl_lookup(net, freq.flr_label);
 			if (fl) {
 				err = fl6_renew(fl, freq.flr_linger, freq.flr_expires);
 				fl_release(fl);
@@ -496,7 +521,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 		if (freq.flr_label & ~IPV6_FLOWLABEL_MASK)
 			return -EINVAL;
 
-		fl = fl_create(&freq, optval, optlen, &err);
+		fl = fl_create(net, &freq, optval, optlen, &err);
 		if (fl == NULL)
 			return err;
 		sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL);
@@ -518,7 +543,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen)
 			read_unlock_bh(&ip6_sk_fl_lock);
 
 			if (fl1 == NULL)
-				fl1 = fl_lookup(freq.flr_label);
+				fl1 = fl_lookup(net, freq.flr_label);
 			if (fl1) {
 recheck:
 				err = -EEXIST;
@@ -559,7 +584,7 @@ release:
 		if (sfl1 == NULL || (err = mem_check(sk)) != 0)
 			goto done;
 
-		fl1 = fl_intern(fl, freq.flr_label);
+		fl1 = fl_intern(net, fl, freq.flr_label);
 		if (fl1 != NULL)
 			goto recheck;
 
@@ -586,6 +611,7 @@ done:
 #ifdef CONFIG_PROC_FS
 
 struct ip6fl_iter_state {
+	struct seq_net_private p;
 	int bucket;
 };
 
@@ -595,12 +621,15 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
 {
 	struct ip6_flowlabel *fl = NULL;
 	struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
+	struct net *net = seq_file_net(seq);
 
 	for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) {
-		if (fl_ht[state->bucket]) {
-			fl = fl_ht[state->bucket];
+		fl = fl_ht[state->bucket];
+
+		while (fl && fl->fl_net != net)
+			fl = fl->next;
+		if (fl)
 			break;
-		}
 	}
 	return fl;
 }
@@ -608,12 +637,18 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
 static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl)
 {
 	struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
+	struct net *net = seq_file_net(seq);
 
 	fl = fl->next;
+try_again:
+	while (fl && fl->fl_net != net)
+		fl = fl->next;
+
 	while (!fl) {
-		if (++state->bucket <= FL_HASH_MASK)
+		if (++state->bucket <= FL_HASH_MASK) {
 			fl = fl_ht[state->bucket];
-		else
+			goto try_again;
+		} else
 			break;
 	}
 	return fl;
@@ -683,8 +718,8 @@ static const struct seq_operations ip6fl_seq_ops = {
 
 static int ip6fl_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &ip6fl_seq_ops,
-			sizeof(struct ip6fl_iter_state));
+	return seq_open_net(inode, file, &ip6fl_seq_ops,
+			    sizeof(struct ip6fl_iter_state));
 }
 
 static const struct file_operations ip6fl_seq_fops = {
@@ -692,12 +727,13 @@ static const struct file_operations ip6fl_seq_fops = {
 	.open		=	ip6fl_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
 };
 
 static int ip6_flowlabel_proc_init(struct net *net)
 {
-	if (!proc_net_fops_create(net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops))
+	if (!proc_net_fops_create(net, "ip6_flowlabel",
+				  S_IRUGO, &ip6fl_seq_fops))
 		return -ENOMEM;
 	return 0;
 }
@@ -717,13 +753,24 @@ static inline void ip6_flowlabel_proc_fini(struct net *net)
 }
 #endif
 
+static inline void ip6_flowlabel_net_exit(struct net *net)
+{
+	ip6_fl_purge(net);
+	ip6_flowlabel_proc_fini(net);
+}
+
+static struct pernet_operations ip6_flowlabel_net_ops = {
+	.init = ip6_flowlabel_proc_init,
+	.exit = ip6_flowlabel_net_exit,
+};
+
 int ip6_flowlabel_init(void)
 {
-	return ip6_flowlabel_proc_init(&init_net);
+	return register_pernet_subsys(&ip6_flowlabel_net_ops);
 }
 
 void ip6_flowlabel_cleanup(void)
 {
 	del_timer(&ip6_fl_gc_timer);
-	ip6_flowlabel_proc_fini(&init_net);
+	unregister_pernet_subsys(&ip6_flowlabel_net_ops);
 }
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 98ab4f459905..43a617e2268b 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -61,11 +61,6 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 	u32 		pkt_len;
 	struct inet6_dev *idev;
 
-	if (dev->nd_net != &init_net) {
-		kfree_skb(skb);
-		return 0;
-	}
-
 	if (skb->pkt_type == PACKET_OTHERHOST) {
 		kfree_skb(skb);
 		return 0;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 8b67ca07467d..a8b4da25b0a7 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -237,9 +237,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
 	if (np)
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
-		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
-	if (hlimit < 0)
-		hlimit = ipv6_get_hoplimit(dst->dev);
+		hlimit = ip6_dst_hoplimit(dst);
 
 	tclass = -1;
 	if (np)
@@ -404,6 +402,7 @@ int ip6_forward(struct sk_buff *skb)
 	struct dst_entry *dst = skb->dst;
 	struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct inet6_skb_parm *opt = IP6CB(skb);
+	struct net *net = dev_net(dst->dev);
 
 	if (ipv6_devconf.forwarding == 0)
 		goto error;
@@ -450,7 +449,7 @@ int ip6_forward(struct sk_buff *skb)
 
 	/* XXX: idev->cnf.proxy_ndp? */
 	if (ipv6_devconf.proxy_ndp &&
-	    pneigh_lookup(&nd_tbl, &init_net, &hdr->daddr, skb->dev, 0)) {
+	    pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) {
 		int proxied = ip6_forward_proxy_check(skb);
 		if (proxied > 0)
 			return ip6_input(skb);
@@ -596,7 +595,6 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
 
 	return offset;
 }
-EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
 
 static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
 {
@@ -912,15 +910,19 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 			       struct dst_entry **dst, struct flowi *fl)
 {
 	int err;
+	struct net *net = sock_net(sk);
 
 	if (*dst == NULL)
-		*dst = ip6_route_output(sk, fl);
+		*dst = ip6_route_output(net, sk, fl);
 
 	if ((err = (*dst)->error))
 		goto out_err_release;
 
 	if (ipv6_addr_any(&fl->fl6_src)) {
-		err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src);
+		err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev,
+					 &fl->fl6_dst,
+					 sk ? inet6_sk(sk)->srcprefs : 0,
+					 &fl->fl6_src);
 		if (err)
 			goto out_err_release;
 	}
@@ -939,7 +941,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 			struct flowi fl_gw;
 			int redirect;
 
-			ifp = ipv6_get_ifaddr(&init_net, &fl->fl6_src,
+			ifp = ipv6_get_ifaddr(net, &fl->fl6_src,
 					      (*dst)->dev, 1);
 
 			redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);
@@ -954,7 +956,7 @@ static int ip6_dst_lookup_tail(struct sock *sk,
 				dst_release(*dst);
 				memcpy(&fl_gw, fl, sizeof(struct flowi));
 				memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr));
-				*dst = ip6_route_output(sk, &fl_gw);
+				*dst = ip6_route_output(net, sk, &fl_gw);
 				if ((err = (*dst)->error))
 					goto out_err_release;
 			}
@@ -1113,7 +1115,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
 			/* need source address above miyazawa*/
 		}
 		dst_hold(&rt->u.dst);
-		np->cork.rt = rt;
+		inet->cork.dst = &rt->u.dst;
 		inet->cork.fl = *fl;
 		np->cork.hop_limit = hlimit;
 		np->cork.tclass = tclass;
@@ -1134,7 +1136,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
 		length += exthdrlen;
 		transhdrlen += exthdrlen;
 	} else {
-		rt = np->cork.rt;
+		rt = (struct rt6_info *)inet->cork.dst;
 		fl = &inet->cork.fl;
 		if (inet->cork.flags & IPCORK_OPT)
 			opt = np->cork.opt;
@@ -1379,9 +1381,9 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
 	inet->cork.flags &= ~IPCORK_OPT;
 	kfree(np->cork.opt);
 	np->cork.opt = NULL;
-	if (np->cork.rt) {
-		dst_release(&np->cork.rt->u.dst);
-		np->cork.rt = NULL;
+	if (inet->cork.dst) {
+		dst_release(inet->cork.dst);
+		inet->cork.dst = NULL;
 		inet->cork.flags &= ~IPCORK_ALLFRAG;
 	}
 	memset(&inet->cork.fl, 0, sizeof(inet->cork.fl));
@@ -1396,7 +1398,7 @@ int ip6_push_pending_frames(struct sock *sk)
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6hdr *hdr;
 	struct ipv6_txoptions *opt = np->cork.opt;
-	struct rt6_info *rt = np->cork.rt;
+	struct rt6_info *rt = (struct rt6_info *)inet->cork.dst;
 	struct flowi *fl = &inet->cork.fl;
 	unsigned char proto = fl->proto;
 	int err = 0;
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 78f438880923..61517fe0c57c 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -60,7 +60,7 @@ MODULE_LICENSE("GPL");
 #define IPV6_TLV_TEL_DST_SIZE 8
 
 #ifdef IP6_TNL_DEBUG
-#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
+#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__)
 #else
 #define IP6_TNL_TRACE(x...) do {;} while(0)
 #endif
@@ -602,7 +602,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		skb_reset_network_header(skb2);
 
 		/* Try to guess incoming interface */
-		rt = rt6_lookup(&ipv6_hdr(skb2)->saddr, NULL, 0, 0);
+		rt = rt6_lookup(&init_net, &ipv6_hdr(skb2)->saddr, NULL, 0, 0);
 
 		if (rt && rt->rt6i_dev)
 			skb2->dev = rt->rt6i_dev;
@@ -847,7 +847,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
 	if ((dst = ip6_tnl_dst_check(t)) != NULL)
 		dst_hold(dst);
 	else {
-		dst = ip6_route_output(NULL, fl);
+		dst = ip6_route_output(&init_net, NULL, fl);
 
 		if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0)
 			goto tx_err_link_failure;
@@ -1112,7 +1112,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
 		int strict = (ipv6_addr_type(&p->raddr) &
 			      (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
 
-		struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
+		struct rt6_info *rt = rt6_lookup(&init_net, &p->raddr, &p->laddr,
 						 p->link, strict);
 
 		if (rt == NULL)
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index bf2a686aa13d..4195ac92345e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -57,118 +57,6 @@
 
 DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly;
 
-static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb,
-						    int proto)
-{
-	struct inet6_protocol *ops = NULL;
-
-	for (;;) {
-		struct ipv6_opt_hdr *opth;
-		int len;
-
-		if (proto != NEXTHDR_HOP) {
-			ops = rcu_dereference(inet6_protos[proto]);
-
-			if (unlikely(!ops))
-				break;
-
-			if (!(ops->flags & INET6_PROTO_GSO_EXTHDR))
-				break;
-		}
-
-		if (unlikely(!pskb_may_pull(skb, 8)))
-			break;
-
-		opth = (void *)skb->data;
-		len = opth->hdrlen * 8 + 8;
-
-		if (unlikely(!pskb_may_pull(skb, len)))
-			break;
-
-		proto = opth->nexthdr;
-		__skb_pull(skb, len);
-	}
-
-	return ops;
-}
-
-static int ipv6_gso_send_check(struct sk_buff *skb)
-{
-	struct ipv6hdr *ipv6h;
-	struct inet6_protocol *ops;
-	int err = -EINVAL;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-		goto out;
-
-	ipv6h = ipv6_hdr(skb);
-	__skb_pull(skb, sizeof(*ipv6h));
-	err = -EPROTONOSUPPORT;
-
-	rcu_read_lock();
-	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
-	if (likely(ops && ops->gso_send_check)) {
-		skb_reset_transport_header(skb);
-		err = ops->gso_send_check(skb);
-	}
-	rcu_read_unlock();
-
-out:
-	return err;
-}
-
-static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
-{
-	struct sk_buff *segs = ERR_PTR(-EINVAL);
-	struct ipv6hdr *ipv6h;
-	struct inet6_protocol *ops;
-
-	if (!(features & NETIF_F_V6_CSUM))
-		features &= ~NETIF_F_SG;
-
-	if (unlikely(skb_shinfo(skb)->gso_type &
-		     ~(SKB_GSO_UDP |
-		       SKB_GSO_DODGY |
-		       SKB_GSO_TCP_ECN |
-		       SKB_GSO_TCPV6 |
-		       0)))
-		goto out;
-
-	if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
-		goto out;
-
-	ipv6h = ipv6_hdr(skb);
-	__skb_pull(skb, sizeof(*ipv6h));
-	segs = ERR_PTR(-EPROTONOSUPPORT);
-
-	rcu_read_lock();
-	ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
-	if (likely(ops && ops->gso_segment)) {
-		skb_reset_transport_header(skb);
-		segs = ops->gso_segment(skb, features);
-	}
-	rcu_read_unlock();
-
-	if (unlikely(IS_ERR(segs)))
-		goto out;
-
-	for (skb = segs; skb; skb = skb->next) {
-		ipv6h = ipv6_hdr(skb);
-		ipv6h->payload_len = htons(skb->len - skb->mac_len -
-					   sizeof(*ipv6h));
-	}
-
-out:
-	return segs;
-}
-
-static struct packet_type ipv6_packet_type = {
-	.type = __constant_htons(ETH_P_IPV6),
-	.func = ipv6_rcv,
-	.gso_send_check = ipv6_gso_send_check,
-	.gso_segment = ipv6_gso_segment,
-};
-
 struct ip6_ra_chain *ip6_ra_chain;
 DEFINE_RWLOCK(ip6_ra_lock);
 
@@ -219,6 +107,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 		    char __user *optval, int optlen)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net *net = sock_net(sk);
 	int val, valbool;
 	int retv = -ENOPROTOOPT;
 
@@ -266,10 +155,11 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 
 			if (sk->sk_protocol == IPPROTO_TCP) {
 				struct inet_connection_sock *icsk = inet_csk(sk);
+				struct net *net = sock_net(sk);
 
 				local_bh_disable();
-				sock_prot_inuse_add(sk->sk_prot, -1);
-				sock_prot_inuse_add(&tcp_prot, 1);
+				sock_prot_inuse_add(net, sk->sk_prot, -1);
+				sock_prot_inuse_add(net, &tcp_prot, 1);
 				local_bh_enable();
 				sk->sk_prot = &tcp_prot;
 				icsk->icsk_af_ops = &ipv4_specific;
@@ -278,12 +168,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
 				tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
 			} else {
 				struct proto *prot = &udp_prot;
+				struct net *net = sock_net(sk);
 
 				if (sk->sk_protocol == IPPROTO_UDPLITE)
 					prot = &udplite_prot;
 				local_bh_disable();
-				sock_prot_inuse_add(sk->sk_prot, -1);
-				sock_prot_inuse_add(prot, 1);
+				sock_prot_inuse_add(net, sk->sk_prot, -1);
+				sock_prot_inuse_add(net, prot, 1);
 				local_bh_enable();
 				sk->sk_prot = prot;
 				sk->sk_socket->ops = &inet_dgram_ops;
@@ -544,7 +435,7 @@ done:
 			if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
 				goto e_inval;
 
-			if (__dev_get_by_index(&init_net, val) == NULL) {
+			if (__dev_get_by_index(net, val) == NULL) {
 				retv = -ENODEV;
 				break;
 			}
@@ -728,7 +619,67 @@ done:
 		retv = xfrm_user_policy(sk, optname, optval, optlen);
 		break;
 
+	case IPV6_ADDR_PREFERENCES:
+	    {
+		unsigned int pref = 0;
+		unsigned int prefmask = ~0;
+
+		retv = -EINVAL;
+
+		/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
+		switch (val & (IPV6_PREFER_SRC_PUBLIC|
+			       IPV6_PREFER_SRC_TMP|
+			       IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
+		case IPV6_PREFER_SRC_PUBLIC:
+			pref |= IPV6_PREFER_SRC_PUBLIC;
+			break;
+		case IPV6_PREFER_SRC_TMP:
+			pref |= IPV6_PREFER_SRC_TMP;
+			break;
+		case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
+			break;
+		case 0:
+			goto pref_skip_pubtmp;
+		default:
+			goto e_inval;
+		}
+
+		prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
+			      IPV6_PREFER_SRC_TMP);
+pref_skip_pubtmp:
+
+		/* check HOME/COA conflicts */
+		switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
+		case IPV6_PREFER_SRC_HOME:
+			break;
+		case IPV6_PREFER_SRC_COA:
+			pref |= IPV6_PREFER_SRC_COA;
+		case 0:
+			goto pref_skip_coa;
+		default:
+			goto e_inval;
+		}
+
+		prefmask &= ~IPV6_PREFER_SRC_COA;
+pref_skip_coa:
+
+		/* check CGA/NONCGA conflicts */
+		switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
+		case IPV6_PREFER_SRC_CGA:
+		case IPV6_PREFER_SRC_NONCGA:
+		case 0:
+			break;
+		default:
+			goto e_inval;
+		}
+
+		np->srcprefs = (np->srcprefs & prefmask) | pref;
+		retv = 0;
+
+		break;
+	    }
 	}
+
 	release_sock(sk);
 
 	return retv;
@@ -1015,9 +966,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 		dst = sk_dst_get(sk);
 		if (dst) {
 			if (val < 0)
-				val = dst_metric(dst, RTAX_HOPLIMIT);
-			if (val < 0)
-				val = ipv6_get_hoplimit(dst->dev);
+				val = ip6_dst_hoplimit(dst);
 			dst_release(dst);
 		}
 		if (val < 0)
@@ -1045,6 +994,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 		val = np->sndflow;
 		break;
 
+	case IPV6_ADDR_PREFERENCES:
+		val = 0;
+
+		if (np->srcprefs & IPV6_PREFER_SRC_TMP)
+			val |= IPV6_PREFER_SRC_TMP;
+		else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC)
+			val |= IPV6_PREFER_SRC_PUBLIC;
+		else {
+			/* XXX: should we return system default? */
+			val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT;
+		}
+
+		if (np->srcprefs & IPV6_PREFER_SRC_COA)
+			val |= IPV6_PREFER_SRC_COA;
+		else
+			val |= IPV6_PREFER_SRC_HOME;
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
@@ -1128,13 +1095,3 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL(compat_ipv6_getsockopt);
 #endif
 
-int __init ipv6_packet_init(void)
-{
-	dev_add_pack(&ipv6_packet_type);
-	return 0;
-}
-
-void ipv6_packet_cleanup(void)
-{
-	dev_remove_pack(&ipv6_packet_type);
-}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index ab228d1ea114..d810cff818cf 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -126,8 +126,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT;
 /* Big mc list lock for all the sockets */
 static DEFINE_RWLOCK(ipv6_sk_mc_lock);
 
-static struct socket *igmp6_socket;
-
 int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr);
 
 static void igmp6_join_group(struct ifmcaddr6 *ma);
@@ -183,6 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 	struct net_device *dev = NULL;
 	struct ipv6_mc_socklist *mc_lst;
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct net *net = sock_net(sk);
 	int err;
 
 	if (!ipv6_addr_is_multicast(addr))
@@ -208,14 +207,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
 
 	if (ifindex == 0) {
 		struct rt6_info *rt;
-		rt = rt6_lookup(addr, NULL, 0, 0);
+		rt = rt6_lookup(net, addr, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
 			dev_hold(dev);
 			dst_release(&rt->u.dst);
 		}
 	} else
-		dev = dev_get_by_index(&init_net, ifindex);
+		dev = dev_get_by_index(net, ifindex);
 
 	if (dev == NULL) {
 		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
@@ -256,6 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6_mc_socklist *mc_lst, **lnk;
+	struct net *net = sock_net(sk);
 
 	write_lock_bh(&ipv6_sk_mc_lock);
 	for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
@@ -266,7 +266,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 			*lnk = mc_lst->next;
 			write_unlock_bh(&ipv6_sk_mc_lock);
 
-			if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) {
+			dev = dev_get_by_index(net, mc_lst->ifindex);
+			if (dev != NULL) {
 				struct inet6_dev *idev = in6_dev_get(dev);
 
 				(void) ip6_mc_leave_src(sk, mc_lst, idev);
@@ -286,7 +287,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
 	return -EADDRNOTAVAIL;
 }
 
-static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
+static struct inet6_dev *ip6_mc_find_dev(struct net *net,
+					 struct in6_addr *group,
+					 int ifindex)
 {
 	struct net_device *dev = NULL;
 	struct inet6_dev *idev = NULL;
@@ -294,14 +297,14 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
 	if (ifindex == 0) {
 		struct rt6_info *rt;
 
-		rt = rt6_lookup(group, NULL, 0, 0);
+		rt = rt6_lookup(net, group, NULL, 0, 0);
 		if (rt) {
 			dev = rt->rt6i_dev;
 			dev_hold(dev);
 			dst_release(&rt->u.dst);
 		}
 	} else
-		dev = dev_get_by_index(&init_net, ifindex);
+		dev = dev_get_by_index(net, ifindex);
 
 	if (!dev)
 		return NULL;
@@ -324,6 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk)
 {
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct ipv6_mc_socklist *mc_lst;
+	struct net *net = sock_net(sk);
 
 	write_lock_bh(&ipv6_sk_mc_lock);
 	while ((mc_lst = np->ipv6_mc_list) != NULL) {
@@ -332,7 +336,7 @@ void ipv6_sock_mc_close(struct sock *sk)
 		np->ipv6_mc_list = mc_lst->next;
 		write_unlock_bh(&ipv6_sk_mc_lock);
 
-		dev = dev_get_by_index(&init_net, mc_lst->ifindex);
+		dev = dev_get_by_index(net, mc_lst->ifindex);
 		if (dev) {
 			struct inet6_dev *idev = in6_dev_get(dev);
 
@@ -361,6 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *psl;
+	struct net *net = sock_net(sk);
 	int i, j, rv;
 	int leavegroup = 0;
 	int pmclocked = 0;
@@ -376,7 +381,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
 	if (!ipv6_addr_is_multicast(group))
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(group, pgsr->gsr_interface);
+	idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
 	if (!idev)
 		return -ENODEV;
 	dev = idev->dev;
@@ -500,6 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
 	struct inet6_dev *idev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *newpsl, *psl;
+	struct net *net = sock_net(sk);
 	int leavegroup = 0;
 	int i, err;
 
@@ -511,7 +517,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
 	    gsf->gf_fmode != MCAST_EXCLUDE)
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(group, gsf->gf_interface);
+	idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
 
 	if (!idev)
 		return -ENODEV;
@@ -592,13 +598,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
 	struct net_device *dev;
 	struct ipv6_pinfo *inet6 = inet6_sk(sk);
 	struct ip6_sf_socklist *psl;
+	struct net *net = sock_net(sk);
 
 	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
 
 	if (!ipv6_addr_is_multicast(group))
 		return -EINVAL;
 
-	idev = ip6_mc_find_dev(group, gsf->gf_interface);
+	idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
 
 	if (!idev)
 		return -ENODEV;
@@ -1393,7 +1400,8 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
 
 static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 {
-	struct sock *sk = igmp6_socket->sk;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.igmp_sk;
 	struct sk_buff *skb;
 	struct mld2_report *pmr;
 	struct in6_addr addr_buf;
@@ -1433,25 +1441,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 	return skb;
 }
 
-static inline int mld_dev_queue_xmit2(struct sk_buff *skb)
-{
-	struct net_device *dev = skb->dev;
-	unsigned char ha[MAX_ADDR_LEN];
-
-	ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1);
-	if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) {
-		kfree_skb(skb);
-		return -EINVAL;
-	}
-	return dev_queue_xmit(skb);
-}
-
-static inline int mld_dev_queue_xmit(struct sk_buff *skb)
-{
-	return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
-		       mld_dev_queue_xmit2);
-}
-
 static void mld_sendpack(struct sk_buff *skb)
 {
 	struct ipv6hdr *pip6 = ipv6_hdr(skb);
@@ -1459,7 +1448,9 @@ static void mld_sendpack(struct sk_buff *skb)
 			      (struct mld2_report *)skb_transport_header(skb);
 	int payload_len, mldlen;
 	struct inet6_dev *idev = in6_dev_get(skb->dev);
+	struct net *net = dev_net(skb->dev);
 	int err;
+	struct flowi fl;
 
 	IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS);
 	payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
@@ -1469,8 +1460,25 @@ static void mld_sendpack(struct sk_buff *skb)
 	pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
 		IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb),
 					     mldlen, 0));
+
+	skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+
+	if (!skb->dst) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT,
+			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+			 skb->dev->ifindex);
+
+	err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+	if (err)
+		goto err_out;
+
 	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
-		mld_dev_queue_xmit);
+		      dst_output);
+out:
 	if (!err) {
 		ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT);
 		ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
@@ -1480,6 +1488,11 @@ static void mld_sendpack(struct sk_buff *skb)
 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
+	return;
+
+err_out:
+	kfree_skb(skb);
+	goto out;
 }
 
 static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel)
@@ -1749,7 +1762,8 @@ static void mld_send_cr(struct inet6_dev *idev)
 
 static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 {
-	struct sock *sk = igmp6_socket->sk;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.igmp_sk;
 	struct inet6_dev *idev;
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
@@ -1761,6 +1775,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 	u8 ra[8] = { IPPROTO_ICMPV6, 0,
 		     IPV6_TLV_ROUTERALERT, 2, 0, 0,
 		     IPV6_TLV_PADN, 0 };
+	struct flowi fl;
 
 	rcu_read_lock();
 	IP6_INC_STATS(__in6_dev_get(dev),
@@ -1813,8 +1828,23 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 
 	idev = in6_dev_get(skb->dev);
 
+	skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
+	if (!skb->dst) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	icmpv6_flow_init(sk, &fl, type,
+			 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+			 skb->dev->ifindex);
+
+	err = xfrm_lookup(&skb->dst, &fl, NULL, 0);
+	if (err)
+		goto err_out;
+
 	err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
-		mld_dev_queue_xmit);
+		      dst_output);
+out:
 	if (!err) {
 		ICMP6MSGOUT_INC_STATS(idev, type);
 		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);
@@ -1825,6 +1855,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
 	return;
+
+err_out:
+	kfree_skb(skb);
+	goto out;
 }
 
 static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
@@ -2310,6 +2344,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev)
 
 #ifdef CONFIG_PROC_FS
 struct igmp6_mc_iter_state {
+	struct seq_net_private p;
 	struct net_device *dev;
 	struct inet6_dev *idev;
 };
@@ -2320,9 +2355,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
 {
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
+	struct net *net = seq_file_net(seq);
 
 	state->idev = NULL;
-	for_each_netdev(&init_net, state->dev) {
+	for_each_netdev(net, state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (!idev)
@@ -2424,8 +2460,8 @@ static const struct seq_operations igmp6_mc_seq_ops = {
 
 static int igmp6_mc_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &igmp6_mc_seq_ops,
-			sizeof(struct igmp6_mc_iter_state));
+	return seq_open_net(inode, file, &igmp6_mc_seq_ops,
+			    sizeof(struct igmp6_mc_iter_state));
 }
 
 static const struct file_operations igmp6_mc_seq_fops = {
@@ -2433,10 +2469,11 @@ static const struct file_operations igmp6_mc_seq_fops = {
 	.open		=	igmp6_mc_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
 };
 
 struct igmp6_mcf_iter_state {
+	struct seq_net_private p;
 	struct net_device *dev;
 	struct inet6_dev *idev;
 	struct ifmcaddr6 *im;
@@ -2449,10 +2486,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
 	struct ip6_sf_list *psf = NULL;
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
+	struct net *net = seq_file_net(seq);
 
 	state->idev = NULL;
 	state->im = NULL;
-	for_each_netdev(&init_net, state->dev) {
+	for_each_netdev(net, state->dev) {
 		struct inet6_dev *idev;
 		idev = in6_dev_get(state->dev);
 		if (unlikely(idev == NULL))
@@ -2584,8 +2622,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = {
 
 static int igmp6_mcf_seq_open(struct inode *inode, struct file *file)
 {
-	return seq_open_private(file, &igmp6_mcf_seq_ops,
-			sizeof(struct igmp6_mcf_iter_state));
+	return seq_open_net(inode, file, &igmp6_mcf_seq_ops,
+			    sizeof(struct igmp6_mcf_iter_state));
 }
 
 static const struct file_operations igmp6_mcf_seq_fops = {
@@ -2593,47 +2631,96 @@ static const struct file_operations igmp6_mcf_seq_fops = {
 	.open		=	igmp6_mcf_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
-	.release	=	seq_release_private,
+	.release	=	seq_release_net,
 };
+
+static int igmp6_proc_init(struct net *net)
+{
+	int err;
+
+	err = -ENOMEM;
+	if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops))
+		goto out;
+	if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO,
+				  &igmp6_mcf_seq_fops))
+		goto out_proc_net_igmp6;
+
+	err = 0;
+out:
+	return err;
+
+out_proc_net_igmp6:
+	proc_net_remove(net, "igmp6");
+	goto out;
+}
+
+static void igmp6_proc_exit(struct net *net)
+{
+	proc_net_remove(net, "mcfilter6");
+	proc_net_remove(net, "igmp6");
+}
+#else
+static int igmp6_proc_init(struct net *net)
+{
+	return 0;
+}
+static void igmp6_proc_exit(struct net *net)
+{
+	;
+}
 #endif
 
-int __init igmp6_init(struct net_proto_family *ops)
+static int igmp6_net_init(struct net *net)
 {
 	struct ipv6_pinfo *np;
+	struct socket *sock;
 	struct sock *sk;
 	int err;
 
-	err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);
+	err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
 	if (err < 0) {
 		printk(KERN_ERR
 		       "Failed to initialize the IGMP6 control socket (err %d).\n",
 		       err);
-		igmp6_socket = NULL; /* For safety. */
-		return err;
+		goto out;
 	}
 
-	sk = igmp6_socket->sk;
+	net->ipv6.igmp_sk = sk = sock->sk;
+	sk_change_net(sk, net);
 	sk->sk_allocation = GFP_ATOMIC;
 	sk->sk_prot->unhash(sk);
 
 	np = inet6_sk(sk);
 	np->hop_limit = 1;
 
-#ifdef CONFIG_PROC_FS
-	proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops);
-	proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops);
-#endif
+	err = igmp6_proc_init(net);
+	if (err)
+		goto out_sock_create;
+out:
+	return err;
 
-	return 0;
+out_sock_create:
+	sk_release_kernel(net->ipv6.igmp_sk);
+	goto out;
 }
 
-void igmp6_cleanup(void)
+static void igmp6_net_exit(struct net *net)
 {
-	sock_release(igmp6_socket);
-	igmp6_socket = NULL; /* for safety */
+	sk_release_kernel(net->ipv6.igmp_sk);
+	igmp6_proc_exit(net);
+}
 
-#ifdef CONFIG_PROC_FS
-	proc_net_remove(&init_net, "mcfilter6");
-	proc_net_remove(&init_net, "igmp6");
-#endif
+static struct pernet_operations igmp6_net_ops = {
+	.init = igmp6_net_init,
+	.exit = igmp6_net_exit,
+};
+
+int __init igmp6_init(void)
+{
+	return register_pernet_subsys(&igmp6_net_ops);
+}
+
+void igmp6_cleanup(void)
+{
+	unregister_pernet_subsys(&igmp6_net_ops);
 }
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index cd8a5bda13cd..42403c626c27 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -304,13 +304,13 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb,
 static int mip6_destopt_init_state(struct xfrm_state *x)
 {
 	if (x->id.spi) {
-		printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
+		printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
 		       x->id.spi);
 		return -EINVAL;
 	}
 	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 		printk(KERN_INFO "%s: state's mode is not %u: %u\n",
-		       __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+		       __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 		return -EINVAL;
 	}
 
@@ -439,13 +439,13 @@ static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb,
 static int mip6_rthdr_init_state(struct xfrm_state *x)
 {
 	if (x->id.spi) {
-		printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__,
+		printk(KERN_INFO "%s: spi is not 0: %u\n", __func__,
 		       x->id.spi);
 		return -EINVAL;
 	}
 	if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) {
 		printk(KERN_INFO "%s: state's mode is not %u: %u\n",
-		       __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
+		       __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode);
 		return -EINVAL;
 	}
 
@@ -480,15 +480,15 @@ static int __init mip6_init(void)
 	printk(KERN_INFO "Mobile IPv6\n");
 
 	if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) {
-		printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __func__);
 		goto mip6_destopt_xfrm_fail;
 	}
 	if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) {
-		printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __func__);
 		goto mip6_rthdr_xfrm_fail;
 	}
 	if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
-		printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __func__);
 		goto mip6_rawv6_mh_fail;
 	}
 
@@ -506,11 +506,11 @@ static int __init mip6_init(void)
 static void __exit mip6_fini(void)
 {
 	if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
-		printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __func__);
 	if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
-		printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __func__);
 	if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
-		printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
+		printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __func__);
 }
 
 module_init(mip6_init);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 452a2ac4eec8..510aa747a404 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -89,8 +89,6 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv6.h>
 
-static struct socket *ndisc_socket;
-
 static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
 static int ndisc_constructor(struct neighbour *neigh);
 static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
@@ -270,7 +268,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
 			if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) {
 				ND_PRINTK2(KERN_WARNING
 					   "%s(): duplicated ND6 option found: type=%d\n",
-					   __FUNCTION__,
+					   __func__,
 					   nd_opt->nd_opt_type);
 			} else {
 				ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt;
@@ -301,7 +299,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
 				 */
 				ND_PRINTK2(KERN_NOTICE
 					   "%s(): ignored unsupported option; type=%d, len=%d\n",
-					   __FUNCTION__,
+					   __func__,
 					   nd_opt->nd_opt_type, nd_opt->nd_opt_len);
 			}
 		}
@@ -441,21 +439,6 @@ static void pndisc_destructor(struct pneigh_entry *n)
 /*
  *	Send a Neighbour Advertisement
  */
-
-static inline void ndisc_flow_init(struct flowi *fl, u8 type,
-			    struct in6_addr *saddr, struct in6_addr *daddr,
-			    int oif)
-{
-	memset(fl, 0, sizeof(*fl));
-	ipv6_addr_copy(&fl->fl6_src, saddr);
-	ipv6_addr_copy(&fl->fl6_dst, daddr);
-	fl->proto	 	= IPPROTO_ICMPV6;
-	fl->fl_icmp_type	= type;
-	fl->fl_icmp_code	= 0;
-	fl->oif			= oif;
-	security_sk_classify_flow(ndisc_socket->sk, fl);
-}
-
 static void __ndisc_send(struct net_device *dev,
 			 struct neighbour *neigh,
 			 struct in6_addr *daddr, struct in6_addr *saddr,
@@ -464,7 +447,8 @@ static void __ndisc_send(struct net_device *dev,
 {
 	struct flowi fl;
 	struct dst_entry *dst;
-	struct sock *sk = ndisc_socket->sk;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.ndisc_sk;
 	struct sk_buff *skb;
 	struct icmp6hdr *hdr;
 	struct inet6_dev *idev;
@@ -474,10 +458,9 @@ static void __ndisc_send(struct net_device *dev,
 
 	type = icmp6h->icmp6_type;
 
-	ndisc_flow_init(&fl, type, saddr, daddr,
-			dev->ifindex);
+	icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
 
-	dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
+	dst = icmp6_dst_alloc(dev, neigh, daddr);
 	if (!dst)
 		return;
 
@@ -499,7 +482,7 @@ static void __ndisc_send(struct net_device *dev,
 	if (!skb) {
 		ND_PRINTK0(KERN_ERR
 			   "ICMPv6 ND: %s() failed to allocate an skb.\n",
-			   __FUNCTION__);
+			   __func__);
 		dst_release(dst);
 		return;
 	}
@@ -556,14 +539,16 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 	};
 
 	/* for anycast or proxy, solicited_addr != src_addr */
-	ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1);
+	ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);
 	if (ifp) {
 		src_addr = solicited_addr;
 		if (ifp->flags & IFA_F_OPTIMISTIC)
 			override = 0;
 		in6_ifa_put(ifp);
 	} else {
-		if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
+		if (ipv6_dev_get_saddr(dev, daddr,
+				       inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,
+				       &tmpaddr))
 			return;
 		src_addr = &tmpaddr;
 	}
@@ -616,7 +601,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
 	 * suppress the inclusion of the sllao.
 	 */
 	if (send_sllao) {
-		struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr,
+		struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr,
 							   dev, 1);
 		if (ifp) {
 			if (ifp->flags & IFA_F_OPTIMISTIC)  {
@@ -654,7 +639,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
 	struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
 	int probes = atomic_read(&neigh->probes);
 
-	if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1))
+	if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1))
 		saddr = &ipv6_hdr(skb)->saddr;
 
 	if ((probes -= neigh->parms->ucast_probes) < 0) {
@@ -662,7 +647,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
 			ND_PRINTK1(KERN_DEBUG
 				   "%s(): trying to ucast probe in NUD_INVALID: "
 				   NIP6_FMT "\n",
-				   __FUNCTION__,
+				   __func__,
 				   NIP6(*target));
 		}
 		ndisc_send_ns(dev, neigh, target, target, saddr);
@@ -676,18 +661,19 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
 	}
 }
 
-static struct pneigh_entry *pndisc_check_router(struct net_device *dev,
-		struct in6_addr *addr, int *is_router)
+static int pndisc_is_router(const void *pkey,
+			    struct net_device *dev)
 {
 	struct pneigh_entry *n;
+	int ret = -1;
 
 	read_lock_bh(&nd_tbl.lock);
-	n = __pneigh_lookup(&nd_tbl, &init_net, addr, dev);
-	if (n != NULL)
-		*is_router = (n->flags & NTF_ROUTER);
+	n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev);
+	if (n)
+		ret = !!(n->flags & NTF_ROUTER);
 	read_unlock_bh(&nd_tbl.lock);
 
-	return n;
+	return ret;
 }
 
 static void ndisc_recv_ns(struct sk_buff *skb)
@@ -703,10 +689,9 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 	struct inet6_ifaddr *ifp;
 	struct inet6_dev *idev = NULL;
 	struct neighbour *neigh;
-	struct pneigh_entry *pneigh = NULL;
 	int dad = ipv6_addr_any(saddr);
 	int inc;
-	int is_router = 0;
+	int is_router = -1;
 
 	if (ipv6_addr_is_multicast(&msg->target)) {
 		ND_PRINTK2(KERN_WARNING
@@ -756,7 +741,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 
 	inc = ipv6_addr_is_multicast(daddr);
 
-	if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) {
+	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
+	if (ifp) {
 
 		if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
 			if (dad) {
@@ -801,11 +787,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 			return;
 		}
 
-		if (ipv6_chk_acast_addr(dev, &msg->target) ||
+		if (ipv6_chk_acast_addr(dev_net(dev), dev, &msg->target) ||
 		    (idev->cnf.forwarding &&
 		     (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
-		     (pneigh = pndisc_check_router(dev, &msg->target,
-						  &is_router)) != NULL)) {
+		     (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) {
 			if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
 			    skb->pkt_type != PACKET_HOST &&
 			    inc != 0 &&
@@ -826,7 +811,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
 			goto out;
 	}
 
-	is_router = !!(pneigh ? is_router : idev->cnf.forwarding);
+	if (is_router < 0)
+		is_router = !!idev->cnf.forwarding;
 
 	if (dad) {
 		struct in6_addr maddr;
@@ -914,7 +900,8 @@ static void ndisc_recv_na(struct sk_buff *skb)
 			return;
 		}
 	}
-	if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) {
+	ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);
+	if (ifp) {
 		if (ifp->flags & IFA_F_TENTATIVE) {
 			addrconf_dad_failure(ifp);
 			return;
@@ -945,7 +932,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
 		 */
 		if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
 		    ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
-		    pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) {
+		    pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) {
 			/* XXX: idev->cnf.prixy_ndp */
 			goto out;
 		}
@@ -1035,6 +1022,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
 	struct sk_buff *skb;
 	struct nlmsghdr *nlh;
 	struct nduseroptmsg *ndmsg;
+	struct net *net = dev_net(ra->dev);
 	int err;
 	int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg)
 				    + (opt->nd_opt_len << 3));
@@ -1064,7 +1052,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
 		&ipv6_hdr(ra)->saddr);
 	nlmsg_end(skb, nlh);
 
-	err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL,
+	err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL,
 			  GFP_ATOMIC);
 	if (err < 0)
 		goto errout;
@@ -1075,7 +1063,7 @@ nla_put_failure:
 	nlmsg_free(skb);
 	err = -EMSGSIZE;
 errout:
-	rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err);
+	rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
 }
 
 static void ndisc_router_discovery(struct sk_buff *skb)
@@ -1178,7 +1166,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 		if (rt == NULL) {
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() failed to add default route.\n",
-				   __FUNCTION__);
+				   __func__);
 			in6_dev_put(in6_dev);
 			return;
 		}
@@ -1187,7 +1175,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
 		if (neigh == NULL) {
 			ND_PRINTK0(KERN_ERR
 				   "ICMPv6 RA: %s() got default router without neighbour.\n",
-				   __FUNCTION__);
+				   __func__);
 			dst_release(&rt->u.dst);
 			in6_dev_put(in6_dev);
 			return;
@@ -1420,13 +1408,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
 void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 			 struct in6_addr *target)
 {
-	struct sock *sk = ndisc_socket->sk;
+	struct net_device *dev = skb->dev;
+	struct net *net = dev_net(dev);
+	struct sock *sk = net->ipv6.ndisc_sk;
 	int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
 	struct sk_buff *buff;
 	struct icmp6hdr *icmph;
 	struct in6_addr saddr_buf;
 	struct in6_addr *addrp;
-	struct net_device *dev;
 	struct rt6_info *rt;
 	struct dst_entry *dst;
 	struct inet6_dev *idev;
@@ -1436,8 +1425,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 	int err;
 	u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
 
-	dev = skb->dev;
-
 	if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
 		ND_PRINTK2(KERN_WARNING
 			   "ICMPv6 Redirect: no link-local address on %s\n",
@@ -1452,10 +1439,10 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 		return;
 	}
 
-	ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr,
-			dev->ifindex);
+	icmpv6_flow_init(sk, &fl, NDISC_REDIRECT,
+			 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
 
-	dst = ip6_route_output(NULL, &fl);
+	dst = ip6_route_output(net, NULL, &fl);
 	if (dst == NULL)
 		return;
 
@@ -1499,12 +1486,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 	if (buff == NULL) {
 		ND_PRINTK0(KERN_ERR
 			   "ICMPv6 Redirect: %s() failed to allocate an skb.\n",
-			   __FUNCTION__);
+			   __func__);
 		dst_release(dst);
 		return;
 	}
 
-
 	skb_reserve(buff, LL_RESERVED_SPACE(dev));
 	ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr,
 		   IPPROTO_ICMPV6, len);
@@ -1625,18 +1611,16 @@ int ndisc_rcv(struct sk_buff *skb)
 static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
-
-	if (dev->nd_net != &init_net)
-		return NOTIFY_DONE;
+	struct net *net = dev_net(dev);
 
 	switch (event) {
 	case NETDEV_CHANGEADDR:
 		neigh_changeaddr(&nd_tbl, dev);
-		fib6_run_gc(~0UL);
+		fib6_run_gc(~0UL, net);
 		break;
 	case NETDEV_DOWN:
 		neigh_ifdown(&nd_tbl, dev);
-		fib6_run_gc(~0UL);
+		fib6_run_gc(~0UL, net);
 		break;
 	default:
 		break;
@@ -1745,22 +1729,24 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
 
 #endif
 
-int __init ndisc_init(struct net_proto_family *ops)
+static int ndisc_net_init(struct net *net)
 {
+	struct socket *sock;
 	struct ipv6_pinfo *np;
 	struct sock *sk;
 	int err;
 
-	err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket);
+	err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
 	if (err < 0) {
 		ND_PRINTK0(KERN_ERR
 			   "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
 			   err);
-		ndisc_socket = NULL; /* For safety. */
 		return err;
 	}
 
-	sk = ndisc_socket->sk;
+	net->ipv6.ndisc_sk = sk = sock->sk;
+	sk_change_net(sk, net);
+
 	np = inet6_sk(sk);
 	sk->sk_allocation = GFP_ATOMIC;
 	np->hop_limit = 255;
@@ -1768,21 +1754,52 @@ int __init ndisc_init(struct net_proto_family *ops)
 	np->mc_loop = 0;
 	sk->sk_prot->unhash(sk);
 
+	return 0;
+}
+
+static void ndisc_net_exit(struct net *net)
+{
+	sk_release_kernel(net->ipv6.ndisc_sk);
+}
+
+static struct pernet_operations ndisc_net_ops = {
+	.init = ndisc_net_init,
+	.exit = ndisc_net_exit,
+};
+
+int __init ndisc_init(void)
+{
+	int err;
+
+	err = register_pernet_subsys(&ndisc_net_ops);
+	if (err)
+		return err;
 	/*
 	 * Initialize the neighbour table
 	 */
-
 	neigh_table_init(&nd_tbl);
 
 #ifdef CONFIG_SYSCTL
-	neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH,
-			      "ipv6",
-			      &ndisc_ifinfo_sysctl_change,
-			      &ndisc_ifinfo_sysctl_strategy);
+	err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6,
+				    NET_IPV6_NEIGH, "ipv6",
+				    &ndisc_ifinfo_sysctl_change,
+				    &ndisc_ifinfo_sysctl_strategy);
+	if (err)
+		goto out_unregister_pernet;
 #endif
+	err = register_netdevice_notifier(&ndisc_netdev_notifier);
+	if (err)
+		goto out_unregister_sysctl;
+out:
+	return err;
 
-	register_netdevice_notifier(&ndisc_netdev_notifier);
-	return 0;
+out_unregister_sysctl:
+#ifdef CONFIG_SYSCTL
+	neigh_sysctl_unregister(&nd_tbl.parms);
+out_unregister_pernet:
+#endif
+	unregister_pernet_subsys(&ndisc_net_ops);
+	goto out;
 }
 
 void ndisc_cleanup(void)
@@ -1792,6 +1809,5 @@ void ndisc_cleanup(void)
 	neigh_sysctl_unregister(&nd_tbl.parms);
 #endif
 	neigh_table_clear(&nd_tbl);
-	sock_release(ndisc_socket);
-	ndisc_socket = NULL; /* For safety. */
+	unregister_pernet_subsys(&ndisc_net_ops);
 }
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 2e06724dc348..aed51bcc66b4 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -23,7 +23,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
 		    .saddr = iph->saddr, } },
 	};
 
-	dst = ip6_route_output(skb->sk, &fl);
+	dst = ip6_route_output(&init_net, skb->sk, &fl);
 
 #ifdef CONFIG_XFRM
 	if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
@@ -86,7 +86,7 @@ static int nf_ip6_reroute(struct sk_buff *skb,
 
 static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl)
 {
-	*dst = ip6_route_output(NULL, fl);
+	*dst = ip6_route_output(&init_net, NULL, fl);
 	return (*dst)->error;
 }
 
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 8d366f7f2a9a..92a36c9e5402 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -484,7 +484,7 @@ ipq_rcv_dev_event(struct notifier_block *this,
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* Drop any packets associated with the downed device */
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index bf9bb6e55bb5..70ef0d276cc0 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -55,7 +55,7 @@ MODULE_DESCRIPTION("IPv6 packet filter");
 do {								\
 	if (!(x))						\
 		printk("IP_NF_ASSERT: %s:%s:%u\n",		\
-		       __FUNCTION__, __FILE__, __LINE__);	\
+		       __func__, __FILE__, __LINE__);	\
 } while(0)
 #else
 #define IP_NF_ASSERT(x)
@@ -1879,11 +1879,11 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
 
 	switch (cmd) {
 	case IP6T_SO_SET_REPLACE:
-		ret = compat_do_replace(sk->sk_net, user, len);
+		ret = compat_do_replace(sock_net(sk), user, len);
 		break;
 
 	case IP6T_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 1);
+		ret = do_add_counters(sock_net(sk), user, len, 1);
 		break;
 
 	default:
@@ -1990,10 +1990,10 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
 	switch (cmd) {
 	case IP6T_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 1);
+		ret = get_info(sock_net(sk), user, len, 1);
 		break;
 	case IP6T_SO_GET_ENTRIES:
-		ret = compat_get_entries(sk->sk_net, user, len);
+		ret = compat_get_entries(sock_net(sk), user, len);
 		break;
 	default:
 		ret = do_ip6t_get_ctl(sk, cmd, user, len);
@@ -2012,11 +2012,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
 
 	switch (cmd) {
 	case IP6T_SO_SET_REPLACE:
-		ret = do_replace(sk->sk_net, user, len);
+		ret = do_replace(sock_net(sk), user, len);
 		break;
 
 	case IP6T_SO_SET_ADD_COUNTERS:
-		ret = do_add_counters(sk->sk_net, user, len, 0);
+		ret = do_add_counters(sock_net(sk), user, len, 0);
 		break;
 
 	default:
@@ -2037,11 +2037,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
 
 	switch (cmd) {
 	case IP6T_SO_GET_INFO:
-		ret = get_info(sk->sk_net, user, len, 0);
+		ret = get_info(sock_net(sk), user, len, 0);
 		break;
 
 	case IP6T_SO_GET_ENTRIES:
-		ret = get_entries(sk->sk_net, user, len);
+		ret = get_entries(sock_net(sk), user, len);
 		break;
 
 	case IP6T_SO_GET_REVISION_MATCH:
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index b23baa635fe0..baf829075f6f 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -93,7 +93,7 @@ static void send_reset(struct sk_buff *oldskb)
 	fl.fl_ip_sport = otcph.dest;
 	fl.fl_ip_dport = otcph.source;
 	security_skb_classify_flow(oldskb, &fl);
-	dst = ip6_route_output(NULL, &fl);
+	dst = ip6_route_output(&init_net, NULL, &fl);
 	if (dst == NULL)
 		return;
 	if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0))
@@ -177,7 +177,7 @@ reject_tg6(struct sk_buff *skb, const struct net_device *in,
 {
 	const struct ip6t_reject_info *reject = targinfo;
 
-	pr_debug("%s: medium point\n", __FUNCTION__);
+	pr_debug("%s: medium point\n", __func__);
 	/* WARNING: This code causes reentry within ip6tables.
 	   This means that the ip6tables jump stack is now crap.  We
 	   must return an absolute verdict. --RR */
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 24c0d03095bf..9e5f305b2022 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -185,7 +185,7 @@ static void nf_ct_frag6_expire(unsigned long data)
 
 	spin_lock(&fq->q.lock);
 
-	if (fq->q.last_in & COMPLETE)
+	if (fq->q.last_in & INET_FRAG_COMPLETE)
 		goto out;
 
 	fq_kill(fq);
@@ -227,7 +227,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	struct sk_buff *prev, *next;
 	int offset, end;
 
-	if (fq->q.last_in & COMPLETE) {
+	if (fq->q.last_in & INET_FRAG_COMPLETE) {
 		pr_debug("Allready completed\n");
 		goto err;
 	}
@@ -254,11 +254,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		 * or have different end, the segment is corrupted.
 		 */
 		if (end < fq->q.len ||
-		    ((fq->q.last_in & LAST_IN) && end != fq->q.len)) {
+		    ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) {
 			pr_debug("already received last fragment\n");
 			goto err;
 		}
-		fq->q.last_in |= LAST_IN;
+		fq->q.last_in |= INET_FRAG_LAST_IN;
 		fq->q.len = end;
 	} else {
 		/* Check if the fragment is rounded to 8 bytes.
@@ -273,7 +273,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		}
 		if (end > fq->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (fq->q.last_in & LAST_IN) {
+			if (fq->q.last_in & INET_FRAG_LAST_IN) {
 				pr_debug("last packet already reached.\n");
 				goto err;
 			}
@@ -385,7 +385,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	 */
 	if (offset == 0) {
 		fq->nhoffset = nhoff;
-		fq->q.last_in |= FIRST_IN;
+		fq->q.last_in |= INET_FRAG_FIRST_IN;
 	}
 	write_lock(&nf_frags.lock);
 	list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list);
@@ -647,7 +647,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 		goto ret_orig;
 	}
 
-	if (fq->q.last_in == (FIRST_IN|LAST_IN) && fq->q.meat == fq->q.len) {
+	if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
+	    fq->q.meat == fq->q.len) {
 		ret_skb = nf_ct_frag6_reasm(fq, dev);
 		if (ret_skb == NULL)
 			pr_debug("Can't reassemble fragmented packets\n");
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 199ef379e501..ca8b82f96fe5 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -35,16 +35,18 @@ static struct proc_dir_entry *proc_net_devsnmp6;
 
 static int sockstat6_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = seq->private;
+
 	seq_printf(seq, "TCP6: inuse %d\n",
-		       sock_prot_inuse_get(&tcpv6_prot));
+		       sock_prot_inuse_get(net, &tcpv6_prot));
 	seq_printf(seq, "UDP6: inuse %d\n",
-		       sock_prot_inuse_get(&udpv6_prot));
+		       sock_prot_inuse_get(net, &udpv6_prot));
 	seq_printf(seq, "UDPLITE6: inuse %d\n",
-			sock_prot_inuse_get(&udplitev6_prot));
+			sock_prot_inuse_get(net, &udplitev6_prot));
 	seq_printf(seq, "RAW6: inuse %d\n",
-		       sock_prot_inuse_get(&rawv6_prot));
+		       sock_prot_inuse_get(net, &rawv6_prot));
 	seq_printf(seq, "FRAG6: inuse %d memory %d\n",
-		       ip6_frag_nqueues(&init_net), ip6_frag_mem(&init_net));
+		       ip6_frag_nqueues(net), ip6_frag_mem(net));
 	return 0;
 }
 
@@ -183,7 +185,32 @@ static int snmp6_seq_show(struct seq_file *seq, void *v)
 
 static int sockstat6_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, sockstat6_seq_show, NULL);
+	int err;
+	struct net *net;
+
+	err = -ENXIO;
+	net = get_proc_net(inode);
+	if (net == NULL)
+		goto err_net;
+
+	err = single_open(file, sockstat6_seq_show, net);
+	if (err < 0)
+		goto err_open;
+
+	return 0;
+
+err_open:
+	put_net(net);
+err_net:
+	return err;
+}
+
+static int sockstat6_seq_release(struct inode *inode, struct file *file)
+{
+	struct net *net = ((struct seq_file *)file->private_data)->private;
+
+	put_net(net);
+	return single_release(inode, file);
 }
 
 static const struct file_operations sockstat6_seq_fops = {
@@ -191,7 +218,7 @@ static const struct file_operations sockstat6_seq_fops = {
 	.open	 = sockstat6_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = sockstat6_seq_release,
 };
 
 static int snmp6_seq_open(struct inode *inode, struct file *file)
@@ -214,6 +241,9 @@ int snmp6_register_dev(struct inet6_dev *idev)
 	if (!idev || !idev->dev)
 		return -EINVAL;
 
+	if (dev_net(idev->dev) != &init_net)
+		return 0;
+
 	if (!proc_net_devsnmp6)
 		return -ENOENT;
 
@@ -240,27 +270,45 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
 	return 0;
 }
 
+static int ipv6_proc_init_net(struct net *net)
+{
+	if (!proc_net_fops_create(net, "sockstat6", S_IRUGO,
+			&sockstat6_seq_fops))
+		return -ENOMEM;
+	return 0;
+}
+
+static void ipv6_proc_exit_net(struct net *net)
+{
+	proc_net_remove(net, "sockstat6");
+}
+
+static struct pernet_operations ipv6_proc_ops = {
+	.init = ipv6_proc_init_net,
+	.exit = ipv6_proc_exit_net,
+};
+
 int __init ipv6_misc_proc_init(void)
 {
 	int rc = 0;
 
+	if (register_pernet_subsys(&ipv6_proc_ops))
+		goto proc_net_fail;
+
 	if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops))
 		goto proc_snmp6_fail;
 
 	proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net);
 	if (!proc_net_devsnmp6)
 		goto proc_dev_snmp6_fail;
-
-	if (!proc_net_fops_create(&init_net, "sockstat6", S_IRUGO, &sockstat6_seq_fops))
-		goto proc_sockstat6_fail;
 out:
 	return rc;
 
-proc_sockstat6_fail:
-	proc_net_remove(&init_net, "dev_snmp6");
 proc_dev_snmp6_fail:
 	proc_net_remove(&init_net, "snmp6");
 proc_snmp6_fail:
+	unregister_pernet_subsys(&ipv6_proc_ops);
+proc_net_fail:
 	rc = -ENOMEM;
 	goto out;
 }
@@ -270,5 +318,6 @@ void ipv6_misc_proc_exit(void)
 	proc_net_remove(&init_net, "sockstat6");
 	proc_net_remove(&init_net, "dev_snmp6");
 	proc_net_remove(&init_net, "snmp6");
+	unregister_pernet_subsys(&ipv6_proc_ops);
 }
 
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 8897ccf8086a..aae6cedf1709 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -62,20 +62,9 @@
 #include <linux/seq_file.h>
 
 static struct raw_hashinfo raw_v6_hashinfo = {
-	.lock = __RW_LOCK_UNLOCKED(),
+	.lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock),
 };
 
-static void raw_v6_hash(struct sock *sk)
-{
-	raw_hash_sk(sk, &raw_v6_hashinfo);
-}
-
-static void raw_v6_unhash(struct sock *sk)
-{
-	raw_unhash_sk(sk, &raw_v6_hashinfo);
-}
-
-
 static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
 		unsigned short num, struct in6_addr *loc_addr,
 		struct in6_addr *rmt_addr, int dif)
@@ -87,7 +76,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk,
 		if (inet_sk(sk)->num == num) {
 			struct ipv6_pinfo *np = inet6_sk(sk);
 
-			if (sk->sk_net != net)
+			if (!net_eq(sock_net(sk), net))
 				continue;
 
 			if (!ipv6_addr_any(&np->daddr) &&
@@ -179,15 +168,10 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 	read_lock(&raw_v6_hashinfo.lock);
 	sk = sk_head(&raw_v6_hashinfo.ht[hash]);
 
-	/*
-	 *	The first socket found will be delivered after
-	 *	delivery to transport protocols.
-	 */
-
 	if (sk == NULL)
 		goto out;
 
-	net = skb->dev->nd_net;
+	net = dev_net(skb->dev);
 	sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif);
 
 	while (sk) {
@@ -291,7 +275,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 			if (!sk->sk_bound_dev_if)
 				goto out;
 
-			dev = dev_get_by_index(sk->sk_net, sk->sk_bound_dev_if);
+			dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
 			if (!dev) {
 				err = -ENODEV;
 				goto out;
@@ -304,7 +288,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 		v4addr = LOOPBACK4_IPV6;
 		if (!(addr_type & IPV6_ADDR_MULTICAST))	{
 			err = -EADDRNOTAVAIL;
-			if (!ipv6_chk_addr(sk->sk_net, &addr->sin6_addr,
+			if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr,
 					   dev, 0)) {
 				if (dev)
 					dev_put(dev);
@@ -374,7 +358,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
 	if (sk != NULL) {
 		saddr = &ipv6_hdr(skb)->saddr;
 		daddr = &ipv6_hdr(skb)->daddr;
-		net = skb->dev->nd_net;
+		net = dev_net(skb->dev);
 
 		while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr,
 						IP6CB(skb)->iif))) {
@@ -896,9 +880,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
 		else
 			hlimit = np->hop_limit;
 		if (hlimit < 0)
-			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
-		if (hlimit < 0)
-			hlimit = ipv6_get_hoplimit(dst->dev);
+			hlimit = ip6_dst_hoplimit(dst);
 	}
 
 	if (tclass < 0) {
@@ -1184,8 +1166,6 @@ static int rawv6_init_sk(struct sock *sk)
 	return(0);
 }
 
-DEFINE_PROTO_INUSE(rawv6)
-
 struct proto rawv6_prot = {
 	.name		   = "RAWv6",
 	.owner		   = THIS_MODULE,
@@ -1201,14 +1181,14 @@ struct proto rawv6_prot = {
 	.recvmsg	   = rawv6_recvmsg,
 	.bind		   = rawv6_bind,
 	.backlog_rcv	   = rawv6_rcv_skb,
-	.hash		   = raw_v6_hash,
-	.unhash		   = raw_v6_unhash,
+	.hash		   = raw_hash_sk,
+	.unhash		   = raw_unhash_sk,
 	.obj_size	   = sizeof(struct raw6_sock),
+	.h.raw_hash	   = &raw_v6_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_rawv6_setsockopt,
 	.compat_getsockopt = compat_rawv6_getsockopt,
 #endif
-	REF_PROTO_INUSE(rawv6)
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index f936d045a39d..7b247e3a16fe 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -202,7 +202,7 @@ static void ip6_frag_expire(unsigned long data)
 
 	spin_lock(&fq->q.lock);
 
-	if (fq->q.last_in & COMPLETE)
+	if (fq->q.last_in & INET_FRAG_COMPLETE)
 		goto out;
 
 	fq_kill(fq);
@@ -217,7 +217,7 @@ static void ip6_frag_expire(unsigned long data)
 	rcu_read_unlock();
 
 	/* Don't send error if the first segment did not arrive. */
-	if (!(fq->q.last_in&FIRST_IN) || !fq->q.fragments)
+	if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments)
 		goto out;
 
 	/*
@@ -265,7 +265,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	struct net_device *dev;
 	int offset, end;
 
-	if (fq->q.last_in & COMPLETE)
+	if (fq->q.last_in & INET_FRAG_COMPLETE)
 		goto err;
 
 	offset = ntohs(fhdr->frag_off) & ~0x7;
@@ -294,9 +294,9 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 		 * or have different end, the segment is corrupted.
 		 */
 		if (end < fq->q.len ||
-		    ((fq->q.last_in & LAST_IN) && end != fq->q.len))
+		    ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len))
 			goto err;
-		fq->q.last_in |= LAST_IN;
+		fq->q.last_in |= INET_FRAG_LAST_IN;
 		fq->q.len = end;
 	} else {
 		/* Check if the fragment is rounded to 8 bytes.
@@ -314,7 +314,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 		}
 		if (end > fq->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (fq->q.last_in & LAST_IN)
+			if (fq->q.last_in & INET_FRAG_LAST_IN)
 				goto err;
 			fq->q.len = end;
 		}
@@ -417,10 +417,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	 */
 	if (offset == 0) {
 		fq->nhoffset = nhoff;
-		fq->q.last_in |= FIRST_IN;
+		fq->q.last_in |= INET_FRAG_FIRST_IN;
 	}
 
-	if (fq->q.last_in == (FIRST_IN | LAST_IN) && fq->q.meat == fq->q.len)
+	if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
+	    fq->q.meat == fq->q.len)
 		return ip6_frag_reasm(fq, prev, dev);
 
 	write_lock(&ip6_frags.lock);
@@ -600,7 +601,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
 		return 1;
 	}
 
-	net = skb->dev->nd_net;
+	net = dev_net(skb->dev);
 	if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
 		ip6_evictor(net, ip6_dst_idev(skb->dst));
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e8b241cb60bc..cd82b6db35ff 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -40,6 +40,7 @@
 #include <linux/if_arp.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 #include <net/snmp.h>
 #include <net/ipv6.h>
@@ -87,14 +88,16 @@ static void		ip6_link_failure(struct sk_buff *skb);
 static void		ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_add_route_info(struct net *net,
+					   struct in6_addr *prefix, int prefixlen,
 					   struct in6_addr *gwaddr, int ifindex,
 					   unsigned pref);
-static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_get_route_info(struct net *net,
+					   struct in6_addr *prefix, int prefixlen,
 					   struct in6_addr *gwaddr, int ifindex);
 #endif
 
-static struct dst_ops ip6_dst_ops = {
+static struct dst_ops ip6_dst_ops_template = {
 	.family			=	AF_INET6,
 	.protocol		=	__constant_htons(ETH_P_IPV6),
 	.gc			=	ip6_dst_gc,
@@ -124,7 +127,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
 	.entries		=	ATOMIC_INIT(0),
 };
 
-struct rt6_info ip6_null_entry = {
+static struct rt6_info ip6_null_entry_template = {
 	.u = {
 		.dst = {
 			.__refcnt	= ATOMIC_INIT(1),
@@ -134,8 +137,6 @@ struct rt6_info ip6_null_entry = {
 			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
 			.input		= ip6_pkt_discard,
 			.output		= ip6_pkt_discard_out,
-			.ops		= &ip6_dst_ops,
-			.path		= (struct dst_entry*)&ip6_null_entry,
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
@@ -148,7 +149,7 @@ struct rt6_info ip6_null_entry = {
 static int ip6_pkt_prohibit(struct sk_buff *skb);
 static int ip6_pkt_prohibit_out(struct sk_buff *skb);
 
-struct rt6_info ip6_prohibit_entry = {
+struct rt6_info ip6_prohibit_entry_template = {
 	.u = {
 		.dst = {
 			.__refcnt	= ATOMIC_INIT(1),
@@ -158,8 +159,6 @@ struct rt6_info ip6_prohibit_entry = {
 			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
 			.input		= ip6_pkt_prohibit,
 			.output		= ip6_pkt_prohibit_out,
-			.ops		= &ip6_dst_ops,
-			.path		= (struct dst_entry*)&ip6_prohibit_entry,
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
@@ -167,7 +166,7 @@ struct rt6_info ip6_prohibit_entry = {
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
 
-struct rt6_info ip6_blk_hole_entry = {
+static struct rt6_info ip6_blk_hole_entry_template = {
 	.u = {
 		.dst = {
 			.__refcnt	= ATOMIC_INIT(1),
@@ -177,8 +176,6 @@ struct rt6_info ip6_blk_hole_entry = {
 			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
 			.input		= dst_discard,
 			.output		= dst_discard,
-			.ops		= &ip6_dst_ops,
-			.path		= (struct dst_entry*)&ip6_blk_hole_entry,
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
@@ -189,9 +186,9 @@ struct rt6_info ip6_blk_hole_entry = {
 #endif
 
 /* allocate dst with ip6_dst_ops */
-static __inline__ struct rt6_info *ip6_dst_alloc(void)
+static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops)
 {
-	return (struct rt6_info *)dst_alloc(&ip6_dst_ops);
+	return (struct rt6_info *)dst_alloc(ops);
 }
 
 static void ip6_dst_destroy(struct dst_entry *dst)
@@ -211,7 +208,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 	struct rt6_info *rt = (struct rt6_info *)dst;
 	struct inet6_dev *idev = rt->rt6i_idev;
 	struct net_device *loopback_dev =
-		dev->nd_net->loopback_dev;
+		dev_net(dev)->loopback_dev;
 
 	if (dev != loopback_dev && idev != NULL && idev->dev == dev) {
 		struct inet6_dev *loopback_idev =
@@ -239,7 +236,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr)
  *	Route lookup. Any table->tb6_lock is implied.
  */
 
-static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
+static inline struct rt6_info *rt6_device_match(struct net *net,
+						    struct rt6_info *rt,
 						    int oif,
 						    int strict)
 {
@@ -268,7 +266,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
 			return local;
 
 		if (strict)
-			return &ip6_null_entry;
+			return net->ipv6.ip6_null_entry;
 	}
 	return rt;
 }
@@ -409,9 +407,10 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
 static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
 {
 	struct rt6_info *match, *rt0;
+	struct net *net;
 
 	RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
-		  __FUNCTION__, fn->leaf, oif);
+		  __func__, fn->leaf, oif);
 
 	rt0 = fn->rr_ptr;
 	if (!rt0)
@@ -432,15 +431,17 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
 	}
 
 	RT6_TRACE("%s() => %p\n",
-		  __FUNCTION__, match);
+		  __func__, match);
 
-	return (match ? match : &ip6_null_entry);
+	net = dev_net(rt0->rt6i_dev);
+	return (match ? match : net->ipv6.ip6_null_entry);
 }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
 int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
 		  struct in6_addr *gwaddr)
 {
+	struct net *net = dev_net(dev);
 	struct route_info *rinfo = (struct route_info *) opt;
 	struct in6_addr prefix_buf, *prefix;
 	unsigned int pref;
@@ -488,7 +489,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
 		prefix = &prefix_buf;
 	}
 
-	rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex);
+	rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr,
+				dev->ifindex);
 
 	if (rt && !lifetime) {
 		ip6_del_rt(rt);
@@ -496,7 +498,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
 	}
 
 	if (!rt && lifetime)
-		rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
+		rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex,
 					pref);
 	else if (rt)
 		rt->rt6i_flags = RTF_ROUTEINFO |
@@ -515,9 +517,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
 }
 #endif
 
-#define BACKTRACK(saddr) \
+#define BACKTRACK(__net, saddr)			\
 do { \
-	if (rt == &ip6_null_entry) { \
+	if (rt == __net->ipv6.ip6_null_entry) {	\
 		struct fib6_node *pn; \
 		while (1) { \
 			if (fn->fn_flags & RTN_TL_ROOT) \
@@ -533,7 +535,8 @@ do { \
 	} \
 } while(0)
 
-static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_lookup(struct net *net,
+					     struct fib6_table *table,
 					     struct flowi *fl, int flags)
 {
 	struct fib6_node *fn;
@@ -543,8 +546,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
 	fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
 restart:
 	rt = fn->leaf;
-	rt = rt6_device_match(rt, fl->oif, flags);
-	BACKTRACK(&fl->fl6_src);
+	rt = rt6_device_match(net, rt, fl->oif, flags);
+	BACKTRACK(net, &fl->fl6_src);
 out:
 	dst_use(&rt->u.dst, jiffies);
 	read_unlock_bh(&table->tb6_lock);
@@ -552,8 +555,8 @@ out:
 
 }
 
-struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
-			    int oif, int strict)
+struct rt6_info *rt6_lookup(struct net *net, struct in6_addr *daddr,
+			    struct in6_addr *saddr, int oif, int strict)
 {
 	struct flowi fl = {
 		.oif = oif,
@@ -571,7 +574,7 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
 		flags |= RT6_LOOKUP_F_HAS_SADDR;
 	}
 
-	dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
+	dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup);
 	if (dst->error == 0)
 		return (struct rt6_info *) dst;
 
@@ -604,7 +607,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info)
 int ip6_ins_rt(struct rt6_info *rt)
 {
 	struct nl_info info = {
-		.nl_net = &init_net,
+		.nl_net = dev_net(rt->rt6i_dev),
 	};
 	return __ip6_ins_rt(rt, &info);
 }
@@ -660,8 +663,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
 	return rt;
 }
 
-static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif,
-					    struct flowi *fl, int flags)
+static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif,
+				      struct flowi *fl, int flags)
 {
 	struct fib6_node *fn;
 	struct rt6_info *rt, *nrt;
@@ -680,8 +683,9 @@ restart_2:
 
 restart:
 	rt = rt6_select(fn, oif, strict | reachable);
-	BACKTRACK(&fl->fl6_src);
-	if (rt == &ip6_null_entry ||
+
+	BACKTRACK(net, &fl->fl6_src);
+	if (rt == net->ipv6.ip6_null_entry ||
 	    rt->rt6i_flags & RTF_CACHE)
 		goto out;
 
@@ -699,7 +703,7 @@ restart:
 	}
 
 	dst_release(&rt->u.dst);
-	rt = nrt ? : &ip6_null_entry;
+	rt = nrt ? : net->ipv6.ip6_null_entry;
 
 	dst_hold(&rt->u.dst);
 	if (nrt) {
@@ -732,15 +736,16 @@ out2:
 	return rt;
 }
 
-static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table,
 					    struct flowi *fl, int flags)
 {
-	return ip6_pol_route(table, fl->iif, fl, flags);
+	return ip6_pol_route(net, table, fl->iif, fl, flags);
 }
 
 void ip6_route_input(struct sk_buff *skb)
 {
 	struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct net *net = dev_net(skb->dev);
 	int flags = RT6_LOOKUP_F_HAS_SADDR;
 	struct flowi fl = {
 		.iif = skb->dev->ifindex,
@@ -758,16 +763,17 @@ void ip6_route_input(struct sk_buff *skb)
 	if (rt6_need_strict(&iph->daddr))
 		flags |= RT6_LOOKUP_F_IFACE;
 
-	skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
+	skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input);
 }
 
-static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
+static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
 					     struct flowi *fl, int flags)
 {
-	return ip6_pol_route(table, fl->oif, fl, flags);
+	return ip6_pol_route(net, table, fl->oif, fl, flags);
 }
 
-struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
+struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
+				    struct flowi *fl)
 {
 	int flags = 0;
 
@@ -776,8 +782,17 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
 
 	if (!ipv6_addr_any(&fl->fl6_src))
 		flags |= RT6_LOOKUP_F_HAS_SADDR;
+	else if (sk) {
+		unsigned int prefs = inet6_sk(sk)->srcprefs;
+		if (prefs & IPV6_PREFER_SRC_TMP)
+			flags |= RT6_LOOKUP_F_SRCPREF_TMP;
+		if (prefs & IPV6_PREFER_SRC_PUBLIC)
+			flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC;
+		if (prefs & IPV6_PREFER_SRC_COA)
+			flags |= RT6_LOOKUP_F_SRCPREF_COA;
+	}
 
-	return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
+	return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output);
 }
 
 EXPORT_SYMBOL(ip6_route_output);
@@ -886,12 +901,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
 
 static int ipv6_get_mtu(struct net_device *dev);
 
-static inline unsigned int ipv6_advmss(unsigned int mtu)
+static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu)
 {
 	mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
 
-	if (mtu < init_net.ipv6.sysctl.ip6_rt_min_advmss)
-		mtu = init_net.ipv6.sysctl.ip6_rt_min_advmss;
+	if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss)
+		mtu = net->ipv6.sysctl.ip6_rt_min_advmss;
 
 	/*
 	 * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and
@@ -904,21 +919,21 @@ static inline unsigned int ipv6_advmss(unsigned int mtu)
 	return mtu;
 }
 
-static struct dst_entry *ndisc_dst_gc_list;
-static DEFINE_SPINLOCK(ndisc_lock);
+static struct dst_entry *icmp6_dst_gc_list;
+static DEFINE_SPINLOCK(icmp6_dst_lock);
 
-struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
+struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
 				  struct neighbour *neigh,
-				  struct in6_addr *addr,
-				  int (*output)(struct sk_buff *))
+				  struct in6_addr *addr)
 {
 	struct rt6_info *rt;
 	struct inet6_dev *idev = in6_dev_get(dev);
+	struct net *net = dev_net(dev);
 
 	if (unlikely(idev == NULL))
 		return NULL;
 
-	rt = ip6_dst_alloc();
+	rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
 	if (unlikely(rt == NULL)) {
 		in6_dev_put(idev);
 		goto out;
@@ -936,8 +951,8 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
 	atomic_set(&rt->u.dst.__refcnt, 1);
 	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
 	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
-	rt->u.dst.output  = output;
+	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
+	rt->u.dst.output  = ip6_output;
 
 #if 0	/* there's no chance to use these for ndisc */
 	rt->u.dst.flags   = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST
@@ -947,18 +962,18 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
 	rt->rt6i_dst.plen = 128;
 #endif
 
-	spin_lock_bh(&ndisc_lock);
-	rt->u.dst.next = ndisc_dst_gc_list;
-	ndisc_dst_gc_list = &rt->u.dst;
-	spin_unlock_bh(&ndisc_lock);
+	spin_lock_bh(&icmp6_dst_lock);
+	rt->u.dst.next = icmp6_dst_gc_list;
+	icmp6_dst_gc_list = &rt->u.dst;
+	spin_unlock_bh(&icmp6_dst_lock);
 
-	fib6_force_start_gc();
+	fib6_force_start_gc(net);
 
 out:
 	return &rt->u.dst;
 }
 
-int ndisc_dst_gc(int *more)
+int icmp6_dst_gc(int *more)
 {
 	struct dst_entry *dst, *next, **pprev;
 	int freed;
@@ -966,8 +981,8 @@ int ndisc_dst_gc(int *more)
 	next = NULL;
 	freed = 0;
 
-	spin_lock_bh(&ndisc_lock);
-	pprev = &ndisc_dst_gc_list;
+	spin_lock_bh(&icmp6_dst_lock);
+	pprev = &icmp6_dst_gc_list;
 
 	while ((dst = *pprev) != NULL) {
 		if (!atomic_read(&dst->__refcnt)) {
@@ -980,30 +995,33 @@ int ndisc_dst_gc(int *more)
 		}
 	}
 
-	spin_unlock_bh(&ndisc_lock);
+	spin_unlock_bh(&icmp6_dst_lock);
 
 	return freed;
 }
 
 static int ip6_dst_gc(struct dst_ops *ops)
 {
-	static unsigned expire = 30*HZ;
-	static unsigned long last_gc;
 	unsigned long now = jiffies;
-
-	if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) &&
-	    atomic_read(&ip6_dst_ops.entries) <= init_net.ipv6.sysctl.ip6_rt_max_size)
+	struct net *net = ops->dst_net;
+	int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
+	int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
+	int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity;
+	int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout;
+	unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc;
+
+	if (time_after(rt_last_gc + rt_min_interval, now) &&
+	    atomic_read(&ops->entries) <= rt_max_size)
 		goto out;
 
-	expire++;
-	fib6_run_gc(expire);
-	last_gc = now;
-	if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
-		expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
-
+	net->ipv6.ip6_rt_gc_expire++;
+	fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
+	net->ipv6.ip6_rt_last_gc = now;
+	if (atomic_read(&ops->entries) < ops->gc_thresh)
+		net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
 out:
-	expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity;
-	return (atomic_read(&ip6_dst_ops.entries) > init_net.ipv6.sysctl.ip6_rt_max_size);
+	net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity;
+	return (atomic_read(&ops->entries) > rt_max_size);
 }
 
 /* Clean host part of a prefix. Not necessary in radix tree,
@@ -1025,15 +1043,17 @@ static int ipv6_get_mtu(struct net_device *dev)
 	return mtu;
 }
 
-int ipv6_get_hoplimit(struct net_device *dev)
+int ip6_dst_hoplimit(struct dst_entry *dst)
 {
-	int hoplimit = ipv6_devconf.hop_limit;
-	struct inet6_dev *idev;
-
-	idev = in6_dev_get(dev);
-	if (idev) {
-		hoplimit = idev->cnf.hop_limit;
-		in6_dev_put(idev);
+	int hoplimit = dst_metric(dst, RTAX_HOPLIMIT);
+	if (hoplimit < 0) {
+		struct net_device *dev = dst->dev;
+		struct inet6_dev *idev = in6_dev_get(dev);
+		if (idev) {
+			hoplimit = idev->cnf.hop_limit;
+			in6_dev_put(idev);
+		} else
+			hoplimit = ipv6_devconf.hop_limit;
 	}
 	return hoplimit;
 }
@@ -1045,6 +1065,7 @@ int ipv6_get_hoplimit(struct net_device *dev)
 int ip6_route_add(struct fib6_config *cfg)
 {
 	int err;
+	struct net *net = cfg->fc_nlinfo.nl_net;
 	struct rt6_info *rt = NULL;
 	struct net_device *dev = NULL;
 	struct inet6_dev *idev = NULL;
@@ -1059,7 +1080,7 @@ int ip6_route_add(struct fib6_config *cfg)
 #endif
 	if (cfg->fc_ifindex) {
 		err = -ENODEV;
-		dev = dev_get_by_index(&init_net, cfg->fc_ifindex);
+		dev = dev_get_by_index(net, cfg->fc_ifindex);
 		if (!dev)
 			goto out;
 		idev = in6_dev_get(dev);
@@ -1070,13 +1091,13 @@ int ip6_route_add(struct fib6_config *cfg)
 	if (cfg->fc_metric == 0)
 		cfg->fc_metric = IP6_RT_PRIO_USER;
 
-	table = fib6_new_table(cfg->fc_table);
+	table = fib6_new_table(net, cfg->fc_table);
 	if (table == NULL) {
 		err = -ENOBUFS;
 		goto out;
 	}
 
-	rt = ip6_dst_alloc();
+	rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
 
 	if (rt == NULL) {
 		err = -ENOMEM;
@@ -1117,12 +1138,12 @@ int ip6_route_add(struct fib6_config *cfg)
 	if ((cfg->fc_flags & RTF_REJECT) ||
 	    (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {
 		/* hold loopback dev/idev if we haven't done so. */
-		if (dev != init_net.loopback_dev) {
+		if (dev != net->loopback_dev) {
 			if (dev) {
 				dev_put(dev);
 				in6_dev_put(idev);
 			}
-			dev = init_net.loopback_dev;
+			dev = net->loopback_dev;
 			dev_hold(dev);
 			idev = in6_dev_get(dev);
 			if (!idev) {
@@ -1159,7 +1180,7 @@ int ip6_route_add(struct fib6_config *cfg)
 			if (!(gwa_type&IPV6_ADDR_UNICAST))
 				goto out;
 
-			grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1);
+			grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1);
 
 			err = -EHOSTUNREACH;
 			if (grt == NULL)
@@ -1226,10 +1247,13 @@ install_route:
 	if (!rt->u.dst.metrics[RTAX_MTU-1])
 		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
 	if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
 	rt->u.dst.dev = dev;
 	rt->rt6i_idev = idev;
 	rt->rt6i_table = table;
+
+	cfg->fc_nlinfo.nl_net = dev_net(dev);
+
 	return __ip6_ins_rt(rt, &cfg->fc_nlinfo);
 
 out:
@@ -1246,8 +1270,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
 {
 	int err;
 	struct fib6_table *table;
+	struct net *net = dev_net(rt->rt6i_dev);
 
-	if (rt == &ip6_null_entry)
+	if (rt == net->ipv6.ip6_null_entry)
 		return -ENOENT;
 
 	table = rt->rt6i_table;
@@ -1264,7 +1289,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
 int ip6_del_rt(struct rt6_info *rt)
 {
 	struct nl_info info = {
-		.nl_net = &init_net,
+		.nl_net = dev_net(rt->rt6i_dev),
 	};
 	return __ip6_del_rt(rt, &info);
 }
@@ -1276,7 +1301,7 @@ static int ip6_route_del(struct fib6_config *cfg)
 	struct rt6_info *rt;
 	int err = -ESRCH;
 
-	table = fib6_get_table(cfg->fc_table);
+	table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table);
 	if (table == NULL)
 		return err;
 
@@ -1316,7 +1341,8 @@ struct ip6rd_flowi {
 	struct in6_addr gateway;
 };
 
-static struct rt6_info *__ip6_route_redirect(struct fib6_table *table,
+static struct rt6_info *__ip6_route_redirect(struct net *net,
+					     struct fib6_table *table,
 					     struct flowi *fl,
 					     int flags)
 {
@@ -1359,8 +1385,8 @@ restart:
 	}
 
 	if (!rt)
-		rt = &ip6_null_entry;
-	BACKTRACK(&fl->fl6_src);
+		rt = net->ipv6.ip6_null_entry;
+	BACKTRACK(net, &fl->fl6_src);
 out:
 	dst_hold(&rt->u.dst);
 
@@ -1375,6 +1401,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
 					   struct net_device *dev)
 {
 	int flags = RT6_LOOKUP_F_HAS_SADDR;
+	struct net *net = dev_net(dev);
 	struct ip6rd_flowi rdfl = {
 		.fl = {
 			.oif = dev->ifindex,
@@ -1391,7 +1418,8 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
 	if (rt6_need_strict(dest))
 		flags |= RT6_LOOKUP_F_IFACE;
 
-	return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
+	return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl,
+						   flags, __ip6_route_redirect);
 }
 
 void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
@@ -1400,10 +1428,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
 {
 	struct rt6_info *rt, *nrt = NULL;
 	struct netevent_redirect netevent;
+	struct net *net = dev_net(neigh->dev);
 
 	rt = ip6_route_redirect(dest, src, saddr, neigh->dev);
 
-	if (rt == &ip6_null_entry) {
+	if (rt == net->ipv6.ip6_null_entry) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "
 			       "for redirect target\n");
@@ -1448,7 +1477,8 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
 	nrt->rt6i_nexthop = neigh_clone(neigh);
 	/* Reset pmtu, it may be better */
 	nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
-	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst));
+	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
+							dst_mtu(&nrt->u.dst));
 
 	if (ip6_ins_rt(nrt))
 		goto out;
@@ -1476,9 +1506,10 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
 			struct net_device *dev, u32 pmtu)
 {
 	struct rt6_info *rt, *nrt;
+	struct net *net = dev_net(dev);
 	int allfrag = 0;
 
-	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);
+	rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0);
 	if (rt == NULL)
 		return;
 
@@ -1511,7 +1542,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
 		rt->u.dst.metrics[RTAX_MTU-1] = pmtu;
 		if (allfrag)
 			rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
-		dst_set_expires(&rt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires);
+		dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
 		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
 		goto out;
 	}
@@ -1537,7 +1568,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
 		 * which is 10 mins. After 10 mins the decreased pmtu is expired
 		 * and detecting PMTU increase will be automatically happened.
 		 */
-		dst_set_expires(&nrt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires);
+		dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;
 
 		ip6_ins_rt(nrt);
@@ -1552,7 +1583,8 @@ out:
 
 static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
 {
-	struct rt6_info *rt = ip6_dst_alloc();
+	struct net *net = dev_net(ort->rt6i_dev);
+	struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
 
 	if (rt) {
 		rt->u.dst.input = ort->u.dst.input;
@@ -1583,14 +1615,15 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
 }
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
-static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_get_route_info(struct net *net,
+					   struct in6_addr *prefix, int prefixlen,
 					   struct in6_addr *gwaddr, int ifindex)
 {
 	struct fib6_node *fn;
 	struct rt6_info *rt = NULL;
 	struct fib6_table *table;
 
-	table = fib6_get_table(RT6_TABLE_INFO);
+	table = fib6_get_table(net, RT6_TABLE_INFO);
 	if (table == NULL)
 		return NULL;
 
@@ -1614,7 +1647,8 @@ out:
 	return rt;
 }
 
-static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen,
+static struct rt6_info *rt6_add_route_info(struct net *net,
+					   struct in6_addr *prefix, int prefixlen,
 					   struct in6_addr *gwaddr, int ifindex,
 					   unsigned pref)
 {
@@ -1625,6 +1659,9 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle
 		.fc_dst_len	= prefixlen,
 		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO |
 				  RTF_UP | RTF_PREF(pref),
+		.fc_nlinfo.pid = 0,
+		.fc_nlinfo.nlh = NULL,
+		.fc_nlinfo.nl_net = net,
 	};
 
 	ipv6_addr_copy(&cfg.fc_dst, prefix);
@@ -1636,7 +1673,7 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle
 
 	ip6_route_add(&cfg);
 
-	return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
+	return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex);
 }
 #endif
 
@@ -1645,7 +1682,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
 	struct rt6_info *rt;
 	struct fib6_table *table;
 
-	table = fib6_get_table(RT6_TABLE_DFLT);
+	table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT);
 	if (table == NULL)
 		return NULL;
 
@@ -1674,6 +1711,9 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
 		.fc_ifindex	= dev->ifindex,
 		.fc_flags	= RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |
 				  RTF_UP | RTF_EXPIRES | RTF_PREF(pref),
+		.fc_nlinfo.pid = 0,
+		.fc_nlinfo.nlh = NULL,
+		.fc_nlinfo.nl_net = dev_net(dev),
 	};
 
 	ipv6_addr_copy(&cfg.fc_gateway, gwaddr);
@@ -1683,13 +1723,13 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
 	return rt6_get_dflt_router(gwaddr, dev);
 }
 
-void rt6_purge_dflt_routers(void)
+void rt6_purge_dflt_routers(struct net *net)
 {
 	struct rt6_info *rt;
 	struct fib6_table *table;
 
 	/* NOTE: Keep consistent with rt6_get_dflt_router */
-	table = fib6_get_table(RT6_TABLE_DFLT);
+	table = fib6_get_table(net, RT6_TABLE_DFLT);
 	if (table == NULL)
 		return;
 
@@ -1706,7 +1746,8 @@ restart:
 	read_unlock_bh(&table->tb6_lock);
 }
 
-static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg,
+static void rtmsg_to_fib6_config(struct net *net,
+				 struct in6_rtmsg *rtmsg,
 				 struct fib6_config *cfg)
 {
 	memset(cfg, 0, sizeof(*cfg));
@@ -1719,14 +1760,14 @@ static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg,
 	cfg->fc_src_len = rtmsg->rtmsg_src_len;
 	cfg->fc_flags = rtmsg->rtmsg_flags;
 
-	cfg->fc_nlinfo.nl_net = &init_net;
+	cfg->fc_nlinfo.nl_net = net;
 
 	ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst);
 	ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src);
 	ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway);
 }
 
-int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
+int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
 {
 	struct fib6_config cfg;
 	struct in6_rtmsg rtmsg;
@@ -1742,7 +1783,7 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
 		if (err)
 			return -EFAULT;
 
-		rtmsg_to_fib6_config(&rtmsg, &cfg);
+		rtmsg_to_fib6_config(net, &rtmsg, &cfg);
 
 		rtnl_lock();
 		switch (cmd) {
@@ -1821,21 +1862,22 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 				    const struct in6_addr *addr,
 				    int anycast)
 {
-	struct rt6_info *rt = ip6_dst_alloc();
+	struct net *net = dev_net(idev->dev);
+	struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
 
 	if (rt == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	dev_hold(init_net.loopback_dev);
+	dev_hold(net->loopback_dev);
 	in6_dev_hold(idev);
 
 	rt->u.dst.flags = DST_HOST;
 	rt->u.dst.input = ip6_input;
 	rt->u.dst.output = ip6_output;
-	rt->rt6i_dev = init_net.loopback_dev;
+	rt->rt6i_dev = net->loopback_dev;
 	rt->rt6i_idev = idev;
 	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
+	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
 	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
 	rt->u.dst.obsolete = -1;
 
@@ -1852,26 +1894,39 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
 
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
 	rt->rt6i_dst.plen = 128;
-	rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
+	rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);
 
 	atomic_set(&rt->u.dst.__refcnt, 1);
 
 	return rt;
 }
 
+struct arg_dev_net {
+	struct net_device *dev;
+	struct net *net;
+};
+
 static int fib6_ifdown(struct rt6_info *rt, void *arg)
 {
-	if (((void*)rt->rt6i_dev == arg || arg == NULL) &&
-	    rt != &ip6_null_entry) {
+	struct net_device *dev = ((struct arg_dev_net *)arg)->dev;
+	struct net *net = ((struct arg_dev_net *)arg)->net;
+
+	if (((void *)rt->rt6i_dev == dev || dev == NULL) &&
+	    rt != net->ipv6.ip6_null_entry) {
 		RT6_TRACE("deleted by ifdown %p\n", rt);
 		return -1;
 	}
 	return 0;
 }
 
-void rt6_ifdown(struct net_device *dev)
+void rt6_ifdown(struct net *net, struct net_device *dev)
 {
-	fib6_clean_all(fib6_ifdown, 0, dev);
+	struct arg_dev_net adn = {
+		.dev = dev,
+		.net = net,
+	};
+
+	fib6_clean_all(net, fib6_ifdown, 0, &adn);
 }
 
 struct rt6_mtu_change_arg
@@ -1884,6 +1939,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
 {
 	struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;
 	struct inet6_dev *idev;
+	struct net *net = dev_net(arg->dev);
 
 	/* In IPv6 pmtu discovery is not optional,
 	   so that RTAX_MTU lock cannot disable it.
@@ -1915,7 +1971,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
 	     (dst_mtu(&rt->u.dst) < arg->mtu &&
 	      dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) {
 		rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;
-		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu);
+		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
 	}
 	return 0;
 }
@@ -1927,7 +1983,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu)
 		.mtu = mtu,
 	};
 
-	fib6_clean_all(rt6_mtu_change_route, 0, &arg);
+	fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg);
 }
 
 static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = {
@@ -1964,7 +2020,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
 	cfg->fc_nlinfo.nlh = nlh;
-	cfg->fc_nlinfo.nl_net = skb->sk->sk_net;
+	cfg->fc_nlinfo.nl_net = sock_net(skb->sk);
 
 	if (tb[RTA_GATEWAY]) {
 		nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16);
@@ -2010,13 +2066,9 @@ errout:
 
 static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
 	struct fib6_config cfg;
 	int err;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = rtm_to_fib6_config(skb, nlh, &cfg);
 	if (err < 0)
 		return err;
@@ -2026,13 +2078,9 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a
 
 static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
 	struct fib6_config cfg;
 	int err;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = rtm_to_fib6_config(skb, nlh, &cfg);
 	if (err < 0)
 		return err;
@@ -2122,7 +2170,8 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
 		NLA_PUT_U32(skb, RTA_IIF, iif);
 	else if (dst) {
 		struct in6_addr saddr_buf;
-		if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0)
+		if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev,
+				       dst, 0, &saddr_buf) == 0)
 			NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
 	}
 
@@ -2167,7 +2216,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg)
 
 static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
 {
-	struct net *net = in_skb->sk->sk_net;
+	struct net *net = sock_net(in_skb->sk);
 	struct nlattr *tb[RTA_MAX+1];
 	struct rt6_info *rt;
 	struct sk_buff *skb;
@@ -2175,9 +2224,6 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	struct flowi fl;
 	int err, iif = 0;
 
-	if (net != &init_net)
-		return -EINVAL;
-
 	err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy);
 	if (err < 0)
 		goto errout;
@@ -2207,7 +2253,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 
 	if (iif) {
 		struct net_device *dev;
-		dev = __dev_get_by_index(&init_net, iif);
+		dev = __dev_get_by_index(net, iif);
 		if (!dev) {
 			err = -ENODEV;
 			goto errout;
@@ -2226,7 +2272,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 	skb_reset_mac_header(skb);
 	skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr));
 
-	rt = (struct rt6_info*) ip6_route_output(NULL, &fl);
+	rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl);
 	skb->dst = &rt->u.dst;
 
 	err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif,
@@ -2237,7 +2283,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void
 		goto errout;
 	}
 
-	err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid);
+	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
 errout:
 	return err;
 }
@@ -2245,6 +2291,7 @@ errout:
 void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
 {
 	struct sk_buff *skb;
+	struct net *net = info->nl_net;
 	u32 seq;
 	int err;
 
@@ -2263,11 +2310,31 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
 		kfree_skb(skb);
 		goto errout;
 	}
-	err = rtnl_notify(skb, &init_net, info->pid,
-				RTNLGRP_IPV6_ROUTE, info->nlh, gfp_any());
+	err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
+			  info->nlh, gfp_any());
 errout:
 	if (err < 0)
-		rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_ROUTE, err);
+		rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
+}
+
+static int ip6_route_dev_notify(struct notifier_block *this,
+				unsigned long event, void *data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct net *net = dev_net(dev);
+
+	if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) {
+		net->ipv6.ip6_null_entry->u.dst.dev = dev;
+		net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+		net->ipv6.ip6_prohibit_entry->u.dst.dev = dev;
+		net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
+		net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev;
+		net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
+#endif
+	}
+
+	return NOTIFY_OK;
 }
 
 /*
@@ -2316,13 +2383,33 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
 
 static int ipv6_route_show(struct seq_file *m, void *v)
 {
-	fib6_clean_all(rt6_info_route, 0, m);
+	struct net *net = (struct net *)m->private;
+	fib6_clean_all(net, rt6_info_route, 0, m);
 	return 0;
 }
 
 static int ipv6_route_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, ipv6_route_show, NULL);
+	int err;
+	struct net *net = get_proc_net(inode);
+	if (!net)
+		return -ENXIO;
+
+	err = single_open(file, ipv6_route_show, net);
+	if (err < 0) {
+		put_net(net);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ipv6_route_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct net *net = seq->private;
+	put_net(net);
+	return single_release(inode, file);
 }
 
 static const struct file_operations ipv6_route_proc_fops = {
@@ -2330,24 +2417,46 @@ static const struct file_operations ipv6_route_proc_fops = {
 	.open		= ipv6_route_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= single_release,
+	.release	= ipv6_route_release,
 };
 
 static int rt6_stats_seq_show(struct seq_file *seq, void *v)
 {
+	struct net *net = (struct net *)seq->private;
 	seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n",
-		      rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
-		      rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
-		      rt6_stats.fib_rt_cache,
-		      atomic_read(&ip6_dst_ops.entries),
-		      rt6_stats.fib_discarded_routes);
+		   net->ipv6.rt6_stats->fib_nodes,
+		   net->ipv6.rt6_stats->fib_route_nodes,
+		   net->ipv6.rt6_stats->fib_rt_alloc,
+		   net->ipv6.rt6_stats->fib_rt_entries,
+		   net->ipv6.rt6_stats->fib_rt_cache,
+		   atomic_read(&net->ipv6.ip6_dst_ops->entries),
+		   net->ipv6.rt6_stats->fib_discarded_routes);
 
 	return 0;
 }
 
 static int rt6_stats_seq_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, rt6_stats_seq_show, NULL);
+	int err;
+	struct net *net = get_proc_net(inode);
+	if (!net)
+		return -ENXIO;
+
+	err = single_open(file, rt6_stats_seq_show, net);
+	if (err < 0) {
+		put_net(net);
+		return err;
+	}
+
+	return 0;
+}
+
+static int rt6_stats_seq_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+	struct net *net = (struct net *)seq->private;
+	put_net(net);
+	return single_release(inode, file);
 }
 
 static const struct file_operations rt6_stats_seq_fops = {
@@ -2355,42 +2464,8 @@ static const struct file_operations rt6_stats_seq_fops = {
 	.open	 = rt6_stats_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = single_release,
+	.release = rt6_stats_seq_release,
 };
-
-static int ipv6_route_proc_init(struct net *net)
-{
-	int ret = -ENOMEM;
-	if (!proc_net_fops_create(net, "ipv6_route",
-				  0, &ipv6_route_proc_fops))
-		goto out;
-
-	if (!proc_net_fops_create(net, "rt6_stats",
-				  S_IRUGO, &rt6_stats_seq_fops))
-		goto out_ipv6_route;
-
-	ret = 0;
-out:
-	return ret;
-out_ipv6_route:
-	proc_net_remove(net, "ipv6_route");
-	goto out;
-}
-
-static void ipv6_route_proc_fini(struct net *net)
-{
-	proc_net_remove(net, "ipv6_route");
-	proc_net_remove(net, "rt6_stats");
-}
-#else
-static inline int ipv6_route_proc_init(struct net *net)
-{
-	return 0;
-}
-static inline void ipv6_route_proc_fini(struct net *net)
-{
-	return ;
-}
 #endif	/* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SYSCTL
@@ -2399,10 +2474,11 @@ static
 int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
 			      void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-	int delay = init_net.ipv6.sysctl.flush_delay;
+	struct net *net = current->nsproxy->net_ns;
+	int delay = net->ipv6.sysctl.flush_delay;
 	if (write) {
 		proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
-		fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay);
+		fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
 		return 0;
 	} else
 		return -EINVAL;
@@ -2419,7 +2495,7 @@ ctl_table ipv6_route_table_template[] = {
 	{
 		.ctl_name	=	NET_IPV6_ROUTE_GC_THRESH,
 		.procname	=	"gc_thresh",
-		.data		=	&ip6_dst_ops.gc_thresh,
+		.data		=	&ip6_dst_ops_template.gc_thresh,
 		.maxlen		=	sizeof(int),
 		.mode		=	0644,
 		.proc_handler	=	&proc_dointvec,
@@ -2505,33 +2581,141 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
 	table = kmemdup(ipv6_route_table_template,
 			sizeof(ipv6_route_table_template),
 			GFP_KERNEL);
+
+	if (table) {
+		table[0].data = &net->ipv6.sysctl.flush_delay;
+		table[1].data = &net->ipv6.ip6_dst_ops->gc_thresh;
+		table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
+		table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
+		table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
+		table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
+		table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
+		table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
+		table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
+	}
+
 	return table;
 }
 #endif
 
+static int ip6_route_net_init(struct net *net)
+{
+	int ret = 0;
+
+	ret = -ENOMEM;
+	net->ipv6.ip6_dst_ops = kmemdup(&ip6_dst_ops_template,
+					sizeof(*net->ipv6.ip6_dst_ops),
+					GFP_KERNEL);
+	if (!net->ipv6.ip6_dst_ops)
+		goto out;
+	net->ipv6.ip6_dst_ops->dst_net = net;
+
+	net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
+					   sizeof(*net->ipv6.ip6_null_entry),
+					   GFP_KERNEL);
+	if (!net->ipv6.ip6_null_entry)
+		goto out_ip6_dst_ops;
+	net->ipv6.ip6_null_entry->u.dst.path =
+		(struct dst_entry *)net->ipv6.ip6_null_entry;
+	net->ipv6.ip6_null_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
+					       sizeof(*net->ipv6.ip6_prohibit_entry),
+					       GFP_KERNEL);
+	if (!net->ipv6.ip6_prohibit_entry) {
+		kfree(net->ipv6.ip6_null_entry);
+		goto out;
+	}
+	net->ipv6.ip6_prohibit_entry->u.dst.path =
+		(struct dst_entry *)net->ipv6.ip6_prohibit_entry;
+	net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+
+	net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
+					       sizeof(*net->ipv6.ip6_blk_hole_entry),
+					       GFP_KERNEL);
+	if (!net->ipv6.ip6_blk_hole_entry) {
+		kfree(net->ipv6.ip6_null_entry);
+		kfree(net->ipv6.ip6_prohibit_entry);
+		goto out;
+	}
+	net->ipv6.ip6_blk_hole_entry->u.dst.path =
+		(struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
+	net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
+#endif
+
+#ifdef CONFIG_PROC_FS
+	proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops);
+	proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops);
+#endif
+	net->ipv6.ip6_rt_gc_expire = 30*HZ;
+
+	ret = 0;
+out:
+	return ret;
+
+out_ip6_dst_ops:
+	kfree(net->ipv6.ip6_dst_ops);
+	goto out;
+}
+
+static void ip6_route_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+	proc_net_remove(net, "ipv6_route");
+	proc_net_remove(net, "rt6_stats");
+#endif
+	kfree(net->ipv6.ip6_null_entry);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	kfree(net->ipv6.ip6_prohibit_entry);
+	kfree(net->ipv6.ip6_blk_hole_entry);
+#endif
+	kfree(net->ipv6.ip6_dst_ops);
+}
+
+static struct pernet_operations ip6_route_net_ops = {
+	.init = ip6_route_net_init,
+	.exit = ip6_route_net_exit,
+};
+
+static struct notifier_block ip6_route_dev_notifier = {
+	.notifier_call = ip6_route_dev_notify,
+	.priority = 0,
+};
+
 int __init ip6_route_init(void)
 {
 	int ret;
 
-	ip6_dst_ops.kmem_cachep =
+	ret = -ENOMEM;
+	ip6_dst_ops_template.kmem_cachep =
 		kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
 				  SLAB_HWCACHE_ALIGN, NULL);
-	if (!ip6_dst_ops.kmem_cachep)
-		return -ENOMEM;
+	if (!ip6_dst_ops_template.kmem_cachep)
+		goto out;;
 
-	ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
-
-	ret = fib6_init();
+	ret = register_pernet_subsys(&ip6_route_net_ops);
 	if (ret)
 		goto out_kmem_cache;
 
-	ret = ipv6_route_proc_init(&init_net);
+	/* Registering of the loopback is done before this portion of code,
+	 * the loopback reference in rt6_info will not be taken, do it
+	 * manually for init_net */
+	init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #ifdef CONFIG_IPV6_MULTIPLE_TABLES
+	init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+	init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev;
+	init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
+  #endif
+	ret = fib6_init();
 	if (ret)
-		goto out_fib6_init;
+		goto out_register_subsys;
 
 	ret = xfrm6_init();
 	if (ret)
-		goto out_proc_init;
+		goto out_fib6_init;
 
 	ret = fib6_rules_init();
 	if (ret)
@@ -2543,7 +2727,10 @@ int __init ip6_route_init(void)
 	    __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL))
 		goto fib6_rules_init;
 
-	ret = 0;
+	ret = register_netdevice_notifier(&ip6_route_dev_notifier);
+	if (ret)
+		goto fib6_rules_init;
+
 out:
 	return ret;
 
@@ -2551,22 +2738,21 @@ fib6_rules_init:
 	fib6_rules_cleanup();
 xfrm6_init:
 	xfrm6_fini();
-out_proc_init:
-	ipv6_route_proc_fini(&init_net);
 out_fib6_init:
-	rt6_ifdown(NULL);
 	fib6_gc_cleanup();
+out_register_subsys:
+	unregister_pernet_subsys(&ip6_route_net_ops);
 out_kmem_cache:
-	kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
+	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 	goto out;
 }
 
 void ip6_route_cleanup(void)
 {
+	unregister_netdevice_notifier(&ip6_route_dev_notifier);
 	fib6_rules_cleanup();
-	ipv6_route_proc_fini(&init_net);
 	xfrm6_fini();
-	rt6_ifdown(NULL);
 	fib6_gc_cleanup();
-	kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
+	unregister_pernet_subsys(&ip6_route_net_ops);
+	kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
 }
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 1656c003b989..1b8196c8d145 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -339,11 +339,11 @@ out:
 	skb_reset_network_header(skb2);
 
 	/* Try to guess incoming interface */
-	rt6i = rt6_lookup(&iph6->saddr, NULL, NULL, 0);
+	rt6i = rt6_lookup(&init_net, &iph6->saddr, NULL, NULL, 0);
 	if (rt6i && rt6i->rt6i_dev) {
 		skb2->dev = rt6i->rt6i_dev;
 
-		rt6i = rt6_lookup(&iph6->daddr, &iph6->saddr, NULL, 0);
+		rt6i = rt6_lookup(&init_net, &iph6->daddr, &iph6->saddr, NULL, 0);
 
 		if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) {
 			struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev);
@@ -393,7 +393,7 @@ isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev)
 	fl.oif = dev->ifindex;
 	security_skb_classify_flow(skb, &fl);
 
-	dst = ip6_route_output(NULL, &fl);
+	dst = ip6_route_output(&init_net, NULL, &fl);
 	if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) {
 
 		addr6 = (struct in6_addr*)&neigh->primary_key;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
new file mode 100644
index 000000000000..3a622e7abc02
--- /dev/null
+++ b/net/ipv6/syncookies.c
@@ -0,0 +1,267 @@
+/*
+ *  IPv6 Syncookies implementation for the Linux kernel
+ *
+ *  Authors:
+ *  Glenn Griffin	<ggriffin.kernel@gmail.com>
+ *
+ *  Based on IPv4 implementation by Andi Kleen
+ *  linux/net/ipv4/syncookies.c
+ *
+ *	This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/tcp.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/kernel.h>
+#include <net/ipv6.h>
+#include <net/tcp.h>
+
+extern int sysctl_tcp_syncookies;
+extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
+
+#define COOKIEBITS 24	/* Upper bits store count */
+#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
+
+/*
+ * This table has to be sorted and terminated with (__u16)-1.
+ * XXX generate a better table.
+ * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ *
+ * Taken directly from ipv4 implementation.
+ * Should this list be modified for ipv6 use or is it close enough?
+ * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
+ */
+static __u16 const msstab[] = {
+	64 - 1,
+	256 - 1,
+	512 - 1,
+	536 - 1,
+	1024 - 1,
+	1440 - 1,
+	1460 - 1,
+	4312 - 1,
+	(__u16)-1
+};
+/* The number doesn't include the -1 terminator */
+#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
+
+/*
+ * This (misnamed) value is the age of syncookie which is permitted.
+ * Its ideal value should be dependent on TCP_TIMEOUT_INIT and
+ * sysctl_tcp_retries1. It's a rather complicated formula (exponential
+ * backoff) to compute at runtime so it's currently hardcoded here.
+ */
+#define COUNTER_TRIES 4
+
+static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
+					   struct request_sock *req,
+					   struct dst_entry *dst)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct sock *child;
+
+	child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst);
+	if (child)
+		inet_csk_reqsk_queue_add(sk, req, child);
+	else
+		reqsk_free(req);
+
+	return child;
+}
+
+static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS];
+
+static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr,
+		       __be16 sport, __be16 dport, u32 count, int c)
+{
+	__u32 *tmp = __get_cpu_var(cookie_scratch);
+
+	/*
+	 * we have 320 bits of information to hash, copy in the remaining
+	 * 192 bits required for sha_transform, from the syncookie_secret
+	 * and overwrite the digest with the secret
+	 */
+	memcpy(tmp + 10, syncookie_secret[c], 44);
+	memcpy(tmp, saddr, 16);
+	memcpy(tmp + 4, daddr, 16);
+	tmp[8] = ((__force u32)sport << 16) + (__force u32)dport;
+	tmp[9] = count;
+	sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
+
+	return tmp[17];
+}
+
+static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr,
+				   __be16 sport, __be16 dport, __u32 sseq,
+				   __u32 count, __u32 data)
+{
+	return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
+		sseq + (count << COOKIEBITS) +
+		((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
+		& COOKIEMASK));
+}
+
+static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr,
+				  struct in6_addr *daddr, __be16 sport,
+				  __be16 dport, __u32 sseq, __u32 count,
+				  __u32 maxdiff)
+{
+	__u32 diff;
+
+	cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq;
+
+	diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS);
+	if (diff >= maxdiff)
+		return (__u32)-1;
+
+	return (cookie -
+		cookie_hash(saddr, daddr, sport, dport, count - diff, 1))
+		& COOKIEMASK;
+}
+
+__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
+	int mssind;
+	const __u16 mss = *mssp;
+
+	tcp_sk(sk)->last_synq_overflow = jiffies;
+
+	for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
+		;
+	*mssp = msstab[mssind] + 1;
+
+	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT);
+
+	return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source,
+				     th->dest, ntohl(th->seq),
+				     jiffies / (HZ * 60), mssind);
+}
+
+static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
+{
+	struct ipv6hdr *iph = ipv6_hdr(skb);
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 seq = ntohl(th->seq) - 1;
+	__u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr,
+					    th->source, th->dest, seq,
+					    jiffies / (HZ * 60), COUNTER_TRIES);
+
+	return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+}
+
+struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
+{
+	struct inet_request_sock *ireq;
+	struct inet6_request_sock *ireq6;
+	struct tcp_request_sock *treq;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
+	const struct tcphdr *th = tcp_hdr(skb);
+	__u32 cookie = ntohl(th->ack_seq) - 1;
+	struct sock *ret = sk;
+	struct request_sock *req;
+	int mss;
+	struct dst_entry *dst;
+	__u8 rcv_wscale;
+
+	if (!sysctl_tcp_syncookies || !th->ack)
+		goto out;
+
+	if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) ||
+		(mss = cookie_check(skb, cookie)) == 0) {
+		NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED);
+		goto out;
+	}
+
+	NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV);
+
+	ret = NULL;
+	req = inet6_reqsk_alloc(&tcp6_request_sock_ops);
+	if (!req)
+		goto out;
+
+	ireq = inet_rsk(req);
+	ireq6 = inet6_rsk(req);
+	treq = tcp_rsk(req);
+	ireq6->pktopts = NULL;
+
+	if (security_inet_conn_request(sk, skb, req)) {
+		reqsk_free(req);
+		goto out;
+	}
+
+	req->mss = mss;
+	ireq->rmt_port = th->source;
+	ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr);
+	ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr);
+	if (ipv6_opt_accepted(sk, skb) ||
+	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+		atomic_inc(&skb->users);
+		ireq6->pktopts = skb;
+	}
+
+	ireq6->iif = sk->sk_bound_dev_if;
+	/* So that link locals have meaning */
+	if (!sk->sk_bound_dev_if &&
+	    ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+		ireq6->iif = inet6_iif(skb);
+
+	req->expires = 0UL;
+	req->retrans = 0;
+	ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0;
+	ireq->wscale_ok = ireq->sack_ok = 0;
+	treq->rcv_isn = ntohl(th->seq) - 1;
+	treq->snt_isn = cookie;
+
+	/*
+	 * We need to lookup the dst_entry to get the correct window size.
+	 * This is taken from tcp_v6_syn_recv_sock.  Somebody please enlighten
+	 * me if there is a preferred way.
+	 */
+	{
+		struct in6_addr *final_p = NULL, final;
+		struct flowi fl;
+		memset(&fl, 0, sizeof(fl));
+		fl.proto = IPPROTO_TCP;
+		ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
+		if (np->opt && np->opt->srcrt) {
+			struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
+			ipv6_addr_copy(&final, &fl.fl6_dst);
+			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+			final_p = &final;
+		}
+		ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
+		fl.oif = sk->sk_bound_dev_if;
+		fl.fl_ip_dport = inet_rsk(req)->rmt_port;
+		fl.fl_ip_sport = inet_sk(sk)->sport;
+		security_req_classify_flow(req, &fl);
+		if (ip6_dst_lookup(sk, &dst, &fl)) {
+			reqsk_free(req);
+			goto out;
+		}
+		if (final_p)
+			ipv6_addr_copy(&fl.fl6_dst, final_p);
+		if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+			goto out;
+	}
+
+	req->window_clamp = dst_metric(dst, RTAX_WINDOW);
+	tcp_select_initial_window(tcp_full_space(sk), req->mss,
+				  &req->rcv_wnd, &req->window_clamp,
+				  0, &rcv_wscale);
+
+	ireq->rcv_wscale = rcv_wscale;
+
+	ret = get_cookie_sock(sk, skb, req, dst);
+
+out:	return ret;
+}
+
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index d6d3e68086f8..3804dcbbfab0 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -71,24 +71,11 @@ static int ipv6_sysctl_net_init(struct net *net)
 	ipv6_route_table = ipv6_route_sysctl_init(net);
 	if (!ipv6_route_table)
 		goto out_ipv6_table;
+	ipv6_table[0].child = ipv6_route_table;
 
 	ipv6_icmp_table = ipv6_icmp_sysctl_init(net);
 	if (!ipv6_icmp_table)
 		goto out_ipv6_route_table;
-
-	ipv6_route_table[0].data = &net->ipv6.sysctl.flush_delay;
-	/* ipv6_route_table[1].data will be handled when we have
-	   routes per namespace */
-	ipv6_route_table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
-	ipv6_route_table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
-	ipv6_route_table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
-	ipv6_route_table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval;
-	ipv6_route_table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity;
-	ipv6_route_table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires;
-	ipv6_route_table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss;
-	ipv6_table[0].child = ipv6_route_table;
-
-	ipv6_icmp_table[0].data = &net->ipv6.sysctl.icmpv6_time;
 	ipv6_table[1].child = ipv6_icmp_table;
 
 	ipv6_table[2].data = &net->ipv6.sysctl.bindv6only;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 12750f2b05ab..6d851c3c3db9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -69,9 +69,6 @@
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
 
-/* Socket used for sending RSTs and ACKs */
-static struct socket *tcp6_socket;
-
 static void	tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
 static void	tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req);
 static void	tcp_v6_send_check(struct sock *sk, int len,
@@ -324,7 +321,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	struct tcp_sock *tp;
 	__u32 seq;
 
-	sk = inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, &hdr->daddr,
+	sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr,
 			th->dest, &hdr->saddr, th->source, skb->dev->ifindex);
 
 	if (sk == NULL) {
@@ -455,8 +452,7 @@ out:
 }
 
 
-static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
-			      struct dst_entry *dst)
+static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
 {
 	struct inet6_request_sock *treq = inet6_rsk(req);
 	struct ipv6_pinfo *np = inet6_sk(sk);
@@ -464,6 +460,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 	struct ipv6_txoptions *opt = NULL;
 	struct in6_addr * final_p = NULL, final;
 	struct flowi fl;
+	struct dst_entry *dst;
 	int err = -1;
 
 	memset(&fl, 0, sizeof(fl));
@@ -476,24 +473,22 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
 	fl.fl_ip_sport = inet_sk(sk)->sport;
 	security_req_classify_flow(req, &fl);
 
-	if (dst == NULL) {
-		opt = np->opt;
-		if (opt && opt->srcrt) {
-			struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-			ipv6_addr_copy(&final, &fl.fl6_dst);
-			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
-			final_p = &final;
-		}
-
-		err = ip6_dst_lookup(sk, &dst, &fl);
-		if (err)
-			goto done;
-		if (final_p)
-			ipv6_addr_copy(&fl.fl6_dst, final_p);
-		if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
-			goto done;
+	opt = np->opt;
+	if (opt && opt->srcrt) {
+		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+		ipv6_addr_copy(&final, &fl.fl6_dst);
+		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
+		final_p = &final;
 	}
 
+	err = ip6_dst_lookup(sk, &dst, &fl);
+	if (err)
+		goto done;
+	if (final_p)
+		ipv6_addr_copy(&fl.fl6_dst, final_p);
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
+		goto done;
+
 	skb = tcp_make_synack(sk, dst, req);
 	if (skb) {
 		struct tcphdr *th = tcp_hdr(skb);
@@ -514,6 +509,20 @@ done:
 	return err;
 }
 
+static inline void syn_flood_warning(struct sk_buff *skb)
+{
+#ifdef CONFIG_SYN_COOKIES
+	if (sysctl_tcp_syncookies)
+		printk(KERN_INFO
+		       "TCPv6: Possible SYN flooding on port %d. "
+		       "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
+	else
+#endif
+		printk(KERN_INFO
+		       "TCPv6: Possible SYN flooding on port %d. "
+		       "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
+}
+
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
 	if (inet6_rsk(req)->pktopts)
@@ -741,7 +750,7 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
 
 	hp = tcp_get_md5sig_pool();
 	if (!hp) {
-		printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__);
+		printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
 		goto clear_hash_noput;
 	}
 	bp = &hp->md5_blk.ip6;
@@ -781,17 +790,17 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
 	/* Now store the hash into the packet */
 	err = crypto_hash_init(desc);
 	if (err) {
-		printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__);
+		printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
 		goto clear_hash;
 	}
 	err = crypto_hash_update(desc, sg, nbytes);
 	if (err) {
-		printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__);
+		printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
 		goto clear_hash;
 	}
 	err = crypto_hash_final(desc, md5_hash);
 	if (err) {
-		printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__);
+		printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
 		goto clear_hash;
 	}
 
@@ -917,7 +926,7 @@ done_opts:
 }
 #endif
 
-static struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
+struct request_sock_ops tcp6_request_sock_ops __read_mostly = {
 	.family		=	AF_INET6,
 	.obj_size	=	sizeof(struct tcp6_request_sock),
 	.rtx_syn_ack	=	tcp_v6_send_synack,
@@ -979,6 +988,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
 	struct tcphdr *th = tcp_hdr(skb), *t1;
 	struct sk_buff *buff;
 	struct flowi fl;
+	struct net *net = dev_net(skb->dst->dev);
+	struct sock *ctl_sk = net->ipv6.tcp_sk;
 	unsigned int tot_len = sizeof(*th);
 #ifdef CONFIG_TCP_MD5SIG
 	struct tcp_md5sig_key *key;
@@ -1059,11 +1070,14 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
 	fl.fl_ip_sport = t1->source;
 	security_skb_classify_flow(skb, &fl);
 
-	/* sk = NULL, but it is safe for now. RST socket required. */
-	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+	/* Pass a socket to ip6_dst_lookup either it is for RST
+	 * Underlying function will use this to retrieve the network
+	 * namespace
+	 */
+	if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
 
 		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
-			ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
+			ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 			TCP_INC_STATS_BH(TCP_MIB_OUTRSTS);
 			return;
@@ -1079,6 +1093,8 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
 	struct tcphdr *th = tcp_hdr(skb), *t1;
 	struct sk_buff *buff;
 	struct flowi fl;
+	struct net *net = dev_net(skb->dev);
+	struct sock *ctl_sk = net->ipv6.tcp_sk;
 	unsigned int tot_len = sizeof(struct tcphdr);
 	__be32 *topt;
 #ifdef CONFIG_TCP_MD5SIG
@@ -1160,9 +1176,9 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
 	fl.fl_ip_sport = t1->source;
 	security_skb_classify_flow(skb, &fl);
 
-	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+	if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) {
 		if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) {
-			ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0);
+			ip6_xmit(ctl_sk, buff, &fl, NULL, 0);
 			TCP_INC_STATS_BH(TCP_MIB_OUTSEGS);
 			return;
 		}
@@ -1202,7 +1218,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
-	nsk = __inet6_lookup_established(sk->sk_net, &tcp_hashinfo,
+	nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo,
 			&ipv6_hdr(skb)->saddr, th->source,
 			&ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb));
 
@@ -1215,9 +1231,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
 		return NULL;
 	}
 
-#if 0 /*def CONFIG_SYN_COOKIES*/
+#ifdef CONFIG_SYN_COOKIES
 	if (!th->rst && !th->syn && th->ack)
-		sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt));
+		sk = cookie_v6_check(sk, skb);
 #endif
 	return sk;
 }
@@ -1233,6 +1249,11 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	struct tcp_sock *tp = tcp_sk(sk);
 	struct request_sock *req = NULL;
 	__u32 isn = TCP_SKB_CB(skb)->when;
+#ifdef CONFIG_SYN_COOKIES
+	int want_cookie = 0;
+#else
+#define want_cookie 0
+#endif
 
 	if (skb->protocol == htons(ETH_P_IP))
 		return tcp_v4_conn_request(sk, skb);
@@ -1240,12 +1261,14 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 	if (!ipv6_unicast_destination(skb))
 		goto drop;
 
-	/*
-	 *	There are no SYN attacks on IPv6, yet...
-	 */
 	if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
 		if (net_ratelimit())
-			printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n");
+			syn_flood_warning(skb);
+#ifdef CONFIG_SYN_COOKIES
+		if (sysctl_tcp_syncookies)
+			want_cookie = 1;
+		else
+#endif
 		goto drop;
 	}
 
@@ -1266,39 +1289,51 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
 
 	tcp_parse_options(skb, &tmp_opt, 0);
 
+	if (want_cookie) {
+		tcp_clear_options(&tmp_opt);
+		tmp_opt.saw_tstamp = 0;
+	}
+
 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 	tcp_openreq_init(req, &tmp_opt, skb);
 
 	treq = inet6_rsk(req);
 	ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr);
 	ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr);
-	TCP_ECN_create_request(req, tcp_hdr(skb));
 	treq->pktopts = NULL;
-	if (ipv6_opt_accepted(sk, skb) ||
-	    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
-	    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
-		atomic_inc(&skb->users);
-		treq->pktopts = skb;
-	}
-	treq->iif = sk->sk_bound_dev_if;
+	if (!want_cookie)
+		TCP_ECN_create_request(req, tcp_hdr(skb));
+
+	if (want_cookie) {
+		isn = cookie_v6_init_sequence(sk, skb, &req->mss);
+	} else if (!isn) {
+		if (ipv6_opt_accepted(sk, skb) ||
+		    np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
+		    np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
+			atomic_inc(&skb->users);
+			treq->pktopts = skb;
+		}
+		treq->iif = sk->sk_bound_dev_if;
 
-	/* So that link locals have meaning */
-	if (!sk->sk_bound_dev_if &&
-	    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
-		treq->iif = inet6_iif(skb);
+		/* So that link locals have meaning */
+		if (!sk->sk_bound_dev_if &&
+		    ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL)
+			treq->iif = inet6_iif(skb);
 
-	if (isn == 0)
 		isn = tcp_v6_init_sequence(skb);
+	}
 
 	tcp_rsk(req)->snt_isn = isn;
 
 	security_inet_conn_request(sk, skb, req);
 
-	if (tcp_v6_send_synack(sk, req, NULL))
+	if (tcp_v6_send_synack(sk, req))
 		goto drop;
 
-	inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
-	return 0;
+	if (!want_cookie) {
+		inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
+		return 0;
+	}
 
 drop:
 	if (req)
@@ -1704,7 +1739,7 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 	TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
 	TCP_SKB_CB(skb)->sacked = 0;
 
-	sk = __inet6_lookup(skb->dev->nd_net, &tcp_hashinfo,
+	sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo,
 			&ipv6_hdr(skb)->saddr, th->source,
 			&ipv6_hdr(skb)->daddr, ntohs(th->dest),
 			inet6_iif(skb));
@@ -1787,7 +1822,7 @@ do_time_wait:
 	{
 		struct sock *sk2;
 
-		sk2 = inet6_lookup_listener(skb->dev->nd_net, &tcp_hashinfo,
+		sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo,
 					    &ipv6_hdr(skb)->daddr,
 					    ntohs(th->dest), inet6_iif(skb));
 		if (sk2 != NULL) {
@@ -2094,19 +2129,17 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = {
 	.seq_fops	= &tcp6_seq_fops,
 };
 
-int __init tcp6_proc_init(void)
+int tcp6_proc_init(struct net *net)
 {
-	return tcp_proc_register(&tcp6_seq_afinfo);
+	return tcp_proc_register(net, &tcp6_seq_afinfo);
 }
 
-void tcp6_proc_exit(void)
+void tcp6_proc_exit(struct net *net)
 {
-	tcp_proc_unregister(&tcp6_seq_afinfo);
+	tcp_proc_unregister(net, &tcp6_seq_afinfo);
 }
 #endif
 
-DEFINE_PROTO_INUSE(tcpv6)
-
 struct proto tcpv6_prot = {
 	.name			= "TCPv6",
 	.owner			= THIS_MODULE,
@@ -2137,12 +2170,11 @@ struct proto tcpv6_prot = {
 	.obj_size		= sizeof(struct tcp6_sock),
 	.twsk_prot		= &tcp6_timewait_sock_ops,
 	.rsk_prot		= &tcp6_request_sock_ops,
-	.hashinfo		= &tcp_hashinfo,
+	.h.hashinfo		= &tcp_hashinfo,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt	= compat_tcp_setsockopt,
 	.compat_getsockopt	= compat_tcp_getsockopt,
 #endif
-	REF_PROTO_INUSE(tcpv6)
 };
 
 static struct inet6_protocol tcpv6_protocol = {
@@ -2164,6 +2196,31 @@ static struct inet_protosw tcpv6_protosw = {
 				INET_PROTOSW_ICSK,
 };
 
+static int tcpv6_net_init(struct net *net)
+{
+	int err;
+	struct socket *sock;
+	struct sock *sk;
+
+	err = inet_csk_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP);
+	if (err)
+		return err;
+
+	net->ipv6.tcp_sk = sk = sock->sk;
+	sk_change_net(sk, net);
+	return err;
+}
+
+static void tcpv6_net_exit(struct net *net)
+{
+	sk_release_kernel(net->ipv6.tcp_sk);
+}
+
+static struct pernet_operations tcpv6_net_ops = {
+	.init = tcpv6_net_init,
+	.exit = tcpv6_net_exit,
+};
+
 int __init tcpv6_init(void)
 {
 	int ret;
@@ -2177,8 +2234,7 @@ int __init tcpv6_init(void)
 	if (ret)
 		goto out_tcpv6_protocol;
 
-	ret = inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6,
-				       SOCK_RAW, IPPROTO_TCP);
+	ret = register_pernet_subsys(&tcpv6_net_ops);
 	if (ret)
 		goto out_tcpv6_protosw;
 out:
@@ -2193,7 +2249,7 @@ out_tcpv6_protosw:
 
 void tcpv6_exit(void)
 {
-	sock_release(tcp6_socket);
+	unregister_pernet_subsys(&tcpv6_net_ops);
 	inet6_unregister_protosw(&tcpv6_protosw);
 	inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
 }
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 53739de829db..30ef7dc5d403 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -51,9 +51,9 @@
 #include <linux/seq_file.h>
 #include "udp_impl.h"
 
-static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
+int udp_v6_get_port(struct sock *sk, unsigned short snum)
 {
-	return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
+	return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal);
 }
 
 static struct sock *__udp6_lib_lookup(struct net *net,
@@ -70,7 +70,7 @@ static struct sock *__udp6_lib_lookup(struct net *net,
 	sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
 		struct inet_sock *inet = inet_sk(sk);
 
-		if (sk->sk_net == net && sk->sk_hash == hnum &&
+		if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum &&
 				sk->sk_family == PF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(sk);
 			int score = 0;
@@ -235,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 	struct sock *sk;
 	int err;
 
-	sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest,
+	sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest,
 			       saddr, uh->source, inet6_iif(skb), udptable);
 	if (sk == NULL)
 		return;
@@ -323,6 +323,9 @@ static struct sock *udp_v6_mcast_next(struct sock *sk,
 	sk_for_each_from(s, node) {
 		struct inet_sock *inet = inet_sk(s);
 
+		if (sock_net(s) != sock_net(sk))
+			continue;
+
 		if (s->sk_hash == num && s->sk_family == PF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(s);
 			if (inet->dport) {
@@ -480,7 +483,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 	 * check socket cache ... must talk to Alan about his plans
 	 * for sock caches... i'll skip this for now.
 	 */
-	sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source,
+	sk = __udp6_lib_lookup(dev_net(skb->dev), saddr, uh->source,
 			       daddr, uh->dest, inet6_iif(skb), udptable);
 
 	if (sk == NULL) {
@@ -789,9 +792,7 @@ do_udp_sendmsg:
 		else
 			hlimit = np->hop_limit;
 		if (hlimit < 0)
-			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
-		if (hlimit < 0)
-			hlimit = ipv6_get_hoplimit(dst->dev);
+			hlimit = ip6_dst_hoplimit(dst);
 	}
 
 	if (tclass < 0) {
@@ -976,30 +977,30 @@ int udp6_seq_show(struct seq_file *seq, void *v)
 	return 0;
 }
 
-static struct file_operations udp6_seq_fops;
 static struct udp_seq_afinfo udp6_seq_afinfo = {
-	.owner		= THIS_MODULE,
 	.name		= "udp6",
 	.family		= AF_INET6,
 	.hashtable	= udp_hash,
-	.seq_show	= udp6_seq_show,
-	.seq_fops	= &udp6_seq_fops,
+	.seq_fops	= {
+		.owner	=	THIS_MODULE,
+	},
+	.seq_ops	= {
+		.show		= udp6_seq_show,
+	},
 };
 
-int __init udp6_proc_init(void)
+int udp6_proc_init(struct net *net)
 {
-	return udp_proc_register(&udp6_seq_afinfo);
+	return udp_proc_register(net, &udp6_seq_afinfo);
 }
 
-void udp6_proc_exit(void) {
-	udp_proc_unregister(&udp6_seq_afinfo);
+void udp6_proc_exit(struct net *net) {
+	udp_proc_unregister(net, &udp6_seq_afinfo);
 }
 #endif /* CONFIG_PROC_FS */
 
 /* ------------------------------------------------------------------------ */
 
-DEFINE_PROTO_INUSE(udpv6)
-
 struct proto udpv6_prot = {
 	.name		   = "UDPv6",
 	.owner		   = THIS_MODULE,
@@ -1021,11 +1022,11 @@ struct proto udpv6_prot = {
 	.sysctl_wmem	   = &sysctl_udp_wmem_min,
 	.sysctl_rmem	   = &sysctl_udp_rmem_min,
 	.obj_size	   = sizeof(struct udp6_sock),
+	.h.udp_hash	   = udp_hash,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udpv6_setsockopt,
 	.compat_getsockopt = compat_udpv6_getsockopt,
 #endif
-	REF_PROTO_INUSE(udpv6)
 };
 
 static struct inet_protosw udpv6_protosw = {
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 21be3a83e7bc..321b81a4d418 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -11,6 +11,8 @@ extern int  	__udp6_lib_rcv(struct sk_buff *, struct hlist_head [], int );
 extern void 	__udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
 			       int , int , int , __be32 , struct hlist_head []);
 
+extern int	udp_v6_get_port(struct sock *sk, unsigned short snum);
+
 extern int	udpv6_getsockopt(struct sock *sk, int level, int optname,
 				 char __user *optval, int __user *optlen);
 extern int	udpv6_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index 87d4202522ee..491efd00a866 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -35,13 +35,6 @@ static struct inet6_protocol udplitev6_protocol = {
 	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
-{
-	return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal);
-}
-
-DEFINE_PROTO_INUSE(udplitev6)
-
 struct proto udplitev6_prot = {
 	.name		   = "UDPLITEv6",
 	.owner		   = THIS_MODULE,
@@ -58,13 +51,13 @@ struct proto udplitev6_prot = {
 	.backlog_rcv	   = udpv6_queue_rcv_skb,
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
-	.get_port	   = udplite_v6_get_port,
+	.get_port	   = udp_v6_get_port,
 	.obj_size	   = sizeof(struct udp6_sock),
+	.h.udp_hash	   = udplite_hash,
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udpv6_setsockopt,
 	.compat_getsockopt = compat_udpv6_getsockopt,
 #endif
-	REF_PROTO_INUSE(udplitev6)
 };
 
 static struct inet_protosw udplite6_protosw = {
@@ -103,23 +96,40 @@ void udplitev6_exit(void)
 }
 
 #ifdef CONFIG_PROC_FS
-static struct file_operations udplite6_seq_fops;
 static struct udp_seq_afinfo udplite6_seq_afinfo = {
-	.owner		= THIS_MODULE,
 	.name		= "udplite6",
 	.family		= AF_INET6,
 	.hashtable	= udplite_hash,
-	.seq_show	= udp6_seq_show,
-	.seq_fops	= &udplite6_seq_fops,
+	.seq_fops	= {
+		.owner	=	THIS_MODULE,
+	},
+	.seq_ops	= {
+		.show		= udp6_seq_show,
+	},
+};
+
+static int udplite6_proc_init_net(struct net *net)
+{
+	return udp_proc_register(net, &udplite6_seq_afinfo);
+}
+
+static void udplite6_proc_exit_net(struct net *net)
+{
+	udp_proc_unregister(net, &udplite6_seq_afinfo);
+}
+
+static struct pernet_operations udplite6_net_ops = {
+	.init = udplite6_proc_init_net,
+	.exit = udplite6_proc_exit_net,
 };
 
 int __init udplite6_proc_init(void)
 {
-	return udp_proc_register(&udplite6_seq_afinfo);
+	return register_pernet_subsys(&udplite6_net_ops);
 }
 
 void udplite6_proc_exit(void)
 {
-	udp_proc_unregister(&udplite6_seq_afinfo);
+	unregister_pernet_subsys(&udplite6_net_ops);
 }
 #endif
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index a4714d76ae6b..a71c7ddcb41e 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -59,9 +59,6 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		     xfrm_address_t *saddr, u8 proto)
 {
 	struct xfrm_state *x = NULL;
-	int wildcard = 0;
-	xfrm_address_t *xany;
-	int nh = 0;
 	int i = 0;
 
 	/* Allocate new secpath or COW existing one. */
@@ -83,10 +80,9 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 		goto drop;
 	}
 
-	xany = (xfrm_address_t *)&in6addr_any;
-
 	for (i = 0; i < 3; i++) {
 		xfrm_address_t *dst, *src;
+
 		switch (i) {
 		case 0:
 			dst = daddr;
@@ -94,16 +90,13 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 			break;
 		case 1:
 			/* lookup state with wild-card source address */
-			wildcard = 1;
 			dst = daddr;
-			src = xany;
+			src = (xfrm_address_t *)&in6addr_any;
 			break;
-		case 2:
 		default:
 			/* lookup state with wild-card addresses */
-			wildcard = 1; /* XXX */
-			dst = xany;
-			src = xany;
+			dst = (xfrm_address_t *)&in6addr_any;
+			src = (xfrm_address_t *)&in6addr_any;
 			break;
 		}
 
@@ -113,39 +106,19 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
 
 		spin_lock(&x->lock);
 
-		if (wildcard) {
-			if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) {
-				spin_unlock(&x->lock);
-				xfrm_state_put(x);
-				x = NULL;
-				continue;
-			}
-		}
-
-		if (unlikely(x->km.state != XFRM_STATE_VALID)) {
+		if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) &&
+		    likely(x->km.state == XFRM_STATE_VALID) &&
+		    !xfrm_state_check_expire(x)) {
 			spin_unlock(&x->lock);
-			xfrm_state_put(x);
-			x = NULL;
-			continue;
-		}
-		if (xfrm_state_check_expire(x)) {
+			if (x->type->input(x, skb) > 0) {
+				/* found a valid state */
+				break;
+			}
+		} else
 			spin_unlock(&x->lock);
-			xfrm_state_put(x);
-			x = NULL;
-			continue;
-		}
-
-		spin_unlock(&x->lock);
-
-		nh = x->type->input(x, skb);
-		if (nh <= 0) {
-			xfrm_state_put(x);
-			x = NULL;
-			continue;
-		}
 
-		/* Found a state */
-		break;
+		xfrm_state_put(x);
+		x = NULL;
 	}
 
 	if (!x) {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 7d20199ee1f3..8f1e0543b3c4 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -38,7 +38,7 @@ static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
 	if (saddr)
 		memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
 
-	dst = ip6_route_output(NULL, &fl);
+	dst = ip6_route_output(&init_net, NULL, &fl);
 
 	err = dst->error;
 	if (dst->error) {
@@ -57,8 +57,9 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
 	if (IS_ERR(dst))
 		return -EHOSTUNREACH;
 
-	ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
-		       (struct in6_addr *)&saddr->a6);
+	ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev,
+			   (struct in6_addr *)&daddr->a6, 0,
+			   (struct in6_addr *)&saddr->a6);
 	dst_release(dst);
 	return 0;
 }
@@ -246,7 +247,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
 	xdst = (struct xfrm_dst *)dst;
 	if (xdst->u.rt6.rt6i_idev->dev == dev) {
 		struct inet6_dev *loopback_idev =
-			in6_dev_get(dev->nd_net->loopback_dev);
+			in6_dev_get(dev_net(dev)->loopback_dev);
 		BUG_ON(!loopback_idev);
 
 		do {
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index ff1e1db8e236..89884a4f23aa 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -49,125 +49,102 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
 	x->props.family = AF_INET6;
 }
 
+/* distribution counting sort function for xfrm_state and xfrm_tmpl */
 static int
-__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
+__xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass)
 {
 	int i;
-	int j = 0;
+	int class[XFRM_MAX_DEPTH];
+	int count[maxclass];
 
-	/* Rule 1: select IPsec transport except AH */
-	for (i = 0; i < n; i++) {
-		if (src[i]->props.mode == XFRM_MODE_TRANSPORT &&
-		    src[i]->id.proto != IPPROTO_AH) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
-	}
-	if (j == n)
-		goto end;
+	memset(count, 0, sizeof(count));
 
-	/* Rule 2: select MIPv6 RO or inbound trigger */
-#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
 	for (i = 0; i < n; i++) {
-		if (src[i] &&
-		    (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
-		     src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
+		int c;
+		class[i] = c = cmp(src[i]);
+		count[c]++;
 	}
-	if (j == n)
-		goto end;
-#endif
 
-	/* Rule 3: select IPsec transport AH */
-	for (i = 0; i < n; i++) {
-		if (src[i] &&
-		    src[i]->props.mode == XFRM_MODE_TRANSPORT &&
-		    src[i]->id.proto == IPPROTO_AH) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
-	}
-	if (j == n)
-		goto end;
+	for (i = 2; i < maxclass; i++)
+		count[i] += count[i - 1];
 
-	/* Rule 4: select IPsec tunnel */
 	for (i = 0; i < n; i++) {
-		if (src[i] &&
-		    (src[i]->props.mode == XFRM_MODE_TUNNEL ||
-		     src[i]->props.mode == XFRM_MODE_BEET)) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
+		dst[count[class[i] - 1]++] = src[i];
+		src[i] = 0;
 	}
-	if (likely(j == n))
-		goto end;
 
-	/* Final rule */
-	for (i = 0; i < n; i++) {
-		if (src[i]) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
-	}
-
- end:
 	return 0;
 }
 
-static int
-__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
+/*
+ * Rule for xfrm_state:
+ *
+ * rule 1: select IPsec transport except AH
+ * rule 2: select MIPv6 RO or inbound trigger
+ * rule 3: select IPsec transport AH
+ * rule 4: select IPsec tunnel
+ * rule 5: others
+ */
+static int __xfrm6_state_sort_cmp(void *p)
 {
-	int i;
-	int j = 0;
-
-	/* Rule 1: select IPsec transport */
-	for (i = 0; i < n; i++) {
-		if (src[i]->mode == XFRM_MODE_TRANSPORT) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
-	}
-	if (j == n)
-		goto end;
-
-	/* Rule 2: select MIPv6 RO or inbound trigger */
+	struct xfrm_state *v = p;
+
+	switch (v->props.mode) {
+	case XFRM_MODE_TRANSPORT:
+		if (v->id.proto != IPPROTO_AH)
+			return 1;
+		else
+			return 3;
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-	for (i = 0; i < n; i++) {
-		if (src[i] &&
-		    (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
-		     src[i]->mode == XFRM_MODE_IN_TRIGGER)) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
-	}
-	if (j == n)
-		goto end;
+	case XFRM_MODE_ROUTEOPTIMIZATION:
+	case XFRM_MODE_IN_TRIGGER:
+		return 2;
 #endif
-
-	/* Rule 3: select IPsec tunnel */
-	for (i = 0; i < n; i++) {
-		if (src[i] &&
-		    (src[i]->mode == XFRM_MODE_TUNNEL ||
-		     src[i]->mode == XFRM_MODE_BEET)) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
+	case XFRM_MODE_TUNNEL:
+	case XFRM_MODE_BEET:
+		return 4;
 	}
-	if (likely(j == n))
-		goto end;
+	return 5;
+}
 
-	/* Final rule */
-	for (i = 0; i < n; i++) {
-		if (src[i]) {
-			dst[j++] = src[i];
-			src[i] = NULL;
-		}
+static int
+__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
+{
+	return __xfrm6_sort((void **)dst, (void **)src, n,
+			    __xfrm6_state_sort_cmp, 6);
+}
+
+/*
+ * Rule for xfrm_tmpl:
+ *
+ * rule 1: select IPsec transport
+ * rule 2: select MIPv6 RO or inbound trigger
+ * rule 3: select IPsec tunnel
+ * rule 4: others
+ */
+static int __xfrm6_tmpl_sort_cmp(void *p)
+{
+	struct xfrm_tmpl *v = p;
+	switch (v->mode) {
+	case XFRM_MODE_TRANSPORT:
+		return 1;
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+	case XFRM_MODE_ROUTEOPTIMIZATION:
+	case XFRM_MODE_IN_TRIGGER:
+		return 2;
+#endif
+	case XFRM_MODE_TUNNEL:
+	case XFRM_MODE_BEET:
+		return 3;
 	}
+	return 4;
+}
 
- end:
-	return 0;
+static int
+__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
+{
+	return __xfrm6_sort((void **)dst, (void **)src, n,
+			    __xfrm6_tmpl_sort_cmp, 5);
 }
 
 int xfrm6_extract_header(struct sk_buff *skb)
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 639fe8a6ff1e..c2b278138604 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -140,12 +140,26 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
 
 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
 
+static int __xfrm6_tunnel_spi_check(u32 spi)
+{
+	struct xfrm6_tunnel_spi *x6spi;
+	int index = xfrm6_tunnel_spi_hash_byspi(spi);
+	struct hlist_node *pos;
+
+	hlist_for_each_entry(x6spi, pos,
+			     &xfrm6_tunnel_spi_byspi[index],
+			     list_byspi) {
+		if (x6spi->spi == spi)
+			return -1;
+	}
+	return index;
+}
+
 static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
 {
 	u32 spi;
 	struct xfrm6_tunnel_spi *x6spi;
-	struct hlist_node *pos;
-	unsigned index;
+	int index;
 
 	if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN ||
 	    xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX)
@@ -154,32 +168,19 @@ static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
 		xfrm6_tunnel_spi++;
 
 	for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
-		index = xfrm6_tunnel_spi_hash_byspi(spi);
-		hlist_for_each_entry(x6spi, pos,
-				     &xfrm6_tunnel_spi_byspi[index],
-				     list_byspi) {
-			if (x6spi->spi == spi)
-				goto try_next_1;
-		}
-		xfrm6_tunnel_spi = spi;
-		goto alloc_spi;
-try_next_1:;
+		index = __xfrm6_tunnel_spi_check(spi);
+		if (index >= 0)
+			goto alloc_spi;
 	}
 	for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) {
-		index = xfrm6_tunnel_spi_hash_byspi(spi);
-		hlist_for_each_entry(x6spi, pos,
-				     &xfrm6_tunnel_spi_byspi[index],
-				     list_byspi) {
-			if (x6spi->spi == spi)
-				goto try_next_2;
-		}
-		xfrm6_tunnel_spi = spi;
-		goto alloc_spi;
-try_next_2:;
+		index = __xfrm6_tunnel_spi_check(spi);
+		if (index >= 0)
+			goto alloc_spi;
 	}
 	spi = 0;
 	goto out;
 alloc_spi:
+	xfrm6_tunnel_spi = spi;
 	x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
 	if (!x6spi)
 		goto out;
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index c76a9523091b..81ae8735f5e3 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -335,7 +335,7 @@ static int ipxitf_device_event(struct notifier_block *notifier,
 	struct net_device *dev = ptr;
 	struct ipx_interface *i, *tmp;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event != NETDEV_DOWN && event != NETDEV_UP)
@@ -1636,7 +1636,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty
 	u16 ipx_pktsize;
 	int rc = 0;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	/* Not ours */
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 240b0cbfb532..ae54b20d0470 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -85,14 +85,14 @@ static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb)
 	struct sock *sk;
 	int err;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	self = instance;
 	sk = instance;
 
 	err = sock_queue_rcv_skb(sk, skb);
 	if (err) {
-		IRDA_DEBUG(1, "%s(), error: no more mem!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), error: no more mem!\n", __func__);
 		self->rx_flow = FLOW_STOP;
 
 		/* When we return error, TTP will need to requeue the skb */
@@ -116,7 +116,7 @@ static void irda_disconnect_indication(void *instance, void *sap,
 
 	self = instance;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	/* Don't care about it, but let's not leak it */
 	if(skb)
@@ -125,7 +125,7 @@ static void irda_disconnect_indication(void *instance, void *sap,
 	sk = instance;
 	if (sk == NULL) {
 		IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n",
-			   __FUNCTION__, self);
+			   __func__, self);
 		return;
 	}
 
@@ -181,7 +181,7 @@ static void irda_connect_confirm(void *instance, void *sap,
 
 	self = instance;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	sk = instance;
 	if (sk == NULL) {
@@ -203,7 +203,7 @@ static void irda_connect_confirm(void *instance, void *sap,
 	case SOCK_STREAM:
 		if (max_sdu_size != 0) {
 			IRDA_ERROR("%s: max_sdu_size must be 0\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
@@ -211,7 +211,7 @@ static void irda_connect_confirm(void *instance, void *sap,
 	case SOCK_SEQPACKET:
 		if (max_sdu_size == 0) {
 			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 		self->max_data_size = max_sdu_size;
@@ -220,7 +220,7 @@ static void irda_connect_confirm(void *instance, void *sap,
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
 	}
 
-	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
 		   self->max_data_size);
 
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
@@ -245,7 +245,7 @@ static void irda_connect_indication(void *instance, void *sap,
 
 	self = instance;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	sk = instance;
 	if (sk == NULL) {
@@ -264,7 +264,7 @@ static void irda_connect_indication(void *instance, void *sap,
 	case SOCK_STREAM:
 		if (max_sdu_size != 0) {
 			IRDA_ERROR("%s: max_sdu_size must be 0\n",
-				   __FUNCTION__);
+				   __func__);
 			kfree_skb(skb);
 			return;
 		}
@@ -273,7 +273,7 @@ static void irda_connect_indication(void *instance, void *sap,
 	case SOCK_SEQPACKET:
 		if (max_sdu_size == 0) {
 			IRDA_ERROR("%s: max_sdu_size cannot be 0\n",
-				   __FUNCTION__);
+				   __func__);
 			kfree_skb(skb);
 			return;
 		}
@@ -283,7 +283,7 @@ static void irda_connect_indication(void *instance, void *sap,
 		self->max_data_size = irttp_get_max_seg_size(self->tsap);
 	}
 
-	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__,
 		   self->max_data_size);
 
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
@@ -302,13 +302,13 @@ static void irda_connect_response(struct irda_sock *self)
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
 			GFP_ATOMIC);
 	if (skb == NULL) {
 		IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 
@@ -329,7 +329,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 	struct irda_sock *self;
 	struct sock *sk;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	self = instance;
 	sk = instance;
@@ -338,17 +338,17 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 	switch (flow) {
 	case FLOW_STOP:
 		IRDA_DEBUG(1, "%s(), IrTTP wants us to slow down\n",
-			   __FUNCTION__);
+			   __func__);
 		self->tx_flow = flow;
 		break;
 	case FLOW_START:
 		self->tx_flow = flow;
 		IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n",
-			   __FUNCTION__);
+			   __func__);
 		wake_up_interruptible(sk->sk_sleep);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __func__);
 		/* Unknown flow command, better stop */
 		self->tx_flow = flow;
 		break;
@@ -370,11 +370,11 @@ static void irda_getvalue_confirm(int result, __u16 obj_id,
 
 	self = (struct irda_sock *) priv;
 	if (!self) {
-		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
+		IRDA_WARNING("%s: lost myself!\n", __func__);
 		return;
 	}
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	/* We probably don't need to make any more queries */
 	iriap_close(self->iriap);
@@ -382,7 +382,7 @@ static void irda_getvalue_confirm(int result, __u16 obj_id,
 
 	/* Check if request succeeded */
 	if (result != IAS_SUCCESS) {
-		IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __func__,
 			   result);
 
 		self->errno = result;	/* We really need it later */
@@ -415,11 +415,11 @@ static void irda_selective_discovery_indication(discinfo_t *discovery,
 {
 	struct irda_sock *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	self = (struct irda_sock *) priv;
 	if (!self) {
-		IRDA_WARNING("%s: lost myself!\n", __FUNCTION__);
+		IRDA_WARNING("%s: lost myself!\n", __func__);
 		return;
 	}
 
@@ -442,7 +442,7 @@ static void irda_discovery_timeout(u_long priv)
 {
 	struct irda_sock *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	self = (struct irda_sock *) priv;
 	BUG_ON(self == NULL);
@@ -467,7 +467,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
 	notify_t notify;
 
 	if (self->tsap) {
-		IRDA_WARNING("%s: busy!\n", __FUNCTION__);
+		IRDA_WARNING("%s: busy!\n", __func__);
 		return -EBUSY;
 	}
 
@@ -486,7 +486,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name)
 				     &notify);
 	if (self->tsap == NULL) {
 		IRDA_DEBUG(0, "%s(), Unable to allocate TSAP!\n",
-			   __FUNCTION__);
+			   __func__);
 		return -ENOMEM;
 	}
 	/* Remember which TSAP selector we actually got */
@@ -507,7 +507,7 @@ static int irda_open_lsap(struct irda_sock *self, int pid)
 	notify_t notify;
 
 	if (self->lsap) {
-		IRDA_WARNING("%s(), busy!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), busy!\n", __func__);
 		return -EBUSY;
 	}
 
@@ -519,7 +519,7 @@ static int irda_open_lsap(struct irda_sock *self, int pid)
 
 	self->lsap = irlmp_open_lsap(LSAP_CONNLESS, &notify, pid);
 	if (self->lsap == NULL) {
-		IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __FUNCTION__);
+		IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -540,11 +540,11 @@ static int irda_open_lsap(struct irda_sock *self, int pid)
  */
 static int irda_find_lsap_sel(struct irda_sock *self, char *name)
 {
-	IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name);
+	IRDA_DEBUG(2, "%s(%p, %s)\n", __func__, self, name);
 
 	if (self->iriap) {
 		IRDA_WARNING("%s(): busy with a previous query\n",
-			     __FUNCTION__);
+			     __func__);
 		return -EBUSY;
 	}
 
@@ -580,7 +580,7 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
 	switch (self->ias_result->type) {
 	case IAS_INTEGER:
 		IRDA_DEBUG(4, "%s() int=%d\n",
-			   __FUNCTION__, self->ias_result->t.integer);
+			   __func__, self->ias_result->t.integer);
 
 		if (self->ias_result->t.integer != -1)
 			self->dtsap_sel = self->ias_result->t.integer;
@@ -589,7 +589,7 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name)
 		break;
 	default:
 		self->dtsap_sel = 0;
-		IRDA_DEBUG(0, "%s(), bad type!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), bad type!\n", __func__);
 		break;
 	}
 	if (self->ias_result)
@@ -627,7 +627,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 	__u32	daddr = DEV_ADDR_ANY;	/* Address we found the service on */
 	__u8	dtsap_sel = 0x0;	/* TSAP associated with it */
 
-	IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name);
+	IRDA_DEBUG(2, "%s(), name=%s\n", __func__, name);
 
 	/* Ask lmp for the current discovery log
 	 * Note : we have to use irlmp_get_discoveries(), as opposed
@@ -649,7 +649,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 		self->daddr = discoveries[i].daddr;
 		self->saddr = 0x0;
 		IRDA_DEBUG(1, "%s(), trying daddr = %08x\n",
-			   __FUNCTION__, self->daddr);
+			   __func__, self->daddr);
 
 		/* Query remote LM-IAS for this service */
 		err = irda_find_lsap_sel(self, name);
@@ -658,7 +658,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 			/* We found the requested service */
 			if(daddr != DEV_ADDR_ANY) {
 				IRDA_DEBUG(1, "%s(), discovered service ''%s'' in two different devices !!!\n",
-					   __FUNCTION__, name);
+					   __func__, name);
 				self->daddr = DEV_ADDR_ANY;
 				kfree(discoveries);
 				return(-ENOTUNIQ);
@@ -672,7 +672,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 			break;
 		default:
 			/* Something bad did happen :-( */
-			IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __func__);
 			self->daddr = DEV_ADDR_ANY;
 			kfree(discoveries);
 			return(-EHOSTUNREACH);
@@ -685,7 +685,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 	/* Check out what we found */
 	if(daddr == DEV_ADDR_ANY) {
 		IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n",
-			   __FUNCTION__, name);
+			   __func__, name);
 		self->daddr = DEV_ADDR_ANY;
 		return(-EADDRNOTAVAIL);
 	}
@@ -696,7 +696,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name)
 	self->dtsap_sel = dtsap_sel;
 
 	IRDA_DEBUG(1, "%s(), discovered requested service ''%s'' at address %08x\n",
-		   __FUNCTION__, name, self->daddr);
+		   __func__, name, self->daddr);
 
 	return 0;
 }
@@ -727,8 +727,8 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr,
 		saddr.sir_addr = self->saddr;
 	}
 
-	IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __FUNCTION__, saddr.sir_lsap_sel);
-	IRDA_DEBUG(1, "%s(), addr = %08x\n", __FUNCTION__, saddr.sir_addr);
+	IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel);
+	IRDA_DEBUG(1, "%s(), addr = %08x\n", __func__, saddr.sir_addr);
 
 	/* uaddr_len come to us uninitialised */
 	*uaddr_len = sizeof (struct sockaddr_irda);
@@ -747,7 +747,7 @@ static int irda_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) &&
 	    (sk->sk_type != SOCK_DGRAM))
@@ -776,7 +776,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	struct irda_sock *self = irda_sk(sk);
 	int err;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	if (addr_len != sizeof(struct sockaddr_irda))
 		return -EINVAL;
@@ -787,7 +787,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 	    (sk->sk_protocol == IRDAPROTO_ULTRA)) {
 		self->pid = addr->sir_lsap_sel;
 		if (self->pid & 0x80) {
-			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
 			return -EOPNOTSUPP;
 		}
 		err = irda_open_lsap(self, self->pid);
@@ -835,9 +835,9 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
 	struct sk_buff *skb;
 	int err;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
-	err = irda_create(sk->sk_net, newsock, sk->sk_protocol);
+	err = irda_create(sock_net(sk), newsock, sk->sk_protocol);
 	if (err)
 		return err;
 
@@ -893,7 +893,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags)
 	/* Now attach up the new socket */
 	new->tsap = irttp_dup(self->tsap, new);
 	if (!new->tsap) {
-		IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
 		kfree_skb(skb);
 		return -1;
 	}
@@ -954,7 +954,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
 	struct irda_sock *self = irda_sk(sk);
 	int err;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	/* Don't allow connect for Ultra sockets */
 	if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA))
@@ -984,13 +984,13 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
 		/* Try to find one suitable */
 		err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name);
 		if (err) {
-			IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __func__);
 			return err;
 		}
 	} else {
 		/* Use the one provided by the user */
 		self->daddr = addr->sir_addr;
-		IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr);
+		IRDA_DEBUG(1, "%s(), daddr = %08x\n", __func__, self->daddr);
 
 		/* If we don't have a valid service name, we assume the
 		 * user want to connect on a specific LSAP. Prevent
@@ -1000,7 +1000,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
 			/* Query remote LM-IAS using service name */
 			err = irda_find_lsap_sel(self, addr->sir_name);
 			if (err) {
-				IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+				IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
 				return err;
 			}
 		} else {
@@ -1025,7 +1025,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr,
 				    self->saddr, self->daddr, NULL,
 				    self->max_sdu_size_rx, NULL);
 	if (err) {
-		IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
 		return err;
 	}
 
@@ -1068,7 +1068,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
 	struct sock *sk;
 	struct irda_sock *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	if (net != &init_net)
 		return -EAFNOSUPPORT;
@@ -1089,7 +1089,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
 		return -ENOMEM;
 
 	self = irda_sk(sk);
-	IRDA_DEBUG(2, "%s() : self is %p\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s() : self is %p\n", __func__, self);
 
 	init_waitqueue_head(&self->query_wait);
 
@@ -1149,7 +1149,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol)
  */
 static void irda_destroy_socket(struct irda_sock *self)
 {
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	/* Unregister with IrLMP */
 	irlmp_unregister_client(self->ckey);
@@ -1186,7 +1186,7 @@ static int irda_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	if (sk == NULL)
 		return 0;
@@ -1254,7 +1254,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
 	struct sk_buff *skb;
 	int err = -EPIPE;
 
-	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+	IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
 
 	/* Note : socket.c set MSG_EOR on SEQPACKET sockets */
 	if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT |
@@ -1282,7 +1282,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
 	/* Check that we don't send out too big frames */
 	if (len > self->max_data_size) {
 		IRDA_DEBUG(2, "%s(), Chopping frame from %zd to %d bytes!\n",
-			   __FUNCTION__, len, self->max_data_size);
+			   __func__, len, self->max_data_size);
 		len = self->max_data_size;
 	}
 
@@ -1306,7 +1306,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock,
 	 */
 	err = irttp_data_request(self->tsap, skb);
 	if (err) {
-		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+		IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
 		goto out_err;
 	}
 	/* Tell client how much data we actually sent */
@@ -1332,7 +1332,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	size_t copied;
 	int err;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	if ((err = sock_error(sk)) < 0)
 		return err;
@@ -1347,7 +1347,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
 
 	if (copied > size) {
 		IRDA_DEBUG(2, "%s(), Received truncated frame (%zd < %zd)!\n",
-			   __FUNCTION__, copied, size);
+			   __func__, copied, size);
 		copied = size;
 		msg->msg_flags |= MSG_TRUNC;
 	}
@@ -1363,7 +1363,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	 */
 	if (self->rx_flow == FLOW_STOP) {
 		if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
-			IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
 			self->rx_flow = FLOW_START;
 			irttp_flow_request(self->tsap, FLOW_START);
 		}
@@ -1385,7 +1385,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
 	int target, err;
 	long timeo;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	if ((err = sock_error(sk)) < 0)
 		return err;
@@ -1459,14 +1459,14 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
 			/* put the skb back if we didn't use it up.. */
 			if (skb->len) {
 				IRDA_DEBUG(1, "%s(), back on q!\n",
-					   __FUNCTION__);
+					   __func__);
 				skb_queue_head(&sk->sk_receive_queue, skb);
 				break;
 			}
 
 			kfree_skb(skb);
 		} else {
-			IRDA_DEBUG(0, "%s() questionable!?\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s() questionable!?\n", __func__);
 
 			/* put message back and return */
 			skb_queue_head(&sk->sk_receive_queue, skb);
@@ -1482,7 +1482,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
 	 */
 	if (self->rx_flow == FLOW_STOP) {
 		if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) {
-			IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__);
 			self->rx_flow = FLOW_START;
 			irttp_flow_request(self->tsap, FLOW_START);
 		}
@@ -1506,7 +1506,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	struct sk_buff *skb;
 	int err;
 
-	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+	IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
 
 	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
 		return -EINVAL;
@@ -1528,7 +1528,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	if (len > self->max_data_size) {
 		IRDA_DEBUG(0, "%s(), Warning to much data! "
 			   "Chopping frame from %zd to %d bytes!\n",
-			   __FUNCTION__, len, self->max_data_size);
+			   __func__, len, self->max_data_size);
 		len = self->max_data_size;
 	}
 
@@ -1540,7 +1540,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	skb_reserve(skb, self->max_header_size);
 	skb_reset_transport_header(skb);
 
-	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
 	skb_put(skb, len);
 	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
@@ -1554,7 +1554,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock,
 	 */
 	err = irttp_udata_request(self->tsap, skb);
 	if (err) {
-		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+		IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
 		return err;
 	}
 	return len;
@@ -1577,7 +1577,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 	struct sk_buff *skb;
 	int err;
 
-	IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len);
+	IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len);
 
 	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT))
 		return -EINVAL;
@@ -1600,7 +1600,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 
 		pid = addr->sir_lsap_sel;
 		if (pid & 0x80) {
-			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__);
 			return -EOPNOTSUPP;
 		}
 	} else {
@@ -1609,7 +1609,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 		if ((self->lsap == NULL) ||
 		    (sk->sk_state != TCP_ESTABLISHED)) {
 			IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n",
-				   __FUNCTION__);
+				   __func__);
 			return -ENOTCONN;
 		}
 		/* Use PID from socket */
@@ -1623,7 +1623,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 	if (len > self->max_data_size) {
 		IRDA_DEBUG(0, "%s(), Warning to much data! "
 			   "Chopping frame from %zd to %d bytes!\n",
-			   __FUNCTION__, len, self->max_data_size);
+			   __func__, len, self->max_data_size);
 		len = self->max_data_size;
 	}
 
@@ -1635,7 +1635,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 	skb_reserve(skb, self->max_header_size);
 	skb_reset_transport_header(skb);
 
-	IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s(), appending user data\n", __func__);
 	skb_put(skb, len);
 	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
 	if (err) {
@@ -1646,7 +1646,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock,
 	err = irlmp_connless_data_request((bound ? self->lsap : NULL),
 					  skb, pid);
 	if (err) {
-		IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err);
+		IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err);
 		return err;
 	}
 	return len;
@@ -1661,7 +1661,7 @@ static int irda_shutdown(struct socket *sock, int how)
 	struct sock *sk = sock->sk;
 	struct irda_sock *self = irda_sk(sk);
 
-	IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(1, "%s(%p)\n", __func__, self);
 
 	sk->sk_state       = TCP_CLOSE;
 	sk->sk_shutdown   |= SEND_SHUTDOWN;
@@ -1696,7 +1696,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
 	struct irda_sock *self = irda_sk(sk);
 	unsigned int mask;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	poll_wait(file, sk->sk_sleep, wait);
 	mask = 0;
@@ -1705,7 +1705,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
 	if (sk->sk_err)
 		mask |= POLLERR;
 	if (sk->sk_shutdown & RCV_SHUTDOWN) {
-		IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
 		mask |= POLLHUP;
 	}
 
@@ -1719,7 +1719,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock,
 	switch (sk->sk_type) {
 	case SOCK_STREAM:
 		if (sk->sk_state == TCP_CLOSE) {
-			IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__);
 			mask |= POLLHUP;
 		}
 
@@ -1755,7 +1755,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
 
-	IRDA_DEBUG(4, "%s(), cmd=%#x\n", __FUNCTION__, cmd);
+	IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd);
 
 	switch (cmd) {
 	case TIOCOUTQ: {
@@ -1796,7 +1796,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 	case SIOCSIFMETRIC:
 		return -EINVAL;
 	default:
-		IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__);
 		return -ENOIOCTLCMD;
 	}
 
@@ -1833,7 +1833,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
 	struct ias_attrib *	ias_attr;	/* Attribute in IAS object */
 	int opt, free_ias = 0;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	if (level != SOL_IRLMP)
 		return -ENOPROTOOPT;
@@ -2012,7 +2012,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
 
 		/* Check is the user space own the object */
 		if(ias_attr->value->owner != IAS_USER_ATTR) {
-			IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__);
 			kfree(ias_opt);
 			return -EPERM;
 		}
@@ -2031,11 +2031,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname,
 		/* Only possible for a seqpacket service (TTP with SAR) */
 		if (sk->sk_type != SOCK_SEQPACKET) {
 			IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n",
-				   __FUNCTION__, opt);
+				   __func__, opt);
 			self->max_sdu_size_rx = opt;
 		} else {
 			IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n",
-				     __FUNCTION__);
+				     __func__);
 			return -ENOPROTOOPT;
 		}
 		break;
@@ -2149,7 +2149,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
 	int err;
 	int offset, total;
 
-	IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(2, "%s(%p)\n", __func__, self);
 
 	if (level != SOL_IRLMP)
 		return -ENOPROTOOPT;
@@ -2310,7 +2310,7 @@ bed:
 		/* Check that we can proceed with IAP */
 		if (self->iriap) {
 			IRDA_WARNING("%s: busy with a previous query\n",
-				     __FUNCTION__);
+				     __func__);
 			kfree(ias_opt);
 			return -EBUSY;
 		}
@@ -2406,7 +2406,7 @@ bed:
 		if (!self->cachedaddr) {
 			int ret = 0;
 
-			IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__);
 
 			/* Set watchdog timer to expire in <val> ms. */
 			self->errno = 0;
@@ -2424,14 +2424,14 @@ bed:
 			if(timer_pending(&(self->watchdog)))
 				del_timer(&(self->watchdog));
 
-			IRDA_DEBUG(1, "%s(), ...waking up !\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__);
 
 			if (ret != 0)
 				return ret;
 		}
 		else
 			IRDA_DEBUG(1, "%s(), found immediately !\n",
-				   __FUNCTION__);
+				   __func__);
 
 		/* Tell IrLMP that we have been notified */
 		irlmp_update_client(self->ckey, self->mask.word,
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index 80c33f408e3f..bfacef8b76f4 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -110,7 +110,7 @@ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
 {
 	discovery_t *discovery;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/*
 	 *  If log is missing this means that IrLAP was unable to perform the
@@ -157,7 +157,7 @@ void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force)
 	int			i = 0;		/* How many we expired */
 
 	IRDA_ASSERT(log != NULL, return;);
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	spin_lock_irqsave(&log->hb_spinlock, flags);
 
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index 6eef1f2a7553..018c92941aba 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -70,7 +70,7 @@ static int __init ircomm_init(void)
 {
 	ircomm = hashbin_new(HB_LOCK);
 	if (ircomm == NULL) {
-		IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
 		return -ENOMEM;
 	}
 
@@ -91,7 +91,7 @@ static int __init ircomm_init(void)
 
 static void __exit ircomm_cleanup(void)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
 
@@ -111,7 +111,7 @@ struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
 	struct ircomm_cb *self = NULL;
 	int ret;
 
-	IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __func__ ,
 		   service_type);
 
 	IRDA_ASSERT(ircomm != NULL, return NULL;);
@@ -155,7 +155,7 @@ EXPORT_SYMBOL(ircomm_open);
  */
 static int __ircomm_close(struct ircomm_cb *self)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Disconnect link if any */
 	ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
@@ -191,7 +191,7 @@ int ircomm_close(struct ircomm_cb *self)
 	IRDA_ASSERT(self != NULL, return -EIO;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	entry = hashbin_remove(ircomm, self->line, NULL);
 
@@ -216,7 +216,7 @@ int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel,
 	struct ircomm_info info;
 	int ret;
 
-	IRDA_DEBUG(2 , "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2 , "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
@@ -245,7 +245,7 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 {
 	int clen = 0;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Check if the packet contains data on the control channel */
 	if (skb->len > 0)
@@ -261,7 +261,7 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 						info->qos, info->max_data_size,
 						info->max_header_size, skb);
 	else {
-		IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 	}
 }
 
@@ -278,7 +278,7 @@ int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
 
@@ -296,7 +296,7 @@ EXPORT_SYMBOL(ircomm_connect_response);
 void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
 			    struct ircomm_info *info)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	if (self->notify.connect_confirm )
 		self->notify.connect_confirm(self->notify.instance,
@@ -304,7 +304,7 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
 					     info->max_data_size,
 					     info->max_header_size, skb);
 	else {
-		IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 	}
 }
 
@@ -318,7 +318,7 @@ int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
 {
 	int ret;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -EFAULT;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
@@ -339,14 +339,14 @@ EXPORT_SYMBOL(ircomm_data_request);
  */
 void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(skb->len > 0, return;);
 
 	if (self->notify.data_indication)
 		self->notify.data_indication(self->notify.instance, self, skb);
 	else {
-		IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 	}
 }
 
@@ -372,7 +372,7 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
 	 */
 	if (unlikely(skb->len < (clen + 1))) {
 		IRDA_DEBUG(2, "%s() throwing away illegal frame\n",
-			   __FUNCTION__ );
+			   __func__ );
 		return;
 	}
 
@@ -391,7 +391,7 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
 		ircomm_data_indication(self, skb);
 	else {
 		IRDA_DEBUG(4, "%s(), data was control info only!\n",
-			   __FUNCTION__ );
+			   __func__ );
 	}
 }
 
@@ -405,7 +405,7 @@ int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
 {
 	int ret;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -EFAULT;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
@@ -427,7 +427,7 @@ EXPORT_SYMBOL(ircomm_control_request);
 static void ircomm_control_indication(struct ircomm_cb *self,
 				      struct sk_buff *skb, int clen)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Use udata for delivering data on the control channel */
 	if (self->notify.udata_indication) {
@@ -448,7 +448,7 @@ static void ircomm_control_indication(struct ircomm_cb *self,
 		 * see ircomm_tty_control_indication(). */
 		dev_kfree_skb(ctrl_skb);
 	} else {
-		IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 	}
 }
 
@@ -463,7 +463,7 @@ int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
 	struct ircomm_info info;
 	int ret;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
@@ -484,7 +484,7 @@ EXPORT_SYMBOL(ircomm_disconnect_request);
 void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 				  struct ircomm_info *info)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(info != NULL, return;);
 
@@ -492,7 +492,7 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
 		self->notify.disconnect_indication(self->notify.instance, self,
 						   info->reason, skb);
 	} else {
-		IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), missing handler\n", __func__ );
 	}
 }
 
@@ -504,7 +504,7 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
  */
 void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c
index 8ba4e59ece16..c35b3ef5c2f0 100644
--- a/net/irda/ircomm/ircomm_event.c
+++ b/net/irda/ircomm/ircomm_event.c
@@ -108,7 +108,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
 		ircomm_connect_indication(self, skb, info);
 		break;
 	default:
-		IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(4, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_event[event]);
 		ret = -EINVAL;
 	}
@@ -138,7 +138,7 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event,
 		ircomm_disconnect_indication(self, skb, info);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(0, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_event[event]);
 		ret = -EINVAL;
 	}
@@ -171,7 +171,7 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
 		ircomm_disconnect_indication(self, skb, info);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
 			   ircomm_event[event]);
 		ret = -EINVAL;
 	}
@@ -213,7 +213,7 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
 		ret = self->issue.disconnect_request(self, skb, info);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ ,
 			   ircomm_event[event]);
 		ret = -EINVAL;
 	}
@@ -229,7 +229,7 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
 int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event,
 		    struct sk_buff *skb, struct ircomm_info *info)
 {
-	IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_state[self->state], ircomm_event[event]);
 
 	return (*state[self->state])(self, event, skb, info);
@@ -245,6 +245,6 @@ void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state)
 {
 	self->state = state;
 
-	IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
+	IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __func__ ,
 		   ircomm_state[self->state], self->service_type);
 }
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
index 55860ee4e39e..67c99d20857f 100644
--- a/net/irda/ircomm/ircomm_lmp.c
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -53,7 +53,7 @@ static int ircomm_lmp_connect_request(struct ircomm_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	/* Don't forget to refcount it - should be NULL anyway */
 	if(userdata)
@@ -76,7 +76,7 @@ static int ircomm_lmp_connect_response(struct ircomm_cb *self,
 	struct sk_buff *tx_skb;
 	int ret;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	/* Any userdata supplied? */
 	if (userdata == NULL) {
@@ -111,7 +111,7 @@ static int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
 	struct sk_buff *tx_skb;
 	int ret;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	if (!userdata) {
 		tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
@@ -148,13 +148,13 @@ static void ircomm_lmp_flow_control(struct sk_buff *skb)
 
 	cb = (struct irda_skb_cb *) skb->cb;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	line = cb->line;
 
 	self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
 	if (!self) {
-		IRDA_DEBUG(2, "%s(), didn't find myself\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ );
 		return;
 	}
 
@@ -164,7 +164,7 @@ static void ircomm_lmp_flow_control(struct sk_buff *skb)
 	self->pkt_count--;
 
 	if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) {
-		IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ );
 		self->flow_status = FLOW_START;
 		if (self->notify.flow_indication)
 			self->notify.flow_indication(self->notify.instance,
@@ -191,7 +191,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self,
 
 	cb->line = self->line;
 
-	IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s(), sending frame\n", __func__ );
 
 	/* Don't forget to refcount it - see ircomm_tty_do_softint() */
 	skb_get(skb);
@@ -199,7 +199,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self,
 	skb->destructor = ircomm_lmp_flow_control;
 
 	if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) {
-		IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ );
 		self->flow_status = FLOW_STOP;
 		if (self->notify.flow_indication)
 			self->notify.flow_indication(self->notify.instance,
@@ -207,7 +207,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self,
 	}
 	ret = irlmp_data_request(self->lsap, skb);
 	if (ret) {
-		IRDA_ERROR("%s(), failed\n", __FUNCTION__);
+		IRDA_ERROR("%s(), failed\n", __func__);
 		/* irlmp_data_request already free the packet */
 	}
 
@@ -225,7 +225,7 @@ static int ircomm_lmp_data_indication(void *instance, void *sap,
 {
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
@@ -255,7 +255,7 @@ static void ircomm_lmp_connect_confirm(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -288,7 +288,7 @@ static void ircomm_lmp_connect_indication(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *)instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -318,7 +318,7 @@ static void ircomm_lmp_disconnect_indication(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -341,7 +341,7 @@ int ircomm_open_lsap(struct ircomm_cb *self)
 {
 	notify_t notify;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	/* Register callbacks */
 	irda_notify_init(&notify);
@@ -354,7 +354,7 @@ int ircomm_open_lsap(struct ircomm_cb *self)
 
 	self->lsap = irlmp_open_lsap(LSAP_ANY, &notify, 0);
 	if (!self->lsap) {
-		IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __FUNCTION__ );
+		IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ );
 		return -1;
 	}
 	self->slsap_sel = self->lsap->slsap_sel;
diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
index 598dcbe4a501..d57aefd9fe77 100644
--- a/net/irda/ircomm/ircomm_param.c
+++ b/net/irda/ircomm/ircomm_param.c
@@ -103,7 +103,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 	struct sk_buff *skb;
 	int count;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -136,7 +136,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 	count = irda_param_insert(self, pi, skb_tail_pointer(skb),
 				  skb_tailroom(skb), &ircomm_param_info);
 	if (count < 0) {
-		IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__);
+		IRDA_WARNING("%s(), no room for parameter!\n", __func__);
 		spin_unlock_irqrestore(&self->spinlock, flags);
 		return -1;
 	}
@@ -144,7 +144,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 
 	spin_unlock_irqrestore(&self->spinlock, flags);
 
-	IRDA_DEBUG(2, "%s(), skb->len=%d\n", __FUNCTION__ , skb->len);
+	IRDA_DEBUG(2, "%s(), skb->len=%d\n", __func__ , skb->len);
 
 	if (flush) {
 		/* ircomm_tty_do_softint will take care of the rest */
@@ -179,10 +179,10 @@ static int ircomm_param_service_type(void *instance, irda_param_t *param,
 	service_type &= self->service_type;
 	if (!service_type) {
 		IRDA_DEBUG(2,
-			   "%s(), No common service type to use!\n", __FUNCTION__ );
+			   "%s(), No common service type to use!\n", __func__ );
 		return -1;
 	}
-	IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ ,
+	IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ ,
 		   service_type);
 
 	/*
@@ -197,7 +197,7 @@ static int ircomm_param_service_type(void *instance, irda_param_t *param,
 	else if (service_type & IRCOMM_3_WIRE_RAW)
 		self->settings.service_type = IRCOMM_3_WIRE_RAW;
 
-	IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __FUNCTION__ ,
+	IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __func__ ,
 		   self->settings.service_type);
 
 	/*
@@ -240,7 +240,7 @@ static int ircomm_param_port_type(void *instance, irda_param_t *param, int get)
 	else {
 		self->settings.port_type = (__u8) param->pv.i;
 
-		IRDA_DEBUG(0, "%s(), port type=%d\n", __FUNCTION__ ,
+		IRDA_DEBUG(0, "%s(), port type=%d\n", __func__ ,
 			   self->settings.port_type);
 	}
 	return 0;
@@ -260,9 +260,9 @@ static int ircomm_param_port_name(void *instance, irda_param_t *param, int get)
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	if (get) {
-		IRDA_DEBUG(0, "%s(), not imp!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), not imp!\n", __func__ );
 	} else {
-		IRDA_DEBUG(0, "%s(), port-name=%s\n", __FUNCTION__ , param->pv.c);
+		IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , param->pv.c);
 		strncpy(self->settings.port_name, param->pv.c, 32);
 	}
 
@@ -287,7 +287,7 @@ static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get)
 	else
 		self->settings.data_rate = param->pv.i;
 
-	IRDA_DEBUG(2, "%s(), data rate = %d\n", __FUNCTION__ , param->pv.i);
+	IRDA_DEBUG(2, "%s(), data rate = %d\n", __func__ , param->pv.i);
 
 	return 0;
 }
@@ -333,7 +333,7 @@ static int ircomm_param_flow_control(void *instance, irda_param_t *param,
 	else
 		self->settings.flow_control = (__u8) param->pv.i;
 
-	IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
+	IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __func__ , (__u8) param->pv.i);
 
 	return 0;
 }
@@ -359,7 +359,7 @@ static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get)
 		self->settings.xonxoff[1] = (__u16) param->pv.i >> 8;
 	}
 
-	IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __FUNCTION__ ,
+	IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ ,
 		   param->pv.i & 0xff, param->pv.i >> 8);
 
 	return 0;
@@ -386,7 +386,7 @@ static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
 		self->settings.enqack[1] = (__u16) param->pv.i >> 8;
 	}
 
-	IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __FUNCTION__ ,
+	IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ ,
 		   param->pv.i & 0xff, param->pv.i >> 8);
 
 	return 0;
@@ -401,7 +401,7 @@ static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get)
 static int ircomm_param_line_status(void *instance, irda_param_t *param,
 				    int get)
 {
-	IRDA_DEBUG(2, "%s(), not impl.\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s(), not impl.\n", __func__ );
 
 	return 0;
 }
@@ -462,7 +462,7 @@ static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	__u8 dce;
 
-	IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i);
+	IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __func__ , (__u8) param->pv.i);
 
 	dce = (__u8) param->pv.i;
 
@@ -474,7 +474,7 @@ static int ircomm_param_dce(void *instance, irda_param_t *param, int get)
 	/* Check if any of the settings have changed */
 	if (dce & 0x0f) {
 		if (dce & IRCOMM_DELTA_CTS) {
-			IRDA_DEBUG(2, "%s(), CTS \n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), CTS \n", __func__ );
 		}
 	}
 
diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c
index 712eafd0cc76..6e6509f22f60 100644
--- a/net/irda/ircomm/ircomm_ttp.c
+++ b/net/irda/ircomm/ircomm_ttp.c
@@ -78,7 +78,7 @@ int ircomm_open_tsap(struct ircomm_cb *self)
 {
 	notify_t notify;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	/* Register callbacks */
 	irda_notify_init(&notify);
@@ -93,7 +93,7 @@ int ircomm_open_tsap(struct ircomm_cb *self)
 	self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT,
 				     &notify);
 	if (!self->tsap) {
-		IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ );
 		return -1;
 	}
 	self->slsap_sel = self->tsap->stsap_sel;
@@ -121,7 +121,7 @@ static int ircomm_ttp_connect_request(struct ircomm_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	/* Don't forget to refcount it - should be NULL anyway */
 	if(userdata)
@@ -145,7 +145,7 @@ static int ircomm_ttp_connect_response(struct ircomm_cb *self,
 {
 	int ret;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	/* Don't forget to refcount it - should be NULL anyway */
 	if(userdata)
@@ -173,7 +173,7 @@ static int ircomm_ttp_data_request(struct ircomm_cb *self,
 
 	IRDA_ASSERT(skb != NULL, return -1;);
 
-	IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen);
+	IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen);
 
 	/*
 	 * Insert clen field, currently we either send data only, or control
@@ -190,7 +190,7 @@ static int ircomm_ttp_data_request(struct ircomm_cb *self,
 
 	ret = irttp_data_request(self->tsap, skb);
 	if (ret) {
-		IRDA_ERROR("%s(), failed\n", __FUNCTION__);
+		IRDA_ERROR("%s(), failed\n", __func__);
 		/* irttp_data_request already free the packet */
 	}
 
@@ -208,7 +208,7 @@ static int ircomm_ttp_data_indication(void *instance, void *sap,
 {
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
@@ -231,7 +231,7 @@ static void ircomm_ttp_connect_confirm(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -240,7 +240,7 @@ static void ircomm_ttp_connect_confirm(void *instance, void *sap,
 
 	if (max_sdu_size != TTP_SAR_DISABLE) {
 		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
-			   __FUNCTION__);
+			   __func__);
 		goto out;
 	}
 
@@ -272,7 +272,7 @@ static void ircomm_ttp_connect_indication(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *)instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -281,7 +281,7 @@ static void ircomm_ttp_connect_indication(void *instance, void *sap,
 
 	if (max_sdu_size != TTP_SAR_DISABLE) {
 		IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n",
-			   __FUNCTION__);
+			   __func__);
 		goto out;
 	}
 
@@ -331,7 +331,7 @@ static void ircomm_ttp_disconnect_indication(void *instance, void *sap,
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 	struct ircomm_info info;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
@@ -356,7 +356,7 @@ static void ircomm_ttp_flow_indication(void *instance, void *sap,
 {
 	struct ircomm_cb *self = (struct ircomm_cb *) instance;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;);
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index be627e1f04d8..d2620410cb0a 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -115,7 +115,7 @@ static int __init ircomm_tty_init(void)
 		return -ENOMEM;
 	ircomm_tty = hashbin_new(HB_LOCK);
 	if (ircomm_tty == NULL) {
-		IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__);
 		put_tty_driver(driver);
 		return -ENOMEM;
 	}
@@ -133,7 +133,7 @@ static int __init ircomm_tty_init(void)
 	tty_set_operations(driver, &ops);
 	if (tty_register_driver(driver)) {
 		IRDA_ERROR("%s(): Couldn't register serial driver\n",
-			   __FUNCTION__);
+			   __func__);
 		put_tty_driver(driver);
 		return -1;
 	}
@@ -142,7 +142,7 @@ static int __init ircomm_tty_init(void)
 
 static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self)
 {
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -163,12 +163,12 @@ static void __exit ircomm_tty_cleanup(void)
 {
 	int ret;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	ret = tty_unregister_driver(driver);
 	if (ret) {
 		IRDA_ERROR("%s(), failed to unregister driver\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 
@@ -187,14 +187,14 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 	notify_t notify;
 	int ret = -ENODEV;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Check if already open */
 	if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
-		IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
 		return 0;
 	}
 
@@ -224,7 +224,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 	/* Connect IrCOMM link with remote device */
 	ret = ircomm_tty_attach_cable(self);
 	if (ret < 0) {
-		IRDA_ERROR("%s(), error attaching cable!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), error attaching cable!\n", __func__);
 		goto err;
 	}
 
@@ -249,7 +249,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
 	unsigned long	flags;
 	struct tty_struct *tty;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	tty = self->tty;
 
@@ -260,12 +260,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
 	if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
 		/* nonblock mode is set or port is not enabled */
 		self->flags |= ASYNC_NORMAL_ACTIVE;
-		IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
 		return 0;
 	}
 
 	if (tty->termios->c_cflag & CLOCAL) {
-		IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
 		do_clocal = 1;
 	}
 
@@ -368,7 +368,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 	unsigned long	flags;
 	int ret;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	line = tty->index;
 	if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
@@ -381,7 +381,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 		/* No, so make new instance */
 		self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
 		if (self == NULL) {
-			IRDA_ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
+			IRDA_ERROR("%s(), kmalloc failed!\n", __func__);
 			return -ENOMEM;
 		}
 
@@ -420,7 +420,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 	self->tty = tty;
 	spin_unlock_irqrestore(&self->spinlock, flags);
 
-	IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__ , tty->driver->name,
+	IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
 		   self->line, self->open_count);
 
 	/* Not really used by us, but lets do it anyway */
@@ -442,7 +442,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 
 		if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
 			IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
-				     __FUNCTION__);
+				     __func__);
 			return -ERESTARTSYS;
 		}
 
@@ -460,9 +460,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 		self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
 		/* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
 		self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */
-		IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IrCOMM device\n", __func__ );
 	} else {
-		IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IrLPT device\n", __func__ );
 		self->service_type = IRCOMM_3_WIRE_RAW;
 		self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */
 	}
@@ -474,7 +474,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 	ret = ircomm_tty_block_til_ready(self, filp);
 	if (ret) {
 		IRDA_DEBUG(2,
-		      "%s(), returning after block_til_ready with %d\n", __FUNCTION__ ,
+		      "%s(), returning after block_til_ready with %d\n", __func__ ,
 		      ret);
 
 		return ret;
@@ -493,7 +493,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned long flags;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	if (!tty)
 		return;
@@ -506,7 +506,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 	if (tty_hung_up_p(filp)) {
 		spin_unlock_irqrestore(&self->spinlock, flags);
 
-		IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
 		return;
 	}
 
@@ -519,20 +519,20 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 		 * serial port won't be shutdown.
 		 */
 		IRDA_DEBUG(0, "%s(), bad serial port count; "
-			   "tty->count is 1, state->count is %d\n", __FUNCTION__ ,
+			   "tty->count is 1, state->count is %d\n", __func__ ,
 			   self->open_count);
 		self->open_count = 1;
 	}
 
 	if (--self->open_count < 0) {
 		IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
-			   __FUNCTION__, self->line, self->open_count);
+			   __func__, self->line, self->open_count);
 		self->open_count = 0;
 	}
 	if (self->open_count) {
 		spin_unlock_irqrestore(&self->spinlock, flags);
 
-		IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
 		return;
 	}
 
@@ -608,7 +608,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
 	unsigned long flags;
 	struct sk_buff *skb, *ctrl_skb;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (!self || self->magic != IRCOMM_TTY_MAGIC)
 		return;
@@ -678,7 +678,7 @@ static int ircomm_tty_write(struct tty_struct *tty,
 	int len = 0;
 	int size;
 
-	IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __FUNCTION__ , count,
+	IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __func__ , count,
 		   tty->hw_stopped);
 
 	IRDA_ASSERT(self != NULL, return -1;);
@@ -701,7 +701,7 @@ static int ircomm_tty_write(struct tty_struct *tty,
 	 * we don't mess up the original "safe skb" (see tx_data_size).
 	 * Jean II */
 	if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) {
-		IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s() : not initialised\n", __func__);
 #ifdef IRCOMM_NO_TX_BEFORE_INIT
 		/* We didn't consume anything, TTY will retry */
 		return 0;
@@ -830,7 +830,7 @@ static int ircomm_tty_write_room(struct tty_struct *tty)
 			ret = self->max_data_size;
 		spin_unlock_irqrestore(&self->spinlock, flags);
 	}
-	IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__ , ret);
+	IRDA_DEBUG(2, "%s(), ret=%d\n", __func__ , ret);
 
 	return ret;
 }
@@ -847,7 +847,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
 	unsigned long orig_jiffies, poll_time;
 	unsigned long flags;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -882,7 +882,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -913,7 +913,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -928,7 +928,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
 		self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
 
 		ircomm_param_request(self, IRCOMM_DTE, TRUE);
-		IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), FLOW_START\n", __func__ );
 	}
 	ircomm_flow_request(self->ircomm, FLOW_START);
 }
@@ -965,7 +965,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
 		return;
@@ -1008,7 +1008,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned long	flags;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -1037,7 +1037,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
  */
 static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch)
 {
-	IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s(), not impl\n", __func__ );
 }
 
 /*
@@ -1081,7 +1081,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 	struct tty_struct *tty;
 	int status;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -1095,14 +1095,14 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 	}
 	if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
 		IRDA_DEBUG(2,
-			   "%s(), ircomm%d CD now %s...\n", __FUNCTION__ , self->line,
+			   "%s(), ircomm%d CD now %s...\n", __func__ , self->line,
 			   (status & IRCOMM_CD) ? "on" : "off");
 
 		if (status & IRCOMM_CD) {
 			wake_up_interruptible(&self->open_wait);
 		} else {
 			IRDA_DEBUG(2,
-				   "%s(), Doing serial hangup..\n", __FUNCTION__ );
+				   "%s(), Doing serial hangup..\n", __func__ );
 			if (tty)
 				tty_hangup(tty);
 
@@ -1114,7 +1114,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 		if (tty->hw_stopped) {
 			if (status & IRCOMM_CTS) {
 				IRDA_DEBUG(2,
-					   "%s(), CTS tx start...\n", __FUNCTION__ );
+					   "%s(), CTS tx start...\n", __func__ );
 				tty->hw_stopped = 0;
 
 				/* Wake up processes blocked on open */
@@ -1126,7 +1126,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
 		} else {
 			if (!(status & IRCOMM_CTS)) {
 				IRDA_DEBUG(2,
-					   "%s(), CTS tx stop...\n", __FUNCTION__ );
+					   "%s(), CTS tx stop...\n", __func__ );
 				tty->hw_stopped = 1;
 			}
 		}
@@ -1144,14 +1144,14 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 	IRDA_ASSERT(skb != NULL, return -1;);
 
 	if (!self->tty) {
-		IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
 		return 0;
 	}
 
@@ -1162,7 +1162,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
 	 * params, we can just as well declare the hardware for running.
 	 */
 	if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
-		IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
 		ircomm_param_request(self, IRCOMM_POLL, TRUE);
 
 		/* We can just as well declare the hardware for running */
@@ -1194,7 +1194,7 @@ static int ircomm_tty_control_indication(void *instance, void *sap,
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	int clen;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
@@ -1230,7 +1230,7 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 
 	switch (cmd) {
 	case FLOW_START:
-		IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
 		tty->hw_stopped = 0;
 
 		/* ircomm_tty_do_softint will take care of the rest */
@@ -1238,7 +1238,7 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
 		break;
 	default:  /* If we get here, something is very wrong, better stop */
 	case FLOW_STOP:
-		IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
 		tty->hw_stopped = 1;
 		break;
 	}
diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index b5a13882c927..9032a1d1190d 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -129,14 +129,14 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
  */
 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 {
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
 	/* Check if somebody has already connected to us */
 	if (ircomm_is_connected(self->ircomm)) {
-		IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), already connected!\n", __func__ );
 		return 0;
 	}
 
@@ -158,7 +158,7 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
  */
 void ircomm_tty_detach_cable(struct ircomm_tty_cb *self)
 {
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -207,7 +207,7 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self)
 	__u8 oct_seq[6];
 	__u16 hints;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -308,16 +308,16 @@ int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self)
 	 * Set default values, but only if the application for some reason
 	 * haven't set them already
 	 */
-	IRDA_DEBUG(2, "%s(), data-rate = %d\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ ,
 		   self->settings.data_rate);
 	if (!self->settings.data_rate)
 		self->settings.data_rate = 9600;
-	IRDA_DEBUG(2, "%s(), data-format = %d\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ ,
 		   self->settings.data_format);
 	if (!self->settings.data_format)
 		self->settings.data_format = IRCOMM_WSIZE_8;  /* 8N1 */
 
-	IRDA_DEBUG(2, "%s(), flow-control = %d\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ ,
 		   self->settings.flow_control);
 	/*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/
 
@@ -362,7 +362,7 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery,
 	struct ircomm_tty_cb *self;
 	struct ircomm_tty_info info;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Important note :
 	 * We need to drop all passive discoveries.
@@ -398,7 +398,7 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -428,7 +428,7 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -439,13 +439,13 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
 
 	/* Check if request succeeded */
 	if (result != IAS_SUCCESS) {
-		IRDA_DEBUG(4, "%s(), got NULL value!\n", __FUNCTION__ );
+		IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ );
 		return;
 	}
 
 	switch (value->type) {
 	case IAS_OCT_SEQ:
-		IRDA_DEBUG(2, "%s(), got octet sequence\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ );
 
 		irda_param_extract_all(self, value->t.oct_seq, value->len,
 				       &ircomm_param_info);
@@ -455,21 +455,21 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id,
 		break;
 	case IAS_INTEGER:
 		/* Got LSAP selector */
-		IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ ,
 			   value->t.integer);
 
 		if (value->t.integer == -1) {
-			IRDA_DEBUG(0, "%s(), invalid value!\n", __FUNCTION__ );
+			IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ );
 		} else
 			self->dlsap_sel = value->t.integer;
 
 		ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL);
 		break;
 	case IAS_MISSING:
-		IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), got unknown type!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ );
 		break;
 	}
 	irias_delete_value(value);
@@ -489,7 +489,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap,
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -520,7 +520,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
 	int clen;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -549,7 +549,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
  */
 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -566,10 +566,10 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 	 * line.
 	 */
 	if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
-		IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
 		return;
 	} else {
-		IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
 
 		self->tty->hw_stopped = 0;
 
@@ -607,7 +607,7 @@ static void ircomm_tty_watchdog_timer_expired(void *data)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
@@ -628,7 +628,7 @@ int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 
 	return (*state[self->state])(self, event, skb, info);
@@ -646,7 +646,7 @@ static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ ,
 		   ircomm_tty_state[self->state], self->service_type);
 	*/
 	self->state = state;
@@ -665,7 +665,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 	switch (event) {
 	case IRCOMM_TTY_ATTACH_CABLE:
@@ -681,7 +681,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
 
 		if (self->iriap) {
 			IRDA_WARNING("%s(), busy with a previous query\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 
@@ -709,7 +709,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
@@ -729,7 +729,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 
 	switch (event) {
@@ -739,7 +739,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
 
 		if (self->iriap) {
 			IRDA_WARNING("%s(), busy with a previous query\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 
@@ -782,7 +782,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
@@ -802,14 +802,14 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 
 	switch (event) {
 	case IRCOMM_TTY_GOT_PARAMETERS:
 		if (self->iriap) {
 			IRDA_WARNING("%s(), busy with a previous query\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 
@@ -840,7 +840,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
@@ -860,7 +860,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 
 	switch (event) {
@@ -889,7 +889,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
@@ -909,7 +909,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ ,
+	IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ ,
 		   ircomm_tty_state[self->state], ircomm_tty_event[event]);
 
 	switch (event) {
@@ -943,7 +943,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self,
 		ircomm_tty_next_state(self, IRCOMM_TTY_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
@@ -981,13 +981,13 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
 			self->settings.dce = IRCOMM_DELTA_CD;
 			ircomm_tty_check_modem_status(self);
 		} else {
-			IRDA_DEBUG(0, "%s(), hanging up!\n", __FUNCTION__ );
+			IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
 			if (self->tty)
 				tty_hangup(self->tty);
 		}
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ ,
 			   ircomm_tty_event[event]);
 		ret = -EINVAL;
 	}
diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c
index 6030947b6d93..24cb3aa2bbfb 100644
--- a/net/irda/ircomm/ircomm_tty_ioctl.c
+++ b/net/irda/ircomm/ircomm_tty_ioctl.c
@@ -57,7 +57,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
 	unsigned cflag, cval;
 	int baud;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (!self->tty || !self->tty->termios || !self->ircomm)
 		return;
@@ -94,7 +94,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
 		self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
 		/* This got me. Bummer. Jean II */
 		if (self->service_type == IRCOMM_3_WIRE_RAW)
-			IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__);
+			IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
 	} else {
 		self->flags &= ~ASYNC_CTS_FLOW;
 		self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
@@ -150,7 +150,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned int cflag = tty->termios->c_cflag;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if ((cflag == old_termios->c_cflag) &&
 	    (RELEVANT_IFLAG(tty->termios->c_iflag) ==
@@ -199,7 +199,7 @@ int ircomm_tty_tiocmget(struct tty_struct *tty, struct file *file)
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	unsigned int result;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (tty->flags & (1 << TTY_IO_ERROR))
 		return -EIO;
@@ -224,7 +224,7 @@ int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file,
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (tty->flags & (1 << TTY_IO_ERROR))
 		return -EIO;
@@ -266,7 +266,7 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
 	if (!retinfo)
 		return -EFAULT;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	memset(&info, 0, sizeof(info));
 	info.line = self->line;
@@ -302,7 +302,7 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self,
 	struct serial_struct new_serial;
 	struct ircomm_tty_cb old_state, *state;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
@@ -376,7 +376,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
 	int ret = 0;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
 	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
@@ -397,7 +397,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file,
 		break;
 
 	case TIOCGICOUNT:
-		IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __func__ );
 #if 0
 		save_flags(flags); cli();
 		cnow = driver->icount;
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 87185910d0ee..ea319e3ddc18 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -90,7 +90,7 @@ static void leftover_dongle(void *arg)
 
 void irda_device_cleanup(void)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
 
@@ -107,7 +107,7 @@ void irda_device_set_media_busy(struct net_device *dev, int status)
 {
 	struct irlap_cb *self;
 
-	IRDA_DEBUG(4, "%s(%s)\n", __FUNCTION__, status ? "TRUE" : "FALSE");
+	IRDA_DEBUG(4, "%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
 
 	self = (struct irlap_cb *) dev->atalk_ptr;
 
@@ -147,11 +147,11 @@ int irda_device_is_receiving(struct net_device *dev)
 	struct if_irda_req req;
 	int ret;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	if (!dev->do_ioctl) {
 		IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
-			   __FUNCTION__);
+			   __func__);
 		return -1;
 	}
 
@@ -191,7 +191,7 @@ static int irda_task_kick(struct irda_task *task)
 	int count = 0;
 	int timeout;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(task != NULL, return -1;);
 	IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
@@ -201,14 +201,14 @@ static int irda_task_kick(struct irda_task *task)
 		timeout = task->function(task);
 		if (count++ > 100) {
 			IRDA_ERROR("%s: error in task handler!\n",
-				   __FUNCTION__);
+				   __func__);
 			irda_task_delete(task);
 			return TRUE;
 		}
 	} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
 
 	if (timeout < 0) {
-		IRDA_ERROR("%s: Error executing task!\n", __FUNCTION__);
+		IRDA_ERROR("%s: Error executing task!\n", __func__);
 		irda_task_delete(task);
 		return TRUE;
 	}
@@ -241,7 +241,7 @@ static int irda_task_kick(struct irda_task *task)
 		finished = FALSE;
 	} else {
 		IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n",
-			   __FUNCTION__);
+			   __func__);
 		finished = FALSE;
 	}
 
@@ -258,7 +258,7 @@ static void irda_task_timer_expired(void *data)
 {
 	struct irda_task *task;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	task = (struct irda_task *) data;
 
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 390a790886eb..9e15c82960fe 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -108,7 +108,7 @@ int __init iriap_init(void)
 	irias_objects = hashbin_new(HB_LOCK);
 	if (!irias_objects) {
 		IRDA_WARNING("%s: Can't allocate irias_objects hashbin!\n",
-			     __FUNCTION__);
+			     __func__);
 		hashbin_delete(iriap, NULL);
 		return -ENOMEM;
 	}
@@ -139,7 +139,7 @@ int __init iriap_init(void)
 	 */
 	server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
 	if (!server) {
-		IRDA_DEBUG(0, "%s(), unable to open server\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unable to open server\n", __func__);
 		return -1;
 	}
 	iriap_register_lsap(server, LSAP_IAS, IAS_SERVER);
@@ -171,11 +171,11 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv,
 {
 	struct iriap_cb *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	self = kzalloc(sizeof(*self), GFP_ATOMIC);
 	if (!self) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -217,7 +217,7 @@ EXPORT_SYMBOL(iriap_open);
  */
 static void __iriap_close(struct iriap_cb *self)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -241,7 +241,7 @@ void iriap_close(struct iriap_cb *self)
 {
 	struct iriap_cb *entry;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -262,7 +262,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
 {
 	notify_t notify;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	irda_notify_init(&notify);
 	notify.connect_confirm       = iriap_connect_confirm;
@@ -277,7 +277,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode)
 
 	self->lsap = irlmp_open_lsap(slsap_sel, &notify, 0);
 	if (self->lsap == NULL) {
-		IRDA_ERROR("%s: Unable to allocated LSAP!\n", __FUNCTION__);
+		IRDA_ERROR("%s: Unable to allocated LSAP!\n", __func__);
 		return -1;
 	}
 	self->slsap_sel = self->lsap->slsap_sel;
@@ -297,7 +297,7 @@ static void iriap_disconnect_indication(void *instance, void *sap,
 {
 	struct iriap_cb *self;
 
-	IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);
+	IRDA_DEBUG(4, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
 
 	self = (struct iriap_cb *) instance;
 
@@ -313,7 +313,7 @@ static void iriap_disconnect_indication(void *instance, void *sap,
 		dev_kfree_skb(skb);
 
 	if (self->mode == IAS_CLIENT) {
-		IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), disconnect as client\n", __func__);
 
 
 		iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION,
@@ -326,7 +326,7 @@ static void iriap_disconnect_indication(void *instance, void *sap,
 		if (self->confirm)
 			self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 	} else {
-		IRDA_DEBUG(4, "%s(), disconnect as server\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), disconnect as server\n", __func__);
 		iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION,
 				      NULL);
 		iriap_close(self);
@@ -340,7 +340,7 @@ static void iriap_disconnect_request(struct iriap_cb *self)
 {
 	struct sk_buff *tx_skb;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -349,7 +349,7 @@ static void iriap_disconnect_request(struct iriap_cb *self)
 	if (tx_skb == NULL) {
 		IRDA_DEBUG(0,
 			   "%s(), Could not allocate an sk_buff of length %d\n",
-			   __FUNCTION__, LMP_MAX_HEADER);
+			   __func__, LMP_MAX_HEADER);
 		return;
 	}
 
@@ -453,13 +453,13 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 	/* Get length, MSB first */
 	len = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2;
 
-	IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len);
+	IRDA_DEBUG(4, "%s(), len=%d\n", __func__, len);
 
 	/* Get object ID, MSB first */
 	obj_id = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2;
 
 	type = fp[n++];
-	IRDA_DEBUG(4, "%s(), Value type = %d\n", __FUNCTION__, type);
+	IRDA_DEBUG(4, "%s(), Value type = %d\n", __func__, type);
 
 	switch (type) {
 	case IAS_INTEGER:
@@ -468,7 +468,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 		value = irias_new_integer_value(tmp_cpu32);
 
 		/*  Legal values restricted to 0x01-0x6f, page 15 irttp */
-		IRDA_DEBUG(4, "%s(), lsap=%d\n", __FUNCTION__, value->t.integer);
+		IRDA_DEBUG(4, "%s(), lsap=%d\n", __func__, value->t.integer);
 		break;
 	case IAS_STRING:
 		charset = fp[n++];
@@ -488,7 +488,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 /*		case CS_UNICODE: */
 		default:
 			IRDA_DEBUG(0, "%s(), charset %s, not supported\n",
-				   __FUNCTION__, ias_charset_types[charset]);
+				   __func__, ias_charset_types[charset]);
 
 			/* Aborting, close connection! */
 			iriap_disconnect_request(self);
@@ -496,7 +496,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 			/* break; */
 		}
 		value_len = fp[n++];
-		IRDA_DEBUG(4, "%s(), strlen=%d\n", __FUNCTION__, value_len);
+		IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len);
 
 		/* Make sure the string is null-terminated */
 		fp[n+value_len] = 0x00;
@@ -526,7 +526,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self,
 	if (self->confirm)
 		self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
 	else {
-		IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), missing handler!\n", __func__);
 		irias_delete_value(value);
 	}
 }
@@ -548,7 +548,7 @@ static void iriap_getvaluebyclass_response(struct iriap_cb *self,
 	__be16 tmp_be16;
 	__u8 *fp;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -610,12 +610,12 @@ static void iriap_getvaluebyclass_response(struct iriap_cb *self,
 		memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len;
 		break;
 	case IAS_MISSING:
-		IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__);
+		IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __func__);
 		skb_put(tx_skb, 1);
 		fp[n++] = value->type;
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), type not implemented!\n", __func__);
 		break;
 	}
 	iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb);
@@ -642,7 +642,7 @@ static void iriap_getvaluebyclass_indication(struct iriap_cb *self,
 	__u8 *fp;
 	int n;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -697,7 +697,7 @@ void iriap_send_ack(struct iriap_cb *self)
 	struct sk_buff *tx_skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -728,7 +728,7 @@ void iriap_connect_request(struct iriap_cb *self)
 				    self->saddr, self->daddr,
 				    NULL, NULL);
 	if (ret < 0) {
-		IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), connect failed!\n", __func__);
 		self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 	}
 }
@@ -776,7 +776,7 @@ static void iriap_connect_indication(void *instance, void *sap,
 {
 	struct iriap_cb *self, *new;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	self = (struct iriap_cb *) instance;
 
@@ -787,14 +787,14 @@ static void iriap_connect_indication(void *instance, void *sap,
 	/* Start new server */
 	new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL);
 	if (!new) {
-		IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), open failed\n", __func__);
 		goto out;
 	}
 
 	/* Now attach up the new "socket" */
 	new->lsap = irlmp_dup(self->lsap, new);
 	if (!new->lsap) {
-		IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
 		goto out;
 	}
 
@@ -824,7 +824,7 @@ static int iriap_data_indication(void *instance, void *sap,
 	__u8  *frame;
 	__u8  opcode;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	self = (struct iriap_cb *) instance;
 
@@ -836,7 +836,7 @@ static int iriap_data_indication(void *instance, void *sap,
 
 	if (self->mode == IAS_SERVER) {
 		/* Call server */
-		IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), Calling server!\n", __func__);
 		iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb);
 		goto out;
 	}
@@ -844,13 +844,13 @@ static int iriap_data_indication(void *instance, void *sap,
 	if (~opcode & IAP_LST) {
 		IRDA_WARNING("%s:, IrIAS multiframe commands or "
 			     "results is not implemented yet!\n",
-			     __FUNCTION__);
+			     __func__);
 		goto out;
 	}
 
 	/* Check for ack frames since they don't contain any data */
 	if (opcode & IAP_ACK) {
-		IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s() Got ack frame!\n", __func__);
 		goto out;
 	}
 
@@ -868,7 +868,7 @@ static int iriap_data_indication(void *instance, void *sap,
 			iriap_getvaluebyclass_confirm(self, skb);
 			break;
 		case IAS_CLASS_UNKNOWN:
-			IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), No such class!\n", __func__);
 			/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
@@ -881,7 +881,7 @@ static int iriap_data_indication(void *instance, void *sap,
 					      self->priv);
 			break;
 		case IAS_ATTRIB_UNKNOWN:
-			IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), No such attribute!\n", __func__);
 			/* Finished, close connection! */
 			iriap_disconnect_request(self);
 
@@ -896,7 +896,7 @@ static int iriap_data_indication(void *instance, void *sap,
 		}
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__,
+		IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __func__,
 			   opcode);
 		break;
 	}
@@ -918,7 +918,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
 	__u8 *fp;
 	__u8 opcode;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
@@ -929,7 +929,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
 	opcode = fp[0];
 	if (~opcode & 0x80) {
 		IRDA_WARNING("%s: IrIAS multiframe commands or results "
-			     "is not implemented yet!\n", __FUNCTION__);
+			     "is not implemented yet!\n", __func__);
 		return;
 	}
 	opcode &= 0x7f; /* Mask away LST bit */
@@ -937,7 +937,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb)
 	switch (opcode) {
 	case GET_INFO_BASE:
 		IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n",
-			     __FUNCTION__);
+			     __func__);
 		break;
 	case GET_VALUE_BY_CLASS:
 		iriap_getvaluebyclass_indication(self, skb);
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
index 8fb9d7277ca8..a301cbd93785 100644
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -185,7 +185,7 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
 	case IAP_LM_DISCONNECT_INDICATION:
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
 		break;
 	}
 }
@@ -217,7 +217,7 @@ static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_next_client_state(self, S_DISCONNECT);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
 		break;
 	}
 }
@@ -269,7 +269,7 @@ static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_next_call_state(self, S_OUTSTANDING);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
 		break;
 	}
 }
@@ -283,7 +283,7 @@ static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event,
 			    struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 /*
@@ -305,7 +305,7 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_next_call_state(self, S_WAIT_FOR_CALL);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event);
 		break;
 	}
 }
@@ -318,7 +318,7 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
 			     struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 /*
@@ -330,7 +330,7 @@ static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
 				  struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 
@@ -343,7 +343,7 @@ static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
 				struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 /**************************************************************************
@@ -367,7 +367,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
 	case IAP_LM_CONNECT_INDICATION:
 		tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
 		if (tx_skb == NULL) {
-			IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
+			IRDA_WARNING("%s: unable to malloc!\n", __func__);
 			return;
 		}
 
@@ -386,7 +386,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_next_r_connect_state(self, R_RECEIVING);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(0, "%s(), unknown event %d\n", __func__, event);
 		break;
 	}
 }
@@ -397,7 +397,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
 			 struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	switch (event) {
 	case IAP_LM_DISCONNECT_INDICATION:
@@ -406,7 +406,7 @@ static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_next_r_connect_state(self, R_WAITING);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
 		break;
 	}
 }
@@ -421,13 +421,13 @@ static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event,
 			    struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
 				struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), Not implemented\n", __func__);
 }
 
 /*
@@ -439,7 +439,7 @@ static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
 			      struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	switch (event) {
 	case IAP_RECV_F_LST:
@@ -448,7 +448,7 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
 		iriap_call_indication(self, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
 		break;
 	}
 }
@@ -462,7 +462,7 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
 			    struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(skb != NULL, return;);
 	IRDA_ASSERT(self != NULL, return;);
@@ -483,7 +483,7 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
 		irlmp_data_request(self->lsap, skb);
 		break;
 	default:
-		IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unknown event!\n", __func__);
 		break;
 	}
 }
@@ -491,7 +491,7 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event,
 static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event,
 			      struct sk_buff *skb)
 {
-	IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event);
+	IRDA_DEBUG(0, "%s(), event=%d\n", __func__, event);
 
 	switch (event) {
 	case IAP_RECV_F_LST:
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index cbcf04380f3a..99ebb96f1386 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -47,12 +47,12 @@ struct ias_object *irias_new_object( char *name, int id)
 {
 	struct ias_object *obj;
 
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC);
 	if (obj == NULL) {
 		IRDA_WARNING("%s(), Unable to allocate object!\n",
-			     __FUNCTION__);
+			     __func__);
 		return NULL;
 	}
 
@@ -60,7 +60,7 @@ struct ias_object *irias_new_object( char *name, int id)
 	obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
 	if (!obj->name) {
 		IRDA_WARNING("%s(), Unable to allocate name!\n",
-			     __FUNCTION__);
+			     __func__);
 		kfree(obj);
 		return NULL;
 	}
@@ -73,7 +73,7 @@ struct ias_object *irias_new_object( char *name, int id)
 
 	if (obj->attribs == NULL) {
 		IRDA_WARNING("%s(), Unable to allocate attribs!\n",
-			     __FUNCTION__);
+			     __func__);
 		kfree(obj->name);
 		kfree(obj);
 		return NULL;
@@ -134,7 +134,7 @@ int irias_delete_object(struct ias_object *obj)
 	node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj);
 	if (!node)
 		IRDA_DEBUG( 0, "%s(), object already removed!\n",
-			    __FUNCTION__);
+			    __func__);
 
 	/* Destroy */
 	__irias_delete_object(obj);
@@ -268,7 +268,7 @@ int irias_object_change_attribute(char *obj_name, char *attrib_name,
 	/* Find object */
 	obj = hashbin_lock_find(irias_objects, 0, obj_name);
 	if (obj == NULL) {
-		IRDA_WARNING("%s: Unable to find object: %s\n", __FUNCTION__,
+		IRDA_WARNING("%s: Unable to find object: %s\n", __func__,
 			     obj_name);
 		return -1;
 	}
@@ -280,14 +280,14 @@ int irias_object_change_attribute(char *obj_name, char *attrib_name,
 	attrib = hashbin_find(obj->attribs, 0, attrib_name);
 	if (attrib == NULL) {
 		IRDA_WARNING("%s: Unable to find attribute: %s\n",
-			     __FUNCTION__, attrib_name);
+			     __func__, attrib_name);
 		spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 		return -1;
 	}
 
 	if ( attrib->value->type != new_value->type) {
 		IRDA_DEBUG( 0, "%s(), changing value type not allowed!\n",
-			    __FUNCTION__);
+			    __func__);
 		spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 		return -1;
 	}
@@ -322,7 +322,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
 	attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
 	if (attrib == NULL) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		return;
 	}
 
@@ -333,7 +333,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
 	attrib->value = irias_new_integer_value(value);
 	if (!attrib->name || !attrib->value) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		if (attrib->value)
 			irias_delete_value(attrib->value);
 		kfree(attrib->name);
@@ -366,7 +366,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
 	attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC);
 	if (attrib == NULL) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		return;
 	}
 
@@ -376,7 +376,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
 	attrib->value = irias_new_octseq_value( octets, len);
 	if (!attrib->name || !attrib->value) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		if (attrib->value)
 			irias_delete_value(attrib->value);
 		kfree(attrib->name);
@@ -408,7 +408,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
 	attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC);
 	if (attrib == NULL) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		return;
 	}
 
@@ -418,7 +418,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
 	attrib->value = irias_new_string_value(value);
 	if (!attrib->name || !attrib->value) {
 		IRDA_WARNING("%s: Unable to allocate attribute!\n",
-			     __FUNCTION__);
+			     __func__);
 		if (attrib->value)
 			irias_delete_value(attrib->value);
 		kfree(attrib->name);
@@ -442,7 +442,7 @@ struct ias_value *irias_new_integer_value(int integer)
 
 	value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -467,7 +467,7 @@ struct ias_value *irias_new_string_value(char *string)
 
 	value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -475,7 +475,7 @@ struct ias_value *irias_new_string_value(char *string)
 	value->charset = CS_ASCII;
 	value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
 	if (!value->t.string) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		kfree(value);
 		return NULL;
 	}
@@ -498,7 +498,7 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
 
 	value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -510,7 +510,7 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
 
 	value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC);
 	if (value->t.oct_seq == NULL){
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		kfree(value);
 		return NULL;
 	}
@@ -523,7 +523,7 @@ struct ias_value *irias_new_missing_value(void)
 
 	value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
-		IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_WARNING("%s: Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -540,7 +540,7 @@ struct ias_value *irias_new_missing_value(void)
  */
 void irias_delete_value(struct ias_value *value)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(value != NULL, return;);
 
@@ -558,7 +558,7 @@ void irias_delete_value(struct ias_value *value)
 		 kfree(value->t.oct_seq);
 		 break;
 	default:
-		IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), Unknown value type!\n", __func__);
 		break;
 	}
 	kfree(value);
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index fff52d57a200..6be1ec26b30c 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -72,7 +72,7 @@ static void irlan_client_kick_timer_expired(void *data)
 {
 	struct irlan_cb *self = (struct irlan_cb *) data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -91,7 +91,7 @@ static void irlan_client_kick_timer_expired(void *data)
 
 static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	irda_start_timer(&self->client.kick_timer, timeout, (void *) self,
 			 irlan_client_kick_timer_expired);
@@ -105,7 +105,7 @@ static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout)
  */
 void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(1, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -117,7 +117,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 	if ((self->client.state != IRLAN_IDLE) ||
 	    (self->provider.access_type == ACCESS_DIRECT))
 	{
-			IRDA_DEBUG(0, "%s(), already awake!\n", __FUNCTION__ );
+			IRDA_DEBUG(0, "%s(), already awake!\n", __func__ );
 			return;
 	}
 
@@ -126,7 +126,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 	self->daddr = daddr;
 
 	if (self->disconnect_reason == LM_USER_REQUEST) {
-			IRDA_DEBUG(0, "%s(), still stopped by user\n", __FUNCTION__ );
+			IRDA_DEBUG(0, "%s(), still stopped by user\n", __func__ );
 			return;
 	}
 
@@ -153,7 +153,7 @@ void irlan_client_discovery_indication(discinfo_t *discovery,
 	struct irlan_cb *self;
 	__u32 saddr, daddr;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(1, "%s()\n", __func__ );
 
 	IRDA_ASSERT(discovery != NULL, return;);
 
@@ -175,7 +175,7 @@ void irlan_client_discovery_indication(discinfo_t *discovery,
 	if (self) {
 		IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;);
 
-		IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ ,
+		IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __func__ ,
 		      daddr);
 
 		irlan_client_wakeup(self, saddr, daddr);
@@ -195,7 +195,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 {
 	struct irlan_cb *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	self = (struct irlan_cb *) instance;
 
@@ -206,7 +206,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap,
 	irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
 
 	/* Ready for a new command */
-	IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __func__ );
 	self->client.tx_busy = FALSE;
 
 	/* Check if we have some queued commands waiting to be sent */
@@ -223,7 +223,7 @@ static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap,
 	struct tsap_cb *tsap;
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
+	IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
 
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -255,7 +255,7 @@ static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
 	struct tsap_cb *tsap;
 	notify_t notify;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -275,7 +275,7 @@ static void irlan_client_open_ctrl_tsap(struct irlan_cb *self)
 
 	tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
 	if (!tsap) {
-		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
 		return;
 	}
 	self->client.tsap_ctrl = tsap;
@@ -295,7 +295,7 @@ static void irlan_client_ctrl_connect_confirm(void *instance, void *sap,
 {
 	struct irlan_cb *self;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	self = (struct irlan_cb *) instance;
 
@@ -374,13 +374,13 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 
 	IRDA_ASSERT(skb != NULL, return;);
 
-	IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len);
+	IRDA_DEBUG(4, "%s() skb->len=%d\n", __func__ , (int) skb->len);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	if (!skb) {
-		IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__);
+		IRDA_ERROR("%s(), Got NULL skb!\n", __func__);
 		return;
 	}
 	frame = skb->data;
@@ -405,7 +405,7 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 	/* How many parameters? */
 	count = frame[1];
 
-	IRDA_DEBUG(4, "%s(), got %d parameters\n", __FUNCTION__ , count);
+	IRDA_DEBUG(4, "%s(), got %d parameters\n", __func__ , count);
 
 	ptr = frame+2;
 
@@ -413,7 +413,7 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 	for (i=0; i<count;i++) {
 		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret < 0) {
-			IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
 			break;
 		}
 		ptr += ret;
@@ -438,7 +438,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
 	int i;
 	DECLARE_MAC_BUF(mac);
 
-	IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param);
+	IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -476,7 +476,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
 		else if (strcmp(value, "HOSTED") == 0)
 			self->client.access_type = ACCESS_HOSTED;
 		else {
-			IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
 		}
 	}
 	/* IRLAN version */
@@ -498,14 +498,14 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
 		memcpy(&tmp_cpu, value, 2); /* Align value */
 		le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 		self->client.recv_arb_val = tmp_cpu;
-		IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __FUNCTION__ ,
+		IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __func__ ,
 			   self->client.recv_arb_val);
 	}
 	if (strcmp(param, "MAX_FRAME") == 0) {
 		memcpy(&tmp_cpu, value, 2); /* Align value */
 		le16_to_cpus(&tmp_cpu);     /* Convert to host order */
 		self->client.max_frame = tmp_cpu;
-		IRDA_DEBUG(4, "%s(), max frame=%d\n", __FUNCTION__ ,
+		IRDA_DEBUG(4, "%s(), max frame=%d\n", __func__ ,
 			   self->client.max_frame);
 	}
 
@@ -539,7 +539,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id,
 {
 	struct irlan_cb *self;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(priv != NULL, return;);
 
@@ -552,7 +552,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id,
 
 	/* Check if request succeeded */
 	if (result != IAS_SUCCESS) {
-		IRDA_DEBUG(2, "%s(), got NULL value!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), got NULL value!\n", __func__ );
 		irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL,
 				      NULL);
 		return;
@@ -570,7 +570,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id,
 		irias_delete_value(value);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), unknown type!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), unknown type!\n", __func__ );
 		break;
 	}
 	irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL);
diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c
index 6afcee59e906..8d5a8ebc444f 100644
--- a/net/irda/irlan/irlan_client_event.c
+++ b/net/irda/irlan/irlan_client_event.c
@@ -92,7 +92,7 @@ void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -101,7 +101,7 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 	case IRLAN_DISCOVERY_INDICATION:
 		if (self->client.iriap) {
 			IRDA_WARNING("%s(), busy with a previous query\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 
@@ -114,10 +114,10 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 					      "IrLAN", "IrDA:TinyTP:LsapSel");
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -136,7 +136,7 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
 				    struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -154,7 +154,7 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_CONN);
 		break;
 	case IRLAN_IAS_PROVIDER_NOT_AVAIL:
-		IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__ );
 		irlan_next_client_state(self, IRLAN_IDLE);
 
 		/* Give the client a kick! */
@@ -167,10 +167,10 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -189,7 +189,7 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -204,10 +204,10 @@ static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -224,7 +224,7 @@ static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -244,10 +244,10 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -266,7 +266,7 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
 				    struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -281,10 +281,10 @@ static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -305,7 +305,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 {
 	struct qos_info qos;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -344,7 +344,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 			irlan_next_client_state(self, IRLAN_DATA);
 			break;
 		default:
-			IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ );
 			break;
 		}
 		break;
@@ -353,10 +353,10 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 
@@ -376,7 +376,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -390,10 +390,10 @@ static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -407,7 +407,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
 {
 	struct qos_info qos;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -429,7 +429,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
 		} else if (self->client.recv_arb_val >
 			   self->provider.send_arb_val)
 		{
-			IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__ );
 		}
 		break;
 	case IRLAN_DATA_CONNECT_INDICATION:
@@ -440,10 +440,10 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	case IRLAN_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -462,7 +462,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -476,7 +476,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_client_state(self, IRLAN_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -494,7 +494,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
 				    struct sk_buff *skb)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (skb)
 		dev_kfree_skb(skb);
@@ -511,7 +511,7 @@ static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (skb)
 		dev_kfree_skb(skb);
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 1eb4bbcb1c9e..75bb6a9dcaaa 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -124,7 +124,7 @@ static int __init irlan_init(void)
 	struct irlan_cb *new;
 	__u16 hints;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 #ifdef CONFIG_PROC_FS
 	{ struct proc_dir_entry *proc;
@@ -136,7 +136,7 @@ static int __init irlan_init(void)
 	}
 #endif /* CONFIG_PROC_FS */
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 	hints = irlmp_service_to_hint(S_LAN);
 
 	/* Register with IrLMP as a client */
@@ -179,7 +179,7 @@ static void __exit irlan_cleanup(void)
 {
 	struct irlan_cb *self, *next;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	irlmp_unregister_client(ckey);
 	irlmp_unregister_service(skey);
@@ -207,7 +207,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
 	struct net_device *dev;
 	struct irlan_cb *self;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Create network device with irlan */
 	dev = alloc_irlandev(eth ? "eth%d" : "irlan%d");
@@ -252,7 +252,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
 
 	if (register_netdev(dev)) {
 		IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
-			   __FUNCTION__ );
+			   __func__ );
 		self = NULL;
 		free_netdev(dev);
 	} else {
@@ -272,7 +272,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	ASSERT_RTNL();
 	IRDA_ASSERT(self != NULL, return;);
@@ -320,7 +320,7 @@ static void irlan_connect_indication(void *instance, void *sap,
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -332,7 +332,7 @@ static void irlan_connect_indication(void *instance, void *sap,
 	self->max_sdu_size = max_sdu_size;
 	self->max_header_size = max_header_size;
 
-	IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
 
 	del_timer(&self->watchdog_timer);
 
@@ -376,7 +376,7 @@ static void irlan_connect_confirm(void *instance, void *sap,
 
 	/* TODO: we could set the MTU depending on the max_sdu_size */
 
-	IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s: We are now connected!\n", __func__);
 	del_timer(&self->watchdog_timer);
 
 	/*
@@ -412,7 +412,7 @@ static void irlan_disconnect_indication(void *instance,
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	IRDA_DEBUG(0, "%s(), reason=%d\n", __FUNCTION__ , reason);
+	IRDA_DEBUG(0, "%s(), reason=%d\n", __func__ , reason);
 
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -431,22 +431,22 @@ static void irlan_disconnect_indication(void *instance,
 
 	switch (reason) {
 	case LM_USER_REQUEST: /* User request */
-		IRDA_DEBUG(2, "%s(), User requested\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), User requested\n", __func__ );
 		break;
 	case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
-		IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __func__ );
 		break;
 	case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */
-		IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __func__ );
 		break;
 	case LM_LAP_RESET:  /* IrLAP reset */
-		IRDA_DEBUG(2, "%s(), IrLAP reset\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IrLAP reset\n", __func__ );
 		break;
 	case LM_INIT_DISCONNECT:
-		IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __func__ );
 		break;
 	default:
-		IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__);
+		IRDA_ERROR("%s(), Unknown disconnect reason\n", __func__);
 		break;
 	}
 
@@ -468,7 +468,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
 	struct tsap_cb *tsap;
 	notify_t notify;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -490,7 +490,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
 
 	tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, &notify);
 	if (!tsap) {
-		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
 		return;
 	}
 	self->tsap_data = tsap;
@@ -504,7 +504,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
 
 void irlan_close_tsaps(struct irlan_cb *self)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -594,7 +594,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	if (irda_lock(&self->client.tx_busy) == FALSE)
 		return -EBUSY;
@@ -613,7 +613,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
 		dev_kfree_skb(skb);
 		return -1;
 	}
-	IRDA_DEBUG(2, "%s(), sending ...\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s(), sending ...\n", __func__ );
 
 	return irttp_data_request(self->client.tsap_ctrl, skb);
 }
@@ -626,7 +626,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
  */
 static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Queue command */
 	skb_queue_tail(&self->client.txq, skb);
@@ -646,7 +646,7 @@ void irlan_get_provider_info(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -679,7 +679,7 @@ void irlan_open_data_channel(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -714,7 +714,7 @@ void irlan_close_data_channel(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -755,7 +755,7 @@ static void irlan_open_unicast_addr(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -797,7 +797,7 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -841,7 +841,7 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -886,7 +886,7 @@ static void irlan_get_unicast_addr(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -926,7 +926,7 @@ void irlan_get_media_char(struct irlan_cb *self)
 	struct sk_buff *skb;
 	__u8 *frame;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -1014,7 +1014,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
 	int n=0;
 
 	if (skb == NULL) {
-		IRDA_DEBUG(2, "%s(), Got NULL skb\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Got NULL skb\n", __func__ );
 		return 0;
 	}
 
@@ -1031,7 +1031,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
 		IRDA_ASSERT(value_len > 0, return 0;);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ );
 		return 0;
 		break;
 	}
@@ -1041,7 +1041,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
 
 	/* Make space for data */
 	if (skb_tailroom(skb) < (param_len+value_len+3)) {
-		IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __func__ );
 		return 0;
 	}
 	skb_put(skb, param_len+value_len+3);
@@ -1088,13 +1088,13 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
 	__u16 val_len;
 	int n=0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	/* get length of parameter name (1 byte) */
 	name_len = buf[n++];
 
 	if (name_len > 254) {
-		IRDA_DEBUG(2, "%s(), name_len > 254\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), name_len > 254\n", __func__ );
 		return -RSP_INVALID_COMMAND_FORMAT;
 	}
 
@@ -1111,7 +1111,7 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
 	le16_to_cpus(&val_len); n+=2;
 
 	if (val_len > 1016) {
-		IRDA_DEBUG(2, "%s(), parameter length to long\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ );
 		return -RSP_INVALID_COMMAND_FORMAT;
 	}
 	*len = val_len;
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 1ab91f787cc1..7a6b14ab1e7f 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -103,7 +103,7 @@ static int irlan_eth_open(struct net_device *dev)
 {
 	struct irlan_cb *self = netdev_priv(dev);
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Ready to play! */
 	netif_stop_queue(dev); /* Wait until data link is ready */
@@ -130,7 +130,7 @@ static int irlan_eth_close(struct net_device *dev)
 {
 	struct irlan_cb *self = netdev_priv(dev);
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Stop device */
 	netif_stop_queue(dev);
@@ -221,7 +221,7 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
 	}
 	if (skb->len < ETH_HLEN) {
 		IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n",
-			   __FUNCTION__, skb->len);
+			   __func__, skb->len);
 		++self->stats.rx_dropped;
 		dev_kfree_skb(skb);
 		return 0;
@@ -270,7 +270,7 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 
 	IRDA_ASSERT(dev != NULL, return;);
 
-	IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__,
+	IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__,
 		   flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START",
 		   netif_running(dev));
 
@@ -332,11 +332,11 @@ static void irlan_eth_set_multicast_list(struct net_device *dev)
 {
 	struct irlan_cb *self = netdev_priv(dev);
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(2, "%s()\n", __func__ );
 
 	/* Check if data channel has been connected yet */
 	if (self->client.state != IRLAN_DATA) {
-		IRDA_DEBUG(1, "%s(), delaying!\n", __FUNCTION__ );
+		IRDA_DEBUG(1, "%s(), delaying!\n", __func__ );
 		return;
 	}
 
@@ -346,20 +346,20 @@ static void irlan_eth_set_multicast_list(struct net_device *dev)
 	}
 	else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
 		/* Disable promiscuous mode, use normal mode. */
-		IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
+		IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
 		/* hardware_set_filter(NULL); */
 
 		irlan_set_multicast_filter(self, TRUE);
 	}
 	else if (dev->mc_count) {
-		IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ );
+		IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ );
 		/* Walk the address list, and load the filter */
 		/* hardware_set_filter(dev->mc_list); */
 
 		irlan_set_multicast_filter(self, TRUE);
 	}
 	else {
-		IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __FUNCTION__ );
+		IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__ );
 		irlan_set_multicast_filter(self, FALSE);
 	}
 
diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c
index a9750a801388..cbcb4eb54037 100644
--- a/net/irda/irlan/irlan_event.c
+++ b/net/irda/irlan/irlan_event.c
@@ -40,7 +40,7 @@ char *irlan_state[] = {
 
 void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
 {
-	IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
+	IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -50,7 +50,7 @@ void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state)
 
 void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state)
 {
-	IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]);
+	IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
index 4384be9a6888..9ff7823abec7 100644
--- a/net/irda/irlan/irlan_filter.c
+++ b/net/irda/irlan/irlan_filter.c
@@ -145,7 +145,7 @@ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
 {
 	__u8 *bytes;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	bytes = value;
 
@@ -158,7 +158,7 @@ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
 	 *  This is experimental!! DB.
 	 */
 	 if (strcmp(param, "MODE") == 0) {
-		IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+		IRDA_DEBUG(0, "%s()\n", __func__ );
 		self->use_udata = TRUE;
 		return;
 	}
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
index 13db942812e4..3f81f81b2dfa 100644
--- a/net/irda/irlan/irlan_provider.c
+++ b/net/irda/irlan/irlan_provider.c
@@ -70,7 +70,7 @@ static int irlan_provider_data_indication(void *instance, void *sap,
 	struct irlan_cb *self;
 	__u8 code;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	self = (struct irlan_cb *) instance;
 
@@ -99,15 +99,15 @@ static int irlan_provider_data_indication(void *instance, void *sap,
 		irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb);
 		break;
 	case CMD_RECONNECT_DATA_CHAN:
-		IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __FUNCTION__ );
-		IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __func__ );
+		IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
 		break;
 	case CMD_CLOSE_DATA_CHAN:
 		IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n");
-		IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ );
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
 		break;
 	}
 	return 0;
@@ -129,7 +129,7 @@ static void irlan_provider_connect_indication(void *instance, void *sap,
 	struct tsap_cb *tsap;
 	__u32 saddr, daddr;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(0, "%s()\n", __func__ );
 
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -182,7 +182,7 @@ static void irlan_provider_disconnect_indication(void *instance, void *sap,
 	struct irlan_cb *self;
 	struct tsap_cb *tsap;
 
-	IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason);
+	IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason);
 
 	self = (struct irlan_cb *) instance;
 	tsap = (struct tsap_cb *) sap;
@@ -236,7 +236,7 @@ int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
 
 	IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;);
 
-	IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len);
+	IRDA_DEBUG(4, "%s(), skb->len=%d\n", __func__ , (int)skb->len);
 
 	IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;);
@@ -266,7 +266,7 @@ int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
 	for (i=0; i<count;i++) {
 		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret < 0) {
-			IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ );
 			break;
 		}
 		ptr+=ret;
@@ -291,7 +291,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -323,7 +323,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
 			irlan_insert_string_param(skb, "MEDIA", "802.5");
 			break;
 		default:
-			IRDA_DEBUG(2, "%s(), unknown media type!\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), unknown media type!\n", __func__ );
 			break;
 		}
 		irlan_insert_short_param(skb, "IRLAN_VER", 0x0101);
@@ -347,7 +347,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
 			irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED");
 			break;
 		default:
-			IRDA_DEBUG(2, "%s(), Unknown access type\n", __FUNCTION__ );
+			IRDA_DEBUG(2, "%s(), Unknown access type\n", __func__ );
 			break;
 		}
 		irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee);
@@ -367,7 +367,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
 		irlan_filter_request(self, skb);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ );
 		break;
 	}
 
@@ -385,7 +385,7 @@ int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 	struct tsap_cb *tsap;
 	notify_t notify;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -406,7 +406,7 @@ int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 
 	tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
 	if (!tsap) {
-		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ );
+		IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ );
 		return -1;
 	}
 	self->provider.tsap_ctrl = tsap;
diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c
index 10ece5a47522..01a9d7c993ee 100644
--- a/net/irda/irlan/irlan_provider_event.c
+++ b/net/irda/irlan/irlan_provider_event.c
@@ -72,7 +72,7 @@ void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 				     struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -82,7 +82,7 @@ static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event,
 	     irlan_next_provider_state( self, IRLAN_INFO);
 	     break;
 	default:
-		IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -101,7 +101,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 {
 	int ret;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -147,7 +147,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -166,7 +166,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 				     struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 
@@ -186,7 +186,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
@@ -205,7 +205,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 				     struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
+	IRDA_DEBUG(4, "%s()\n", __func__ );
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;);
@@ -221,7 +221,7 @@ static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 		irlan_next_provider_state(self, IRLAN_IDLE);
 		break;
 	default:
-		IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event);
+		IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event);
 		break;
 	}
 	if (skb)
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index f3236acc8d22..e4965b764b9b 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -88,7 +88,7 @@ int __init irlap_init(void)
 	irlap = hashbin_new(HB_LOCK);
 	if (irlap == NULL) {
 		IRDA_ERROR("%s: can't allocate irlap hashbin!\n",
-			   __FUNCTION__);
+			   __func__);
 		return -ENOMEM;
 	}
 
@@ -113,7 +113,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
 {
 	struct irlap_cb *self;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/* Initialize the irlap structure. */
 	self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL);
@@ -215,7 +215,7 @@ void irlap_close(struct irlap_cb *self)
 {
 	struct irlap_cb *lap;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -231,7 +231,7 @@ void irlap_close(struct irlap_cb *self)
 	/* Be sure that we manage to remove ourself from the hash */
 	lap = hashbin_remove(irlap, self->saddr, NULL);
 	if (!lap) {
-		IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __func__);
 		return;
 	}
 	__irlap_close(lap);
@@ -246,7 +246,7 @@ EXPORT_SYMBOL(irlap_close);
  */
 void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -265,7 +265,7 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb)
  */
 void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL);
 }
@@ -280,7 +280,7 @@ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata)
 void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
 			   struct qos_info *qos_user, int sniff)
 {
-	IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr);
+	IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __func__, daddr);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -307,7 +307,7 @@ void irlap_connect_request(struct irlap_cb *self, __u32 daddr,
  */
 void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -344,7 +344,7 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
 		    return;);
@@ -391,7 +391,7 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
 	       return;);
@@ -417,7 +417,7 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb)
 #ifdef CONFIG_IRDA_ULTRA
 void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -437,7 +437,7 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb)
  */
 void irlap_disconnect_request(struct irlap_cb *self)
 {
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -458,7 +458,7 @@ void irlap_disconnect_request(struct irlap_cb *self)
 		irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), disconnect pending!\n", __FUNCTION__);
+		IRDA_DEBUG(2, "%s(), disconnect pending!\n", __func__);
 		self->disconnect_pending = TRUE;
 		break;
 	}
@@ -472,7 +472,7 @@ void irlap_disconnect_request(struct irlap_cb *self)
  */
 void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
 {
-	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]);
+	IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, lap_reasons[reason]);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -482,7 +482,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
 
 	switch (reason) {
 	case LAP_RESET_INDICATION:
-		IRDA_DEBUG(1, "%s(), Sending reset request!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Sending reset request!\n", __func__);
 		irlap_do_event(self, RESET_REQUEST, NULL, NULL);
 		break;
 	case LAP_NO_RESPONSE:	   /* FALLTROUGH */
@@ -493,7 +493,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
 						 reason, NULL);
 		break;
 	default:
-		IRDA_ERROR("%s: Unknown reason %d\n", __FUNCTION__, reason);
+		IRDA_ERROR("%s: Unknown reason %d\n", __func__, reason);
 	}
 }
 
@@ -511,7 +511,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 	IRDA_ASSERT(discovery != NULL, return;);
 
-	IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots);
+	IRDA_DEBUG(4, "%s(), nslots = %d\n", __func__, discovery->nslots);
 
 	IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
 		    (discovery->nslots == 8) || (discovery->nslots == 16),
@@ -520,7 +520,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
 	/* Discovery is only possible in NDM mode */
 	if (self->state != LAP_NDM) {
 		IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n",
-			   __FUNCTION__);
+			   __func__);
 		irlap_discovery_confirm(self, NULL);
 		/* Note : in theory, if we are not in NDM, we could postpone
 		 * the discovery like we do for connection request.
@@ -543,7 +543,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
 
 	if (self->discovery_log == NULL) {
 		IRDA_WARNING("%s(), Unable to allocate discovery log!\n",
-			     __FUNCTION__);
+			     __func__);
 		return;
 	}
 
@@ -598,7 +598,7 @@ void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log)
  */
 void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -644,7 +644,7 @@ void irlap_status_indication(struct irlap_cb *self, int quality_of_link)
  */
 void irlap_reset_indication(struct irlap_cb *self)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -660,7 +660,7 @@ void irlap_reset_indication(struct irlap_cb *self)
  */
 void irlap_reset_confirm(void)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 }
 
 /*
@@ -760,7 +760,7 @@ int irlap_validate_nr_received(struct irlap_cb *self, int nr)
 {
 	/*  nr as expected?  */
 	if (nr == self->vs) {
-		IRDA_DEBUG(4, "%s(), expected!\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), expected!\n", __func__);
 		return NR_EXPECTED;
 	}
 
@@ -788,7 +788,7 @@ int irlap_validate_nr_received(struct irlap_cb *self, int nr)
  */
 void irlap_initiate_connection_state(struct irlap_cb *self)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -871,7 +871,7 @@ static void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now)
 {
 	struct sk_buff *skb;
 
-	IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed);
+	IRDA_DEBUG(0, "%s(), setting speed to %d\n", __func__, speed);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -914,7 +914,7 @@ static void irlap_init_qos_capabilities(struct irlap_cb *self,
 	 *  user may not have set all of them.
 	 */
 	if (qos_user) {
-		IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __func__);
 
 		if (qos_user->baud_rate.bits)
 			self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
@@ -944,7 +944,7 @@ static void irlap_init_qos_capabilities(struct irlap_cb *self,
  */
 void irlap_apply_default_connection_parameters(struct irlap_cb *self)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -1007,7 +1007,7 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self)
  */
 void irlap_apply_connection_parameters(struct irlap_cb *self, int now)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 6af86eba7463..16c4ef0f5c1a 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -217,7 +217,7 @@ static void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 	} else
 		self->fast_RR = FALSE;
 
-	IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __FUNCTION__, timeout, jiffies);
+	IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies);
 #endif /* CONFIG_IRDA_FAST_RR */
 
 	if (timeout == 0)
@@ -241,7 +241,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
 	if (!self || self->magic != LAP_MAGIC)
 		return;
 
-	IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __FUNCTION__,
+	IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __func__,
 		   irlap_event[event], irlap_state[self->state]);
 
 	ret = (*state[self->state])(self, event, skb, info);
@@ -259,7 +259,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
 		 * try to disconnect link if we send any data frames, since
 		 * that will change the state away form XMIT
 		 */
-		IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
+		IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
 			   skb_queue_len(&self->txq));
 
 		if (!skb_queue_empty(&self->txq)) {
@@ -340,7 +340,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 			 * media busy in irlap_connect_request() and
 			 * postpone the event... - Jean II */
 			IRDA_DEBUG(0, "%s(), CONNECT_REQUEST: media busy!\n",
-				   __FUNCTION__);
+				   __func__);
 
 			/* Always switch state before calling upper layers */
 			irlap_next_state(self, LAP_NDM);
@@ -367,7 +367,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 			irlap_connect_indication(self, skb);
 		} else {
 			IRDA_DEBUG(0, "%s(), SNRM frame does not "
-				   "contain an I field!\n", __FUNCTION__);
+				   "contain an I field!\n", __func__);
 		}
 		break;
 	case DISCOVERY_REQUEST:
@@ -375,7 +375,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 
 		if (self->media_busy) {
 			IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n",
-				   __FUNCTION__);
+				   __func__);
 			/* irlap->log.condition = MEDIA_BUSY; */
 
 			/* This will make IrLMP try again */
@@ -441,7 +441,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 		 * those cases...
 		 * Jean II
 		 */
-			IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __func__);
 
 			/* Last discovery request -> in the log */
 			irlap_discovery_indication(self, info->discovery);
@@ -520,7 +520,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 		/* Only accept broadcast frames in NDM mode */
 		if (info->caddr != CBROADCAST) {
 			IRDA_DEBUG(0, "%s(), not a broadcast frame!\n",
-				   __FUNCTION__);
+				   __func__);
 		} else
 			irlap_unitdata_indication(self, skb);
 		break;
@@ -536,10 +536,10 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_send_test_frame(self, CBROADCAST, info->daddr, skb);
 		break;
 	case RECV_TEST_RSP:
-		IRDA_DEBUG(0, "%s() not implemented!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s() not implemented!\n", __func__);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
 			   irlap_event[event]);
 
 		ret = -1;
@@ -567,13 +567,13 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
 		IRDA_ASSERT(info != NULL, return -1;);
 		IRDA_ASSERT(info->discovery != NULL, return -1;);
 
-		IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
+		IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
 			   info->discovery->data.daddr);
 
 		if (!self->discovery_log) {
 			IRDA_WARNING("%s: discovery log is gone! "
 				     "maybe the discovery timeout has been set"
-				     " too short?\n", __FUNCTION__);
+				     " too short?\n", __func__);
 			break;
 		}
 		hashbin_insert(self->discovery_log,
@@ -598,7 +598,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
 
 		IRDA_ASSERT(info != NULL, return -1;);
 
-		IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __FUNCTION__, info->s);
+		IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __func__, info->s);
 
 		/* Last discovery request ? */
 		if (info->s == 0xff)
@@ -613,7 +613,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
 		 */
 		if (irda_device_is_receiving(self->netdev) && !self->add_wait) {
 			IRDA_DEBUG(2, "%s(), device is slow to answer, "
-				   "waiting some more!\n", __FUNCTION__);
+				   "waiting some more!\n", __func__);
 			irlap_start_slot_timer(self, msecs_to_jiffies(10));
 			self->add_wait = TRUE;
 			return ret;
@@ -649,7 +649,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event,
 		}
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
 			   irlap_event[event]);
 
 		ret = -1;
@@ -671,7 +671,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
 	discovery_t *discovery_rsp;
 	int ret=0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -679,7 +679,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
 	switch (event) {
 	case QUERY_TIMER_EXPIRED:
 		IRDA_DEBUG(0, "%s(), QUERY_TIMER_EXPIRED <%ld>\n",
-			   __FUNCTION__, jiffies);
+			   __func__, jiffies);
 		irlap_next_state(self, LAP_NDM);
 		break;
 	case RECV_DISCOVERY_XID_CMD:
@@ -717,7 +717,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event,
 		}
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -1;
@@ -738,7 +738,7 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
+	IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -799,18 +799,18 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event,
 		break;
 	case RECV_DISCOVERY_XID_CMD:
 		IRDA_DEBUG(3, "%s(), event RECV_DISCOVER_XID_CMD!\n",
-			   __FUNCTION__);
+			   __func__);
 		irlap_next_state(self, LAP_NDM);
 
 		break;
 	case DISCONNECT_REQUEST:
-		IRDA_DEBUG(0, "%s(), Disconnect request!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), Disconnect request!\n", __func__);
 		irlap_send_dm_frame(self);
 		irlap_next_state( self, LAP_NDM);
 		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -1;
@@ -832,7 +832,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -861,7 +861,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
 		self->retry_count++;
 		break;
 	case RECV_SNRM_CMD:
-		IRDA_DEBUG(4, "%s(), SNRM battle!\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), SNRM battle!\n", __func__);
 
 		IRDA_ASSERT(skb != NULL, return 0;);
 		IRDA_ASSERT(info != NULL, return 0;);
@@ -948,7 +948,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -1;
@@ -966,7 +966,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event,
 static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event,
 			       struct sk_buff *skb, struct irlap_info *info)
 {
-	IRDA_DEBUG( 0, "%s(), Unknown event\n", __FUNCTION__);
+	IRDA_DEBUG( 0, "%s(), Unknown event\n", __func__);
 
 	return -1;
 }
@@ -1030,7 +1030,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
 			 */
 			if((!nextfit) && (skb->len > self->bytes_left)) {
 				IRDA_DEBUG(0, "%s(), Not allowed to transmit"
-					   " more bytes!\n", __FUNCTION__);
+					   " more bytes!\n", __func__);
 				/* Requeue the skb */
 				skb_queue_head(&self->txq, skb_get(skb));
 				/*
@@ -1082,7 +1082,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
 #endif /* CONFIG_IRDA_FAST_RR */
 		} else {
 			IRDA_DEBUG(4, "%s(), Unable to send! remote busy?\n",
-				   __FUNCTION__);
+				   __func__);
 			skb_queue_head(&self->txq, skb_get(skb));
 
 			/*
@@ -1094,7 +1094,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
 		break;
 	case POLL_TIMER_EXPIRED:
 		IRDA_DEBUG(3, "%s(), POLL_TIMER_EXPIRED <%ld>\n",
-			    __FUNCTION__, jiffies);
+			    __func__, jiffies);
 		irlap_send_rr_frame(self, CMD_FRAME);
 		/* Return to NRM properly - Jean II  */
 		self->window = self->window_size;
@@ -1120,7 +1120,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			   __FUNCTION__, irlap_event[event]);
+			   __func__, irlap_event[event]);
 
 		ret = -EINVAL;
 		break;
@@ -1138,7 +1138,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -1173,7 +1173,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event,
 		}
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d\n", __FUNCTION__, event);
+		IRDA_DEBUG(1, "%s(), Unknown event %d\n", __func__, event);
 
 		ret = -1;
 		break;
@@ -1297,7 +1297,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 			} else {
 				IRDA_DEBUG(4,
 				       "%s(), missing or duplicate frame!\n",
-					   __FUNCTION__);
+					   __func__);
 
 				/* Update Nr received */
 				irlap_update_nr_received(self, info->nr);
@@ -1367,7 +1367,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 		    (nr_status == NR_UNEXPECTED))
 		{
 			IRDA_DEBUG(4, "%s(), unexpected nr and ns!\n",
-				   __FUNCTION__);
+				   __func__);
 			if (info->pf) {
 				/* Resend rejected frames */
 				irlap_resend_rejected_frames(self, CMD_FRAME);
@@ -1407,9 +1407,9 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 			}
 			break;
 		}
-		IRDA_DEBUG(1, "%s(), Not implemented!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Not implemented!\n", __func__);
 		IRDA_DEBUG(1, "%s(), event=%s, ns_status=%d, nr_status=%d\n",
-		       __FUNCTION__, irlap_event[event], ns_status, nr_status);
+		       __func__, irlap_event[event], ns_status, nr_status);
 		break;
 	case RECV_UI_FRAME:
 		/* Poll bit cleared? */
@@ -1420,7 +1420,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 			del_timer(&self->final_timer);
 			irlap_data_indication(self, skb, TRUE);
 			irlap_next_state(self, LAP_XMIT_P);
-			IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __FUNCTION__, irlap_state[self->state]);
+			IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __func__, irlap_state[self->state]);
 			irlap_start_poll_timer(self, self->poll_timeout);
 		}
 		break;
@@ -1475,7 +1475,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 			irlap_next_state(self, LAP_NRM_P);
 		} else if (ret == NR_INVALID) {
 			IRDA_DEBUG(1, "%s(), Received RR with "
-				   "invalid nr !\n", __FUNCTION__);
+				   "invalid nr !\n", __func__);
 
 			irlap_next_state(self, LAP_RESET_WAIT);
 
@@ -1580,7 +1580,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_start_final_timer(self, 2 * self->final_timeout);
 		break;
 	case RECV_RD_RSP:
-		IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __func__);
 
 		irlap_flush_all_queues(self);
 		irlap_next_state(self, LAP_XMIT_P);
@@ -1589,7 +1589,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(1, "%s(), Unknown event %s\n",
-			    __FUNCTION__, irlap_event[event]);
+			    __func__, irlap_event[event]);
 
 		ret = -1;
 		break;
@@ -1609,7 +1609,7 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
+	IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -1635,7 +1635,7 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_next_state( self, LAP_PCLOSE);
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
 			   irlap_event[event]);
 
 		ret = -1;
@@ -1656,7 +1656,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]);
+	IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -1714,7 +1714,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
 		 * state
 		 */
 		if (!info) {
-			IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __FUNCTION__);
+			IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __func__);
 			irlap_initiate_connection_state(self);
 			irlap_wait_min_turn_around(self, &self->qos_tx);
 			irlap_send_ua_response_frame(self, &self->qos_rx);
@@ -1724,12 +1724,12 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event,
 		} else {
 			IRDA_DEBUG(0,
 				   "%s(), SNRM frame contained an I field!\n",
-				   __FUNCTION__);
+				   __func__);
 		}
 		break;
 	default:
 		IRDA_DEBUG(1, "%s(), Unknown event %s\n",
-			   __FUNCTION__, irlap_event[event]);
+			   __func__, irlap_event[event]);
 
 		ret = -1;
 		break;
@@ -1749,7 +1749,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
+	IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[event]);
 
 	IRDA_ASSERT(self != NULL, return -ENODEV;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -1786,7 +1786,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
 			 */
 			if((!nextfit) && (skb->len > self->bytes_left)) {
 				IRDA_DEBUG(0, "%s(), Not allowed to transmit"
-					   " more bytes!\n", __FUNCTION__);
+					   " more bytes!\n", __func__);
 				/* Requeue the skb */
 				skb_queue_head(&self->txq, skb_get(skb));
 
@@ -1832,7 +1832,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
 				ret = -EPROTO;
 			}
 		} else {
-			IRDA_DEBUG(2, "%s(), Unable to send!\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), Unable to send!\n", __func__);
 			skb_queue_head(&self->txq, skb_get(skb));
 			ret = -EPROTO;
 		}
@@ -1848,7 +1848,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
 		 * when we return... - Jean II */
 		break;
 	default:
-		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__,
+		IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__,
 			   irlap_event[event]);
 
 		ret = -EINVAL;
@@ -1871,7 +1871,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 	int nr_status;
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]);
+	IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;);
@@ -1880,7 +1880,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 	case RECV_I_CMD: /* Optimize for the common case */
 		/* FIXME: must check for remote_busy below */
 		IRDA_DEBUG(4, "%s(), event=%s nr=%d, vs=%d, ns=%d, "
-			   "vr=%d, pf=%d\n", __FUNCTION__,
+			   "vr=%d, pf=%d\n", __func__,
 			   irlap_event[event], info->nr,
 			   self->vs, info->ns, self->vr, info->pf);
 
@@ -2112,21 +2112,21 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 			irlap_next_state(self, LAP_NRM_S);
 		} else {
 			IRDA_DEBUG(1, "%s(), invalid nr not implemented!\n",
-				   __FUNCTION__);
+				   __func__);
 		}
 		break;
 	case RECV_SNRM_CMD:
 		/* SNRM frame is not allowed to contain an I-field */
 		if (!info) {
 			del_timer(&self->wd_timer);
-			IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __func__);
 			irlap_next_state(self, LAP_RESET_CHECK);
 
 			irlap_reset_indication(self);
 		} else {
 			IRDA_DEBUG(0,
 				   "%s(), SNRM frame contained an I-field!\n",
-				   __FUNCTION__);
+				   __func__);
 
 		}
 		break;
@@ -2158,7 +2158,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 		 *   which explain why we use (self->N2 / 2) here !!!
 		 * Jean II
 		 */
-		IRDA_DEBUG(1, "%s(), retry_count = %d\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), retry_count = %d\n", __func__,
 			   self->retry_count);
 
 		if (self->retry_count < (self->N2 / 2)) {
@@ -2211,7 +2211,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_send_test_frame(self, self->caddr, info->daddr, skb);
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -EINVAL;
@@ -2228,7 +2228,7 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -ENODEV;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -2285,7 +2285,7 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event,
 			break;		/* stay in SCLOSE */
 		}
 
-		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -EINVAL;
@@ -2301,7 +2301,7 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(1, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]);
+	IRDA_DEBUG(1, "%s(), event=%s\n", __func__, irlap_event[event]);
 
 	IRDA_ASSERT(self != NULL, return -ENODEV;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -2322,7 +2322,7 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
 		irlap_next_state(self, LAP_SCLOSE);
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__,
+		IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__,
 			   event, irlap_event[event]);
 
 		ret = -EINVAL;
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 7c132d6342af..90894534f3cc 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -102,7 +102,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
 	irlap_insert_info(self, skb);
 
 	if (unlikely(self->mode & IRDA_MODE_MONITOR)) {
-		IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __FUNCTION__,
+		IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __func__,
 			   self->netdev->name);
 		dev_kfree_skb(skb);
 		return;
@@ -182,7 +182,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
 		/* Check if the new connection address is valid */
 		if ((info->caddr == 0x00) || (info->caddr == 0xfe)) {
 			IRDA_DEBUG(3, "%s(), invalid connection address!\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 
@@ -193,7 +193,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
 		/* Only accept if addressed directly to us */
 		if (info->saddr != self->saddr) {
 			IRDA_DEBUG(2, "%s(), not addressed to us!\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 		irlap_do_event(self, RECV_SNRM_CMD, skb, info);
@@ -215,7 +215,7 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
 	struct ua_frame *frame;
 	int ret;
 
-	IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies);
+	IRDA_DEBUG(2, "%s() <%ld>\n", __func__, jiffies);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -290,7 +290,7 @@ void irlap_send_disc_frame(struct irlap_cb *self)
 	struct sk_buff *tx_skb = NULL;
 	struct disc_frame *frame;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -321,7 +321,7 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
 	__u32 bcast = BROADCAST;
 	__u8 *info;
 
-	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__,
+	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __func__,
 		   s, S, command);
 
 	IRDA_ASSERT(self != NULL, return;);
@@ -414,13 +414,13 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
 	__u8 *discovery_info;
 	char *text;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __func__);
 		return;
 	}
 
@@ -432,12 +432,12 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
 	/* Make sure frame is addressed to us */
 	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
 		IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 
 	if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) {
-		IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__);
+		IRDA_WARNING("%s: kmalloc failed!\n", __func__);
 		return;
 	}
 
@@ -445,7 +445,7 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
 	discovery->data.saddr = self->saddr;
 	discovery->timestamp = jiffies;
 
-	IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__,
+	IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__,
 		   discovery->data.daddr);
 
 	discovery_info = skb_pull(skb, sizeof(struct xid_frame));
@@ -491,7 +491,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
 	char *text;
 
 	if (!pskb_may_pull(skb, sizeof(struct xid_frame))) {
-		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __func__);
 		return;
 	}
 
@@ -503,7 +503,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
 	/* Make sure frame is addressed to us */
 	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
 		IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 
@@ -536,7 +536,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
 		if((discovery_info == NULL) ||
 		   !pskb_may_pull(skb, 3)) {
 			IRDA_ERROR("%s: discovery frame too short!\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 
@@ -545,7 +545,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
 		 */
 		discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC);
 		if (!discovery) {
-			IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
+			IRDA_WARNING("%s: unable to malloc!\n", __func__);
 			return;
 		}
 
@@ -657,7 +657,7 @@ static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
 {
 	info->nr = skb->data[1] >> 5;
 
-	IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __FUNCTION__, info->nr, jiffies);
+	IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __func__, info->nr, jiffies);
 
 	if (command)
 		irlap_do_event(self, RECV_RNR_CMD, skb, info);
@@ -668,7 +668,7 @@ static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
 static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
 				 struct irlap_info *info, int command)
 {
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s()\n", __func__);
 
 	info->nr = skb->data[1] >> 5;
 
@@ -682,7 +682,7 @@ static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
 static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
 				  struct irlap_info *info, int command)
 {
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s()\n", __func__);
 
 	info->nr = skb->data[1] >> 5;
 
@@ -696,7 +696,7 @@ static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
 static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
 				  struct irlap_info *info, int command)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	/* Check if this is a command or a response frame */
 	if (command)
@@ -755,7 +755,7 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb)
 
 		irlap_send_i_frame( self, tx_skb, CMD_FRAME);
 	} else {
-		IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
 		irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
 		self->window -= 1;
 	}
@@ -808,7 +808,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
 		irlap_next_state(self, LAP_NRM_P);
 		irlap_send_i_frame(self, tx_skb, CMD_FRAME);
 	} else {
-		IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__);
 
 		if (self->ack_required) {
 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME);
@@ -835,7 +835,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
 	 * See max_line_capacities[][] in qos.c for details. Jean II */
 	transmission_time -= (self->final_timeout * self->bytes_left
 			      / self->line_capacity);
-	IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __FUNCTION__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time);
+	IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __func__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time);
 
 	/* We are allowed to transmit a maximum number of bytes again. */
 	self->bytes_left = self->line_capacity;
@@ -1001,7 +1001,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
 		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
 		tx_skb = skb_copy(skb, GFP_ATOMIC);
 		if (!tx_skb) {
-			IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
 			return;
 		}
 
@@ -1033,7 +1033,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
 	 */
 	while (!skb_queue_empty(&self->txq)) {
 
-		IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), sending additional frames!\n", __func__);
 		if (self->window > 0) {
 			skb = skb_dequeue( &self->txq);
 			IRDA_ASSERT(skb != NULL, return;);
@@ -1073,7 +1073,7 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
 		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
 		tx_skb = skb_copy(skb, GFP_ATOMIC);
 		if (!tx_skb) {
-			IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), unable to copy\n", __func__);
 			return;
 		}
 
@@ -1096,7 +1096,7 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command)
 void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
 			 __u8 caddr, int command)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -1156,7 +1156,7 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self,
 static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
 				struct irlap_info *info)
 {
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	info->pf = skb->data[1] & PF_BIT;      /* Final bit */
 
@@ -1175,7 +1175,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
 	__u8 *frame;
 	int w, x, y, z;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
@@ -1183,7 +1183,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
 	IRDA_ASSERT(info != NULL, return;);
 
 	if (!pskb_may_pull(skb, 4)) {
-		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __func__);
 		return;
 	}
 
@@ -1269,10 +1269,10 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
 {
 	struct test_frame *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	if (!pskb_may_pull(skb, sizeof(*frame))) {
-		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __func__);
 		return;
 	}
 	frame = (struct test_frame *) skb->data;
@@ -1281,7 +1281,7 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
 	if (info->caddr == CBROADCAST) {
 		if (skb->len < sizeof(struct test_frame)) {
 			IRDA_DEBUG(0, "%s() test frame too short!\n",
-				   __FUNCTION__);
+				   __func__);
 			return;
 		}
 
@@ -1326,7 +1326,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
 	int command;
 	__u8 control;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto out;
 
 	/* FIXME: should we get our own field? */
@@ -1342,14 +1342,14 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
 	 * share and non linear skbs. This should never happen, so
 	 * we don't need to be clever about it. Jean II */
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-		IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
+		IRDA_ERROR("%s: can't clone shared skb!\n", __func__);
 		dev_kfree_skb(skb);
 		return -1;
 	}
 
 	/* Check if frame is large enough for parsing */
 	if (!pskb_may_pull(skb, 2)) {
-		IRDA_ERROR("%s: frame too short!\n", __FUNCTION__);
+		IRDA_ERROR("%s: frame too short!\n", __func__);
 		dev_kfree_skb(skb);
 		return -1;
 	}
@@ -1365,7 +1365,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
 	/*  First we check if this frame has a valid connection address */
 	if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) {
 		IRDA_DEBUG(0, "%s(), wrong connection address!\n",
-			   __FUNCTION__);
+			   __func__);
 		goto out;
 	}
 	/*
@@ -1400,7 +1400,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
 			break;
 		default:
 			IRDA_WARNING("%s: Unknown S-frame %02x received!\n",
-				__FUNCTION__, info.control);
+				__func__, info.control);
 			break;
 		}
 		goto out;
@@ -1438,7 +1438,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
 		break;
 	default:
 		IRDA_WARNING("%s: Unknown frame %02x received!\n",
-				__FUNCTION__, info.control);
+				__func__, info.control);
 		break;
 	}
 out:
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 135ac6907bbf..1f81f8e7c61d 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -76,7 +76,7 @@ const char *irlmp_reasons[] = {
  */
 int __init irlmp_init(void)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 	/* Initialize the irlmp structure. */
 	irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL);
 	if (irlmp == NULL)
@@ -164,7 +164,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid)
 	/* Allocate new instance of a LSAP connection */
 	self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		IRDA_ERROR("%s: can't allocate memory\n", __FUNCTION__);
+		IRDA_ERROR("%s: can't allocate memory\n", __func__);
 		return NULL;
 	}
 
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(irlmp_open_lsap);
  */
 static void __irlmp_close_lsap(struct lsap_cb *self)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -264,7 +264,7 @@ void irlmp_close_lsap(struct lsap_cb *self)
 	if (!lsap) {
 		IRDA_DEBUG(0,
 		     "%s(), Looks like somebody has removed me already!\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 	__irlmp_close_lsap(self);
@@ -291,7 +291,7 @@ void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
 	 */
 	lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL);
 	if (lap == NULL) {
-		IRDA_ERROR("%s: unable to kmalloc\n", __FUNCTION__);
+		IRDA_ERROR("%s: unable to kmalloc\n", __func__);
 		return;
 	}
 
@@ -304,7 +304,7 @@ void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify)
 #endif
 	lap->lsaps = hashbin_new(HB_LOCK);
 	if (lap->lsaps == NULL) {
-		IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __FUNCTION__);
+		IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __func__);
 		kfree(lap);
 		return;
 	}
@@ -336,7 +336,7 @@ void irlmp_unregister_link(__u32 saddr)
 {
 	struct lap_cb *link;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/* We must remove ourselves from the hashbin *first*. This ensure
 	 * that no more LSAPs will be open on this link and no discovery
@@ -381,7 +381,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
 
 	IRDA_DEBUG(2,
 	      "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n",
-	      __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr);
+	      __func__, self->slsap_sel, dlsap_sel, saddr, daddr);
 
 	if (test_bit(0, &self->connected)) {
 		ret = -EISCONN;
@@ -425,7 +425,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
 		if (daddr != DEV_ADDR_ANY)
 			discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
 		else {
-			IRDA_DEBUG(2, "%s(), no daddr\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), no daddr\n", __func__);
 			discovery = (discovery_t *)
 				hashbin_get_first(irlmp->cachelog);
 		}
@@ -438,7 +438,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
 	}
 	lap = hashbin_lock_find(irlmp->links, saddr, NULL);
 	if (lap == NULL) {
-		IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __func__);
 		ret = -EHOSTUNREACH;
 		goto err;
 	}
@@ -453,14 +453,14 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
 			 * disconnected yet (waiting for timeout in LAP).
 			 * Maybe we could give LAP a bit of help in this case.
 			 */
-			IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__);
+			IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__);
 			ret = -EAGAIN;
 			goto err;
 		}
 
 		/* LAP is already connected to a different node, and LAP
 		 * can only talk to one node at a time */
-		IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __func__);
 		ret = -EBUSY;
 		goto err;
 	}
@@ -522,7 +522,7 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb)
 	IRDA_ASSERT(self->lap != NULL, return;);
 
 	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
-		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+		   __func__, self->slsap_sel, self->dlsap_sel);
 
 	/* Note : self->lap is set in irlmp_link_data_indication(),
 	 * (case CONNECT_CMD:) because we have no way to set it here.
@@ -563,7 +563,7 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata)
 	 * in the state machine itself. Jean II */
 
 	IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
-		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+		   __func__, self->slsap_sel, self->dlsap_sel);
 
 	/* Make room for MUX control header (3 bytes) */
 	IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;);
@@ -589,7 +589,7 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
 	int lap_header_size;
 	int max_seg_size;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(skb != NULL, return;);
 	IRDA_ASSERT(self != NULL, return;);
@@ -603,7 +603,7 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb)
 	max_header_size = LMP_HEADER + lap_header_size;
 
 	IRDA_DEBUG(2, "%s(), max_header_size=%d\n",
-		   __FUNCTION__, max_header_size);
+		   __func__, max_header_size);
 
 	/* Hide LMP_CONTROL_HEADER header from layer above */
 	skb_pull(skb, LMP_CONTROL_HEADER);
@@ -629,7 +629,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
 	struct lsap_cb *new;
 	unsigned long flags;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
 
@@ -638,7 +638,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
 	if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) ||
 	    (orig->lap == NULL)) {
 		IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n",
-			   __FUNCTION__);
+			   __func__);
 		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
 				       flags);
 		return NULL;
@@ -647,7 +647,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
 	/* Allocate a new instance */
 	new = kmemdup(orig, sizeof(*new), GFP_ATOMIC);
 	if (!new)  {
-		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
 		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
 				       flags);
 		return NULL;
@@ -693,7 +693,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata)
 	 * and us that might mess up the hashbins below. This fixes it.
 	 * Jean II */
 	if (! test_and_clear_bit(0, &self->connected)) {
-		IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
 		dev_kfree_skb(userdata);
 		return -1;
 	}
@@ -747,19 +747,19 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
 {
 	struct lsap_cb *lsap;
 
-	IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]);
+	IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]);
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
 	IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n",
-		   __FUNCTION__, self->slsap_sel, self->dlsap_sel);
+		   __func__, self->slsap_sel, self->dlsap_sel);
 
 	/* Already disconnected ?
 	 * There is a race condition between irlmp_disconnect_request()
 	 * and us that might mess up the hashbins below. This fixes it.
 	 * Jean II */
 	if (! test_and_clear_bit(0, &self->connected)) {
-		IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__);
 		return;
 	}
 
@@ -792,7 +792,7 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason,
 		self->notify.disconnect_indication(self->notify.instance,
 						   self, reason, skb);
 	} else {
-		IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), no handler\n", __func__);
 	}
 }
 
@@ -845,7 +845,7 @@ void irlmp_do_discovery(int nslots)
 	/* Make sure the value is sane */
 	if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){
 		IRDA_WARNING("%s: invalid value for number of slots!\n",
-			     __FUNCTION__);
+			     __func__);
 		nslots = sysctl_discovery_slots = 8;
 	}
 
@@ -963,7 +963,7 @@ irlmp_notify_client(irlmp_client_t *client,
 	int	number;			/* Number of nodes in the log */
 	int	i;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	/* Check if client wants or not partial/selective log (optimisation) */
 	if (!client->disco_callback)
@@ -1014,7 +1014,7 @@ void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode)
 	irlmp_client_t *client;
 	irlmp_client_t *client_next;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(log != NULL, return;);
 
@@ -1049,7 +1049,7 @@ void irlmp_discovery_expiry(discinfo_t *expiries, int number)
 	irlmp_client_t *client_next;
 	int		i;
 
-	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(3, "%s()\n", __func__);
 
 	IRDA_ASSERT(expiries != NULL, return;);
 
@@ -1082,7 +1082,7 @@ void irlmp_discovery_expiry(discinfo_t *expiries, int number)
  */
 discovery_t *irlmp_get_discovery_response(void)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(irlmp != NULL, return NULL;);
 
@@ -1160,7 +1160,7 @@ int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
 {
 	int	ret;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(userdata != NULL, return -1;);
 
@@ -1184,7 +1184,7 @@ int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata)
  */
 void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -1211,7 +1211,7 @@ int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata,
 	struct sk_buff *clone_skb;
 	struct lap_cb *lap;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(userdata != NULL, return -1;);
 
@@ -1262,7 +1262,7 @@ int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata,
 #ifdef CONFIG_IRDA_ULTRA
 void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -1305,7 +1305,7 @@ void irlmp_status_indication(struct lap_cb *self,
 			curr->notify.status_indication(curr->notify.instance,
 						       link, lock);
 		else
-			IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), no handler\n", __func__);
 
 		curr = next;
 	}
@@ -1333,7 +1333,7 @@ void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
 	/* Get the number of lsap. That's the only safe way to know
 	 * that we have looped around... - Jean II */
 	lsap_todo = HASHBIN_GET_SIZE(self->lsaps);
-	IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __FUNCTION__, lsap_todo);
+	IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __func__, lsap_todo);
 
 	/* Poll lsap in order until the queue is full or until we
 	 * tried them all.
@@ -1352,14 +1352,14 @@ void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow)
 		/* Uh-oh... Paranoia */
 		if(curr == NULL)
 			break;
-		IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __FUNCTION__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
+		IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
 
 		/* Inform lsap user that it can send one more packet. */
 		if (curr->notify.flow_indication != NULL)
 			curr->notify.flow_indication(curr->notify.instance,
 						     curr, flow);
 		else
-			IRDA_DEBUG(1, "%s(), no handler\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), no handler\n", __func__);
 	}
 }
 
@@ -1381,7 +1381,7 @@ __u8 *irlmp_hint_to_service(__u8 *hint)
 	 */
 	service = kmalloc(16, GFP_ATOMIC);
 	if (!service) {
-		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -1482,12 +1482,12 @@ void *irlmp_register_service(__u16 hints)
 {
 	irlmp_service_t *service;
 
-	IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints);
+	IRDA_DEBUG(4, "%s(), hints = %04x\n", __func__, hints);
 
 	/* Make a new registration */
 	service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
 	if (!service) {
-		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 	service->hints.word = hints;
@@ -1512,7 +1512,7 @@ int irlmp_unregister_service(void *handle)
 	irlmp_service_t *service;
 	unsigned long flags;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	if (!handle)
 		return -1;
@@ -1520,7 +1520,7 @@ int irlmp_unregister_service(void *handle)
 	/* Caller may call with invalid handle (it's legal) - Jean II */
 	service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
 	if (!service) {
-		IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unknown service!\n", __func__);
 		return -1;
 	}
 
@@ -1557,13 +1557,13 @@ void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
 {
 	irlmp_client_t *client;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 	IRDA_ASSERT(irlmp != NULL, return NULL;);
 
 	/* Make a new registration */
 	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
 	if (!client) {
-		IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__);
+		IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -1599,7 +1599,7 @@ int irlmp_update_client(void *handle, __u16 hint_mask,
 
 	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
 	if (!client) {
-		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
 		return -1;
 	}
 
@@ -1622,7 +1622,7 @@ int irlmp_unregister_client(void *handle)
 {
 	struct irlmp_client *client;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	if (!handle)
 		return -1;
@@ -1630,11 +1630,11 @@ int irlmp_unregister_client(void *handle)
 	/* Caller may call with invalid handle (it's legal) - Jean II */
 	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
 	if (!client) {
-		IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__);
 		return -1;
 	}
 
-	IRDA_DEBUG(4, "%s(), removing client!\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s(), removing client!\n", __func__);
 	hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
 	kfree(client);
 
@@ -1663,7 +1663,7 @@ static int irlmp_slsap_inuse(__u8 slsap_sel)
 	IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
 	IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;);
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 #ifdef CONFIG_IRDA_ULTRA
 	/* Accept all bindings to the connectionless LSAP */
@@ -1790,7 +1790,7 @@ static __u8 irlmp_find_free_slsap(void)
 			/* Make sure we terminate the loop */
 			if (wrapped++) {
 				IRDA_ERROR("%s: no more free LSAPs !\n",
-					   __FUNCTION__);
+					   __func__);
 				return 0;
 			}
 		}
@@ -1805,7 +1805,7 @@ static __u8 irlmp_find_free_slsap(void)
 	/* Got it ! */
 	lsap_sel = irlmp->last_lsap_sel;
 	IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n",
-		   __FUNCTION__, lsap_sel);
+		   __func__, lsap_sel);
 
 	return lsap_sel;
 }
@@ -1823,26 +1823,26 @@ LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason)
 
 	switch (lap_reason) {
 	case LAP_DISC_INDICATION: /* Received a disconnect request from peer */
-		IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__);
+		IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __func__);
 		reason = LM_USER_REQUEST;
 		break;
 	case LAP_NO_RESPONSE:    /* To many retransmits without response */
-		IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__);
+		IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __func__);
 		reason = LM_LAP_DISCONNECT;
 		break;
 	case LAP_RESET_INDICATION:
-		IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__);
+		IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __func__);
 		reason = LM_LAP_RESET;
 		break;
 	case LAP_FOUND_NONE:
 	case LAP_MEDIA_BUSY:
 	case LAP_PRIMARY_CONFLICT:
-		IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__);
 		reason = LM_CONNECT_FAILURE;
 		break;
 	default:
 		IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n",
-			   __FUNCTION__, lap_reason);
+			   __func__, lap_reason);
 		reason = LM_LAP_DISCONNECT;
 		break;
 	}
diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
index 150cd3f1129a..78cce0cb073f 100644
--- a/net/irda/irlmp_event.c
+++ b/net/irda/irlmp_event.c
@@ -120,7 +120,7 @@ static inline void irlmp_next_lap_state(struct lap_cb *self,
 					IRLMP_STATE state)
 {
 	/*
-	IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]);
+	IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]);
 	*/
 	self->lap_state = state;
 }
@@ -130,7 +130,7 @@ static inline void irlmp_next_lsap_state(struct lsap_cb *self,
 {
 	/*
 	IRDA_ASSERT(self != NULL, return;);
-	IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]);
+	IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]);
 	*/
 	self->lsap_state = state;
 }
@@ -143,7 +143,7 @@ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event,
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
 	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n",
-		__FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]);
+		__func__, irlmp_event[event], irlsap_state[ self->lsap_state]);
 
 	return (*lsap_state[self->lsap_state]) (self, event, skb);
 }
@@ -160,7 +160,7 @@ void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
-	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __FUNCTION__,
+	IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__,
 		   irlmp_event[event],
 		   irlmp_state[self->lap_state]);
 
@@ -169,7 +169,7 @@ void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event,
 
 void irlmp_discovery_timer_expired(void *data)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/* We always cleanup the log (active & passive discovery) */
 	irlmp_do_expiry();
@@ -184,7 +184,7 @@ void irlmp_watchdog_timer_expired(void *data)
 {
 	struct lsap_cb *self = (struct lsap_cb *) data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -196,7 +196,7 @@ void irlmp_idle_timer_expired(void *data)
 {
 	struct lap_cb *self = (struct lap_cb *) data;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -256,7 +256,7 @@ irlmp_do_all_lsap_event(hashbin_t *	lsap_hashbin,
 static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
 				struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 	IRDA_ASSERT(self->irlap != NULL, return;);
 
 	switch (event) {
@@ -276,7 +276,7 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
 		irlap_connect_response(self->irlap, skb);
 		break;
 	case LM_LAP_CONNECT_REQUEST:
-		IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__);
 
 		irlmp_next_lap_state(self, LAP_U_CONNECT);
 
@@ -285,13 +285,13 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
 		IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n",
-			   __FUNCTION__);
+			   __func__);
 
 		irlmp_next_lap_state(self, LAP_STANDBY);
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			   __FUNCTION__, irlmp_event[event]);
+			   __func__, irlmp_event[event]);
 		break;
 	}
 }
@@ -306,7 +306,7 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event,
 static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 				  struct sk_buff *skb)
 {
-	IRDA_DEBUG(2, "%s(), event=%s\n", __FUNCTION__, irlmp_event[event]);
+	IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]);
 
 	switch (event) {
 	case LM_LAP_CONNECT_INDICATION:
@@ -326,7 +326,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
 		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
-			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);
+			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __func__);
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 		}
 		break;
@@ -344,12 +344,12 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
 		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
-			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __FUNCTION__);
+			IRDA_DEBUG(0, "%s() NO LSAPs !\n",  __func__);
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
 		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n",  __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n",  __func__);
 		irlmp_next_lap_state(self, LAP_STANDBY);
 
 		/* Send disconnect event to all LSAPs using this link */
@@ -357,7 +357,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 					LM_LAP_DISCONNECT_INDICATION);
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
-		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n",  __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n",  __func__);
 
 		/* One of the LSAP did timeout or was closed, if it was
 		 * the last one, try to get out of here - Jean II */
@@ -367,7 +367,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			 __FUNCTION__, irlmp_event[event]);
+			 __func__, irlmp_event[event]);
 		break;
 	}
 }
@@ -381,11 +381,11 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
 			       struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	switch (event) {
 	case LM_LAP_CONNECT_REQUEST:
-		IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__);
 
 		/*
 		 * IrLAP may have a pending disconnect. We tried to close
@@ -468,7 +468,7 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s\n",
-			 __FUNCTION__, irlmp_event[event]);
+			 __func__, irlmp_event[event]);
 		break;
 	}
 }
@@ -490,7 +490,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
 {
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -505,11 +505,11 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 #endif /* CONFIG_IRDA_ULTRA */
 	case LM_CONNECT_REQUEST:
-		IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__);
 
 		if (self->conn_skb) {
 			IRDA_WARNING("%s: busy with another request!\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 		/* Don't forget to refcount it (see irlmp_connect_request()) */
@@ -526,7 +526,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
 	case LM_CONNECT_INDICATION:
 		if (self->conn_skb) {
 			IRDA_WARNING("%s: busy with another request!\n",
-				     __FUNCTION__);
+				     __func__);
 			return -EBUSY;
 		}
 		/* Don't forget to refcount it (see irlap_driver_rcv()) */
@@ -552,7 +552,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
@@ -570,7 +570,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
 	struct lsap_cb *lsap;
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -603,7 +603,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
 	case LM_WATCHDOG_TIMEOUT:
 		/* May happen, who knows...
 		 * Jean II */
-		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __FUNCTION__);
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __func__);
 
 		/* Disconnect, get out... - Jean II */
 		self->lap = NULL;
@@ -614,7 +614,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event,
 		/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
 		 * are *not* yet bound to the IrLAP link. Jean II */
 		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
@@ -632,7 +632,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
 	struct sk_buff *tx_skb;
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -643,16 +643,16 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 	case LM_CONNECT_RESPONSE:
 		IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
-			   "no indication issued yet\n",  __FUNCTION__);
+			   "no indication issued yet\n",  __func__);
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
 		IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, "
-			   "not yet bound to IrLAP connection\n",  __FUNCTION__);
+			   "not yet bound to IrLAP connection\n",  __func__);
 		/* Keep state */
 		break;
 	case LM_LAP_CONNECT_CONFIRM:
-		IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n",  __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n",  __func__);
 		irlmp_next_lsap_state(self, LSAP_CONNECT);
 
 		tx_skb = self->conn_skb;
@@ -666,7 +666,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
 		/* Will happen in some rare cases because of a race condition.
 		 * Just make sure we don't stay there forever...
 		 * Jean II */
-		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __FUNCTION__);
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n",  __func__);
 
 		/* Go back to disconnected mode, keep the socket waiting */
 		self->lap = NULL;
@@ -680,7 +680,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
 		/* LM_LAP_DISCONNECT_INDICATION : Should never happen, we
 		 * are *not* yet bound to the IrLAP link. Jean II */
 		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
@@ -698,7 +698,7 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
 	LM_REASON reason;
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
@@ -722,12 +722,12 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 	case LM_CONNECT_REQUEST:
 		IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, "
-			   "error, LSAP already connected\n", __FUNCTION__);
+			   "error, LSAP already connected\n", __func__);
 		/* Keep state */
 		break;
 	case LM_CONNECT_RESPONSE:
 		IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, "
-			   "error, LSAP already connected\n", __FUNCTION__);
+			   "error, LSAP already connected\n", __func__);
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
@@ -740,7 +740,7 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
 		/* Try to close the LAP connection if its still there */
 		if (self->lap) {
 			IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",
-				   __FUNCTION__);
+				   __func__);
 			irlmp_do_lap_event(self->lap,
 					   LM_LAP_DISCONNECT_REQUEST,
 					   NULL);
@@ -764,14 +764,14 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event,
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
@@ -793,7 +793,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	switch (event) {
 	case LM_CONNECT_CONFIRM:
@@ -814,7 +814,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",  __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), trying to close IrLAP\n",  __func__);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
 		irlmp_disconnect_indication(self, reason, skb);
@@ -832,7 +832,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
 		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__);
 
 		IRDA_ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
@@ -842,7 +842,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
@@ -863,7 +863,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
 	LM_REASON reason;
 	int ret = 0;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(irlmp != NULL, return -1;);
@@ -883,7 +883,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
 		irlmp_next_lsap_state(self, LSAP_SETUP);
 		break;
 	case LM_WATCHDOG_TIMEOUT:
-		IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n",  __FUNCTION__);
+		IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n",  __func__);
 
 		IRDA_ASSERT(self->lap != NULL, return -1;);
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
@@ -902,7 +902,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event,
 		break;
 	default:
 		IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n",
-			   __FUNCTION__, irlmp_event[event], self->slsap_sel);
+			   __func__, irlmp_event[event], self->slsap_sel);
 		break;
 	}
 	return ret;
diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
index 0a79d9aeb08c..3750884094da 100644
--- a/net/irda/irlmp_frame.c
+++ b/net/irda/irlmp_frame.c
@@ -44,7 +44,7 @@ inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
 	skb->data[1] = slsap;
 
 	if (expedited) {
-		IRDA_DEBUG(4, "%s(), sending expedited data\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), sending expedited data\n", __func__);
 		irlap_data_request(self->irlap, skb, TRUE);
 	} else
 		irlap_data_request(self->irlap, skb, FALSE);
@@ -60,7 +60,7 @@ void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
 {
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -95,7 +95,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 	__u8   dlsap_sel;   /* Destination LSAP address */
 	__u8   *fp;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -117,7 +117,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 	if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
 		IRDA_DEBUG(3, "%s(), incoming connection, "
 			   "source LSAP=%d, dest LSAP=%d\n",
-			   __FUNCTION__, slsap_sel, dlsap_sel);
+			   __func__, slsap_sel, dlsap_sel);
 
 		/* Try to find LSAP among the unconnected LSAPs */
 		lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD,
@@ -125,7 +125,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 
 		/* Maybe LSAP was already connected, so try one more time */
 		if (!lsap) {
-			IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __func__);
 			lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0,
 					       self->lsaps);
 		}
@@ -136,12 +136,12 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 	if (lsap == NULL) {
 		IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
 		IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n",
-			   __FUNCTION__, slsap_sel, dlsap_sel);
+			   __func__, slsap_sel, dlsap_sel);
 		if (fp[0] & CONTROL_BIT) {
 			IRDA_DEBUG(2, "%s(), received control frame %02x\n",
-				   __FUNCTION__, fp[2]);
+				   __func__, fp[2]);
 		} else {
-			IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), received data frame\n", __func__);
 		}
 		return;
 	}
@@ -160,7 +160,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 			break;
 		case DISCONNECT:
 			IRDA_DEBUG(4, "%s(), Disconnect indication!\n",
-				   __FUNCTION__);
+				   __func__);
 			irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION,
 					    skb);
 			break;
@@ -172,7 +172,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb,
 			break;
 		default:
 			IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n",
-				   __FUNCTION__, fp[2]);
+				   __func__, fp[2]);
 			break;
 		}
 	} else if (unreliable) {
@@ -206,7 +206,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
 	__u8   *fp;
 	unsigned long flags;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -224,13 +224,13 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
 
 	if (pid & 0x80) {
 		IRDA_DEBUG(0, "%s(), extension in PID not supp!\n",
-			   __FUNCTION__);
+			   __func__);
 		return;
 	}
 
 	/* Check if frame is addressed to the connectionless LSAP */
 	if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) {
-		IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), dropping frame!\n", __func__);
 		return;
 	}
 
@@ -254,7 +254,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb)
 	if (lsap)
 		irlmp_connless_data_indication(lsap, skb);
 	else {
-		IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __func__);
 	}
 }
 #endif /* CONFIG_IRDA_ULTRA */
@@ -270,7 +270,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap,
 				      LAP_REASON reason,
 				      struct sk_buff *skb)
 {
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(lap != NULL, return;);
 	IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
@@ -296,7 +296,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
 				   __u32 daddr, struct qos_info *qos,
 				   struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/* Copy QoS settings for this session */
 	self->qos = qos;
@@ -317,7 +317,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr,
 void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos,
 				struct sk_buff *skb)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
@@ -383,7 +383,7 @@ void irlmp_link_discovery_indication(struct lap_cb *self,
  */
 void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
 {
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;);
diff --git a/net/irda/irmod.c b/net/irda/irmod.c
index 01554b996b9b..4c487a883725 100644
--- a/net/irda/irmod.c
+++ b/net/irda/irmod.c
@@ -90,7 +90,7 @@ static int __init irda_init(void)
 {
 	int ret = 0;
 
-	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s()\n", __func__);
 
 	/* Lower layer of the stack */
 	irlmp_init();
diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h
index 7873c392ab4c..b001c361ad30 100644
--- a/net/irda/irnet/irnet.h
+++ b/net/irda/irnet/irnet.h
@@ -337,27 +337,27 @@
 /* All error messages (will show up in the normal logs) */
 #define DERROR(dbg, format, args...) \
 	{if(DEBUG_##dbg) \
-		printk(KERN_INFO "irnet: %s(): " format, __FUNCTION__ , ##args);}
+		printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);}
 
 /* Normal debug message (will show up in /var/log/debug) */
 #define DEBUG(dbg, format, args...) \
 	{if(DEBUG_##dbg) \
-		printk(KERN_DEBUG "irnet: %s(): " format, __FUNCTION__ , ##args);}
+		printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);}
 
 /* Entering a function (trace) */
 #define DENTER(dbg, format, args...) \
 	{if(DEBUG_##dbg) \
-		printk(KERN_DEBUG "irnet: -> %s" format, __FUNCTION__ , ##args);}
+		printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);}
 
 /* Entering and exiting a function in one go (trace) */
 #define DPASS(dbg, format, args...) \
 	{if(DEBUG_##dbg) \
-		printk(KERN_DEBUG "irnet: <>%s" format, __FUNCTION__ , ##args);}
+		printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);}
 
 /* Exiting a function (trace) */
 #define DEXIT(dbg, format, args...) \
 	{if(DEBUG_##dbg) \
-		printk(KERN_DEBUG "irnet: <-%s()" format, __FUNCTION__ , ##args);}
+		printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);}
 
 /* Exit a function with debug */
 #define DRETURN(ret, dbg, args...) \
diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c
index cd9ff176ecde..9e1fb82e3220 100644
--- a/net/irda/irnetlink.c
+++ b/net/irda/irnetlink.c
@@ -40,7 +40,7 @@ static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *i
 
 	ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
 
-	IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname);
+	IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname);
 
 	return dev_get_by_name(net, ifname);
 }
@@ -56,7 +56,7 @@ static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info)
 
 	mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
 
-	IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode);
+	IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode);
 
 	dev = ifname_to_netdev(&init_net, info);
 	if (!dev)
diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c
index 40c28efaed95..ba01938becb5 100644
--- a/net/irda/irqueue.c
+++ b/net/irda/irqueue.c
@@ -232,7 +232,7 @@ static __u32 hash( const char* name)
 static void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
 {
 
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	/*
 	 * Check if queue is empty.
@@ -451,7 +451,7 @@ void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv,
 	unsigned long flags = 0;
 	int bin;
 
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	IRDA_ASSERT( hashbin != NULL, return;);
 	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;);
@@ -564,7 +564,7 @@ void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name)
 	unsigned long flags = 0;
 	irda_queue_t* entry;
 
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	IRDA_ASSERT( hashbin != NULL, return NULL;);
 	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
@@ -657,7 +657,7 @@ void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
 	int	bin;
 	long	hashv;
 
-	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG( 4, "%s()\n", __func__);
 
 	IRDA_ASSERT( hashbin != NULL, return NULL;);
 	IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 97db158c9274..74e439e80823 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -95,7 +95,7 @@ int __init irttp_init(void)
 	irttp->tsaps = hashbin_new(HB_LOCK);
 	if (!irttp->tsaps) {
 		IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n",
-			   __FUNCTION__);
+			   __func__);
 		kfree(irttp);
 		return -ENOMEM;
 	}
@@ -164,7 +164,7 @@ static void irttp_todo_expired(unsigned long data)
 	if (!self || self->magic != TTP_TSAP_MAGIC)
 		return;
 
-	IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
 
 	/* Try to make some progress, especially on Tx side - Jean II */
 	irttp_run_rx_queue(self);
@@ -205,7 +205,7 @@ void irttp_flush_queues(struct tsap_cb *self)
 {
 	struct sk_buff* skb;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -238,7 +238,7 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
 	IRDA_ASSERT(self != NULL, return NULL;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;);
 
-	IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __func__,
 		   self->rx_sdu_size);
 
 	skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size);
@@ -264,7 +264,7 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self)
 
 	IRDA_DEBUG(2,
 		   "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n",
-		   __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size);
+		   __func__, n, self->rx_sdu_size, self->rx_max_sdu_size);
 	/* Note : irttp_run_rx_queue() calculate self->rx_sdu_size
 	 * by summing the size of all fragments, so we should always
 	 * have n == self->rx_sdu_size, except in cases where we
@@ -293,7 +293,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self,
 	struct sk_buff *frag;
 	__u8 *frame;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
@@ -303,7 +303,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self,
 	 *  Split frame into a number of segments
 	 */
 	while (skb->len > self->max_seg_size) {
-		IRDA_DEBUG(2, "%s(), fragmenting ...\n", __FUNCTION__);
+		IRDA_DEBUG(2, "%s(), fragmenting ...\n", __func__);
 
 		/* Make new segment */
 		frag = alloc_skb(self->max_seg_size+self->max_header_size,
@@ -328,7 +328,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self,
 		skb_queue_tail(&self->tx_queue, frag);
 	}
 	/* Queue what is left of the original skb */
-	IRDA_DEBUG(2, "%s(), queuing last segment\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s(), queuing last segment\n", __func__);
 
 	frame = skb_push(skb, TTP_HEADER);
 	frame[0] = 0x00; /* Clear more bit */
@@ -359,7 +359,7 @@ static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
 	else
 		self->tx_max_sdu_size = param->pv.i;
 
-	IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __FUNCTION__, param->pv.i);
+	IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __func__, param->pv.i);
 
 	return 0;
 }
@@ -400,13 +400,13 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
 	 * JeanII */
 	if((stsap_sel != LSAP_ANY) &&
 	   ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) {
-		IRDA_DEBUG(0, "%s(), invalid tsap!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), invalid tsap!\n", __func__);
 		return NULL;
 	}
 
 	self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (self == NULL) {
-		IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __func__);
 		return NULL;
 	}
 
@@ -438,7 +438,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
 	 */
 	lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
 	if (lsap == NULL) {
-		IRDA_WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__);
+		IRDA_WARNING("%s: unable to allocate LSAP!!\n", __func__);
 		return NULL;
 	}
 
@@ -448,7 +448,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
 	 *  the stsap_sel we have might not be valid anymore
 	 */
 	self->stsap_sel = lsap->slsap_sel;
-	IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __FUNCTION__, self->stsap_sel);
+	IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __func__, self->stsap_sel);
 
 	self->notify = *notify;
 	self->lsap = lsap;
@@ -506,7 +506,7 @@ int irttp_close_tsap(struct tsap_cb *self)
 {
 	struct tsap_cb *tsap;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
@@ -516,7 +516,7 @@ int irttp_close_tsap(struct tsap_cb *self)
 		/* Check if disconnect is not pending */
 		if (!test_bit(0, &self->disconnect_pend)) {
 			IRDA_WARNING("%s: TSAP still connected!\n",
-				     __FUNCTION__);
+				     __func__);
 			irttp_disconnect_request(self, NULL, P_NORMAL);
 		}
 		self->close_pend = TRUE;
@@ -553,18 +553,18 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb)
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	IRDA_ASSERT(skb != NULL, return -1;);
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
 		IRDA_DEBUG(1, "%s(), No data, or not connected\n",
-			   __FUNCTION__);
+			   __func__);
 		goto err;
 	}
 
 	if (skb->len > self->max_seg_size) {
 		IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n",
-			   __FUNCTION__);
+			   __func__);
 		goto err;
 	}
 
@@ -595,12 +595,12 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 	IRDA_ASSERT(skb != NULL, return -1;);
 
-	IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__,
 		   skb_queue_len(&self->tx_queue));
 
 	/* Check that nothing bad happens */
 	if ((skb->len == 0) || (!self->connected)) {
-		IRDA_WARNING("%s: No data, or not connected\n", __FUNCTION__);
+		IRDA_WARNING("%s: No data, or not connected\n", __func__);
 		ret = -ENOTCONN;
 		goto err;
 	}
@@ -611,7 +611,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
 	 */
 	if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
 		IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n",
-			   __FUNCTION__);
+			   __func__);
 		ret = -EMSGSIZE;
 		goto err;
 	}
@@ -625,7 +625,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb)
 	    (skb->len > self->tx_max_sdu_size))
 	{
 		IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n",
-			   __FUNCTION__);
+			   __func__);
 		ret = -EMSGSIZE;
 		goto err;
 	}
@@ -704,7 +704,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self)
 	int n;
 
 	IRDA_DEBUG(2, "%s() : send_credit = %d, queue_len = %d\n",
-		   __FUNCTION__,
+		   __func__,
 		   self->send_credit, skb_queue_len(&self->tx_queue));
 
 	/* Get exclusive access to the tx queue, otherwise don't touch it */
@@ -813,7 +813,7 @@ static inline void irttp_give_credit(struct tsap_cb *self)
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n",
-		   __FUNCTION__,
+		   __func__,
 		   self->send_credit, self->avail_credit, self->remote_credit);
 
 	/* Give credit to peer */
@@ -862,7 +862,7 @@ static int irttp_udata_indication(void *instance, void *sap,
 	struct tsap_cb *self;
 	int err;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	self = (struct tsap_cb *) instance;
 
@@ -979,7 +979,7 @@ static void irttp_status_indication(void *instance,
 {
 	struct tsap_cb *self;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	self = (struct tsap_cb *) instance;
 
@@ -997,7 +997,7 @@ static void irttp_status_indication(void *instance,
 		self->notify.status_indication(self->notify.instance,
 					       link, lock);
 	else
-		IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__);
+		IRDA_DEBUG(2, "%s(), no handler\n", __func__);
 }
 
 /*
@@ -1015,7 +1015,7 @@ static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
-	IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self);
+	IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self);
 
 	/* We are "polled" directly from LAP, and the LAP want to fill
 	 * its Tx window. We want to do our best to send it data, so that
@@ -1053,18 +1053,18 @@ static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
  */
 void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
 {
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	IRDA_ASSERT(self != NULL, return;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
 
 	switch (flow) {
 	case FLOW_STOP:
-		IRDA_DEBUG(1, "%s(), flow stop\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), flow stop\n", __func__);
 		self->rx_sdu_busy = TRUE;
 		break;
 	case FLOW_START:
-		IRDA_DEBUG(1, "%s(), flow start\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), flow start\n", __func__);
 		self->rx_sdu_busy = FALSE;
 
 		/* Client say he can accept more data, try to free our
@@ -1073,7 +1073,7 @@ void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow)
 
 		break;
 	default:
-		IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __func__);
 	}
 }
 EXPORT_SYMBOL(irttp_flow_request);
@@ -1093,7 +1093,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
 	__u8 *frame;
 	__u8 n;
 
-	IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __FUNCTION__, max_sdu_size);
+	IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __func__, max_sdu_size);
 
 	IRDA_ASSERT(self != NULL, return -EBADR;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;);
@@ -1191,7 +1191,7 @@ static void irttp_connect_confirm(void *instance, void *sap,
 	__u8 plen;
 	__u8 n;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	self = (struct tsap_cb *) instance;
 
@@ -1215,7 +1215,7 @@ static void irttp_connect_confirm(void *instance, void *sap,
 
 	n = skb->data[0] & 0x7f;
 
-	IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __FUNCTION__, n);
+	IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __func__, n);
 
 	self->send_credit = n;
 	self->tx_max_sdu_size = 0;
@@ -1236,7 +1236,7 @@ static void irttp_connect_confirm(void *instance, void *sap,
 		/* Any errors in the parameter list? */
 		if (ret < 0) {
 			IRDA_WARNING("%s: error extracting parameters\n",
-				     __FUNCTION__);
+				     __func__);
 			dev_kfree_skb(skb);
 
 			/* Do not accept this connection attempt */
@@ -1246,10 +1246,10 @@ static void irttp_connect_confirm(void *instance, void *sap,
 		skb_pull(skb, IRDA_MIN(skb->len, plen+1));
 	}
 
-	IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__,
+	IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __func__,
 	      self->send_credit, self->avail_credit, self->remote_credit);
 
-	IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __func__,
 		   self->tx_max_sdu_size);
 
 	if (self->notify.connect_confirm) {
@@ -1288,7 +1288,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
 	self->max_seg_size = max_seg_size - TTP_HEADER;
 	self->max_header_size = max_header_size+TTP_HEADER;
 
-	IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __FUNCTION__, self->stsap_sel);
+	IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __func__, self->stsap_sel);
 
 	/* Need to update dtsap_sel if its equal to LSAP_ANY */
 	self->dtsap_sel = lsap->dlsap_sel;
@@ -1313,7 +1313,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
 		/* Any errors in the parameter list? */
 		if (ret < 0) {
 			IRDA_WARNING("%s: error extracting parameters\n",
-				     __FUNCTION__);
+				     __func__);
 			dev_kfree_skb(skb);
 
 			/* Do not accept this connection attempt */
@@ -1350,7 +1350,7 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
 	IRDA_ASSERT(self != NULL, return -1;);
 	IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
 
-	IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __FUNCTION__,
+	IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __func__,
 		   self->stsap_sel);
 
 	/* Any userdata supplied? */
@@ -1432,14 +1432,14 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
 	struct tsap_cb *new;
 	unsigned long flags;
 
-	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s()\n", __func__);
 
 	/* Protect our access to the old tsap instance */
 	spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
 
 	/* Find the old instance */
 	if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) {
-		IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __func__);
 		spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 		return NULL;
 	}
@@ -1447,7 +1447,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
 	/* Allocate a new instance */
 	new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (!new) {
-		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__);
 		spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 		return NULL;
 	}
@@ -1460,7 +1460,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
 	/* Try to dup the LSAP (may fail if we were too slow) */
 	new->lsap = irlmp_dup(orig->lsap, new);
 	if (!new->lsap) {
-		IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s(), dup failed!\n", __func__);
 		kfree(new);
 		return NULL;
 	}
@@ -1495,7 +1495,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
 
 	/* Already disconnected? */
 	if (!self->connected) {
-		IRDA_DEBUG(4, "%s(), already disconnected!\n", __FUNCTION__);
+		IRDA_DEBUG(4, "%s(), already disconnected!\n", __func__);
 		if (userdata)
 			dev_kfree_skb(userdata);
 		return -1;
@@ -1508,7 +1508,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
 	 * Jean II */
 	if(test_and_set_bit(0, &self->disconnect_pend)) {
 		IRDA_DEBUG(0, "%s(), disconnect already pending\n",
-			   __FUNCTION__);
+			   __func__);
 		if (userdata)
 			dev_kfree_skb(userdata);
 
@@ -1527,7 +1527,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
 			 *  disconnecting right now since the data will
 			 *  not have any usable connection to be sent on
 			 */
-			IRDA_DEBUG(1, "%s(): High priority!!()\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(): High priority!!()\n", __func__);
 			irttp_flush_queues(self);
 		} else if (priority == P_NORMAL) {
 			/*
@@ -1548,7 +1548,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
 	 * be sent at the LMP level (so even if the peer has its Tx queue
 	 * full of data). - Jean II */
 
-	IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __FUNCTION__);
+	IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __func__);
 	self->connected = FALSE;
 
 	if (!userdata) {
@@ -1584,7 +1584,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason,
 {
 	struct tsap_cb *self;
 
-	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(4, "%s()\n", __func__);
 
 	self = (struct tsap_cb *) instance;
 
@@ -1644,7 +1644,7 @@ static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb)
 	 * give an error back
 	 */
 	if (err) {
-		IRDA_DEBUG(0, "%s() requeueing skb!\n", __FUNCTION__);
+		IRDA_DEBUG(0, "%s() requeueing skb!\n", __func__);
 
 		/* Make sure we take a break */
 		self->rx_sdu_busy = TRUE;
@@ -1669,7 +1669,7 @@ void irttp_run_rx_queue(struct tsap_cb *self)
 	struct sk_buff *skb;
 	int more = 0;
 
-	IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __func__,
 		   self->send_credit, self->avail_credit, self->remote_credit);
 
 	/* Get exclusive access to the rx queue, otherwise don't touch it */
@@ -1710,7 +1710,7 @@ void irttp_run_rx_queue(struct tsap_cb *self)
 			 */
 			if (self->rx_sdu_size <= self->rx_max_sdu_size) {
 				IRDA_DEBUG(4, "%s(), queueing frag\n",
-					   __FUNCTION__);
+					   __func__);
 				skb_queue_tail(&self->rx_fragments, skb);
 			} else {
 				/* Free the part of the SDU that is too big */
@@ -1740,7 +1740,7 @@ void irttp_run_rx_queue(struct tsap_cb *self)
 			/* Now we can deliver the reassembled skb */
 			irttp_do_data_indication(self, skb);
 		} else {
-			IRDA_DEBUG(1, "%s(), Truncated frame\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), Truncated frame\n", __func__);
 
 			/* Free the part of the SDU that is too big */
 			dev_kfree_skb(skb);
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index 722bbe044d9c..fc1a20565e2d 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -148,23 +148,23 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
 	 */
 	if (p.pl == 0) {
 		if (p.pv.i < 0xff) {
-			IRDA_DEBUG(2, "%s(), using 1 byte\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), using 1 byte\n", __func__);
 			p.pl = 1;
 		} else if (p.pv.i < 0xffff) {
-			IRDA_DEBUG(2, "%s(), using 2 bytes\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), using 2 bytes\n", __func__);
 			p.pl = 2;
 		} else {
-			IRDA_DEBUG(2, "%s(), using 4 bytes\n", __FUNCTION__);
+			IRDA_DEBUG(2, "%s(), using 4 bytes\n", __func__);
 			p.pl = 4; /* Default length */
 		}
 	}
 	/* Check if buffer is long enough for insertion */
 	if (len < (2+p.pl)) {
 		IRDA_WARNING("%s: buffer too short for insertion!\n",
-			     __FUNCTION__);
+			     __func__);
 		return -1;
 	}
-	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
 		   p.pi, p.pl, p.pv.i);
 	switch (p.pl) {
 	case 1:
@@ -187,7 +187,7 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi,
 		break;
 	default:
 		IRDA_WARNING("%s: length %d not supported\n",
-			     __FUNCTION__, p.pl);
+			     __func__, p.pl);
 		/* Skip parameter */
 		return -1;
 	}
@@ -218,7 +218,7 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
 	if (len < (2+p.pl)) {
 		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
-			     __FUNCTION__, p.pl, len);
+			     __func__, p.pl, len);
 		return -1;
 	}
 
@@ -230,7 +230,7 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
 	if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) {
 		IRDA_ERROR("%s: invalid parameter length! "
 			   "Expected %d bytes, but value had %d bytes!\n",
-			   __FUNCTION__, type & PV_MASK, p.pl);
+			   __func__, type & PV_MASK, p.pl);
 
 		/* Most parameters are bit/byte fields or little endian,
 		 * so it's ok to only extract a subset of it (the subset
@@ -268,13 +268,13 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi,
 		break;
 	default:
 		IRDA_WARNING("%s: length %d not supported\n",
-			     __FUNCTION__, p.pl);
+			     __func__, p.pl);
 
 		/* Skip parameter */
 		return p.pl+2;
 	}
 
-	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__,
 		   p.pi, p.pl, p.pv.i);
 	/* Call handler for this parameter */
 	err = (*func)(self, &p, PV_PUT);
@@ -294,19 +294,19 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
 	irda_param_t p;
 	int err;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	p.pi = pi;     /* In case handler needs to know */
 	p.pl = buf[1]; /* Extract length of value */
 
-	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__,
 		   p.pi, p.pl);
 
 	/* Check if buffer is long enough for parsing */
 	if (len < (2+p.pl)) {
 		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
-			     __FUNCTION__, p.pl, len);
+			     __func__, p.pl, len);
 		return -1;
 	}
 
@@ -314,7 +314,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi,
 	 * checked that the buffer is long enough */
 	strncpy(str, buf+2, p.pl);
 
-	IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __FUNCTION__,
+	IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __func__,
 		   (__u8) str[0], (__u8) str[1]);
 
 	/* Null terminate string */
@@ -345,11 +345,11 @@ static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi,
 	if (len < (2+p.pl)) {
 		IRDA_WARNING("%s: buffer too short for parsing! "
 			     "Need %d bytes, but len is only %d\n",
-			     __FUNCTION__, p.pl, len);
+			     __func__, p.pl, len);
 		return -1;
 	}
 
-	IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__);
+	IRDA_DEBUG(0, "%s(), not impl\n", __func__);
 
 	return p.pl+2; /* Extracted pl+2 bytes */
 }
@@ -473,7 +473,7 @@ int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len,
 	    (pi_minor > info->tables[pi_major].len-1))
 	{
 		IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
-			   __FUNCTION__, pi);
+			   __func__, pi);
 
 		/* Skip this parameter */
 		return -1;
@@ -487,7 +487,7 @@ int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len,
 
 	/*  Check if handler has been implemented */
 	if (!pi_minor_info->func) {
-		IRDA_MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi);
+		IRDA_MESSAGE("%s: no handler for pi=%#x\n", __func__, pi);
 		/* Skip this parameter */
 		return -1;
 	}
@@ -527,7 +527,7 @@ static int irda_param_extract(void *self, __u8 *buf, int len,
 	    (pi_minor > info->tables[pi_major].len-1))
 	{
 		IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n",
-			   __FUNCTION__, buf[0]);
+			   __func__, buf[0]);
 
 		/* Skip this parameter */
 		return 2 + buf[n + 1];  /* Continue */
@@ -539,13 +539,13 @@ static int irda_param_extract(void *self, __u8 *buf, int len,
 	/* Find expected data type for this parameter identifier (pi)*/
 	type = pi_minor_info->type;
 
-	IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __FUNCTION__,
+	IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __func__,
 		   pi_major, pi_minor, type);
 
 	/*  Check if handler has been implemented */
 	if (!pi_minor_info->func) {
 		IRDA_MESSAGE("%s: no handler for pi=%#x\n",
-			     __FUNCTION__, buf[n]);
+			     __func__, buf[n]);
 		/* Skip this parameter */
 		return 2 + buf[n + 1]; /* Continue */
 	}
diff --git a/net/irda/qos.c b/net/irda/qos.c
index aeb18cf1dcae..2b00974e5bae 100644
--- a/net/irda/qos.c
+++ b/net/irda/qos.c
@@ -201,7 +201,7 @@ static int msb_index (__u16 word)
 	 * it's very likely the peer. - Jean II */
 	if (word == 0) {
 		IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n",
-			 __FUNCTION__);
+			 __func__);
 		/* The only safe choice (we don't know the array size) */
 		word = 0x1;
 	}
@@ -342,7 +342,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
 	__u32 line_capacity;
 	int index;
 
-	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+	IRDA_DEBUG(2, "%s()\n", __func__);
 
 	/*
 	 * Make sure the mintt is sensible.
@@ -352,7 +352,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
 		int i;
 
 		IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n",
-			 __FUNCTION__, sysctl_min_tx_turn_time);
+			 __func__, sysctl_min_tx_turn_time);
 
 		/* We don't really need bits, but easier this way */
 		i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times,
@@ -370,7 +370,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
 	{
 		IRDA_DEBUG(0,
 			   "%s(), adjusting max turn time from %d to 500 ms\n",
-			   __FUNCTION__, qos->max_turn_time.value);
+			   __func__, qos->max_turn_time.value);
 		qos->max_turn_time.value = 500;
 	}
 
@@ -386,7 +386,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
 	while ((qos->data_size.value > line_capacity) && (index > 0)) {
 		qos->data_size.value = data_sizes[index--];
 		IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
-			   __FUNCTION__, qos->data_size.value);
+			   __func__, qos->data_size.value);
 	}
 #else /* Use method described in section 6.6.11 of IrLAP */
 	while (irlap_requested_line_capacity(qos) > line_capacity) {
@@ -396,14 +396,14 @@ static void irlap_adjust_qos_settings(struct qos_info *qos)
 		if (qos->window_size.value > 1) {
 			qos->window_size.value--;
 			IRDA_DEBUG(2, "%s(), reducing window size to %d\n",
-				   __FUNCTION__, qos->window_size.value);
+				   __func__, qos->window_size.value);
 		} else if (index > 1) {
 			qos->data_size.value = data_sizes[index--];
 			IRDA_DEBUG(2, "%s(), reducing data size to %d\n",
-				   __FUNCTION__, qos->data_size.value);
+				   __func__, qos->data_size.value);
 		} else {
 			IRDA_WARNING("%s(), nothing more we can do!\n",
-				     __FUNCTION__);
+				     __func__);
 		}
 	}
 #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
@@ -538,7 +538,7 @@ static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get)
 	if (get) {
 		param->pv.i = self->qos_rx.baud_rate.bits;
 		IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n",
-			   __FUNCTION__, param->pv.i);
+			   __func__, param->pv.i);
 	} else {
 		/*
 		 *  Stations must agree on baud rate, so calculate
@@ -711,7 +711,7 @@ __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
 	int i,j;
 
 	IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n",
-		   __FUNCTION__, speed, max_turn_time);
+		   __func__, speed, max_turn_time);
 
 	i = value_index(speed, baud_rates, 10);
 	j = value_index(max_turn_time, max_turn_times, 4);
@@ -722,7 +722,7 @@ __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time)
 	line_capacity = max_line_capacities[i][j];
 
 	IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n",
-		   __FUNCTION__, line_capacity);
+		   __func__, line_capacity);
 
 	return line_capacity;
 }
@@ -738,7 +738,7 @@ static __u32 irlap_requested_line_capacity(struct qos_info *qos)
 					     qos->min_turn_time.value);
 
 	IRDA_DEBUG(2, "%s(), requested line capacity=%d\n",
-		   __FUNCTION__, line_capacity);
+		   __func__, line_capacity);
 
 	return line_capacity;
 }
diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c
index c246983308b8..fd0995b1323a 100644
--- a/net/irda/wrapper.c
+++ b/net/irda/wrapper.c
@@ -106,16 +106,16 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 		 * Nothing to worry about, but we set the default number of
 		 * BOF's
 		 */
-		IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __FUNCTION__);
+		IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __func__);
 		xbofs = 10;
 	} else
 		xbofs = cb->xbofs + cb->xbofs_delay;
 
-	IRDA_DEBUG(4, "%s(), xbofs=%d\n", __FUNCTION__, xbofs);
+	IRDA_DEBUG(4, "%s(), xbofs=%d\n", __func__, xbofs);
 
 	/* Check that we never use more than 115 + 48 xbofs */
 	if (xbofs > 163) {
-		IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __FUNCTION__,
+		IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __func__,
 			   xbofs);
 		xbofs = 163;
 	}
@@ -135,7 +135,7 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 		 */
 		if(n >= (buffsize-5)) {
 			IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n",
-				   __FUNCTION__, n);
+				   __func__, n);
 			return n;
 		}
 
@@ -287,7 +287,7 @@ async_unwrap_bof(struct net_device *dev,
 		/* Not supposed to happen, the previous frame is not
 		 * finished - Jean II */
 		IRDA_DEBUG(1, "%s(), Discarding incomplete frame\n",
-			   __FUNCTION__);
+			   __func__);
 		stats->rx_errors++;
 		stats->rx_missed_errors++;
 		irda_device_set_media_busy(dev, TRUE);
@@ -360,7 +360,7 @@ async_unwrap_eof(struct net_device *dev,
 			/* Wrong CRC, discard frame!  */
 			irda_device_set_media_busy(dev, TRUE);
 
-			IRDA_DEBUG(1, "%s(), crc error\n", __FUNCTION__);
+			IRDA_DEBUG(1, "%s(), crc error\n", __func__);
 			stats->rx_errors++;
 			stats->rx_crc_errors++;
 		}
@@ -386,7 +386,7 @@ async_unwrap_ce(struct net_device *dev,
 		break;
 
 	case LINK_ESCAPE:
-		IRDA_WARNING("%s: state not defined\n", __FUNCTION__);
+		IRDA_WARNING("%s: state not defined\n", __func__);
 		break;
 
 	case BEGIN_FRAME:
@@ -421,7 +421,7 @@ async_unwrap_other(struct net_device *dev,
 #endif
 		} else {
 			IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
-				   __FUNCTION__);
+				   __func__);
 			rx_buff->state = OUTSIDE_FRAME;
 		}
 		break;
@@ -440,7 +440,7 @@ async_unwrap_other(struct net_device *dev,
 			rx_buff->state = INSIDE_FRAME;
 		} else {
 			IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n",
-				   __FUNCTION__);
+				   __func__);
 			rx_buff->state = OUTSIDE_FRAME;
 		}
 		break;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index e9ef9af4a53b..6db58924368a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -48,6 +48,17 @@ struct pfkey_sock {
 	struct sock	sk;
 	int		registered;
 	int		promisc;
+
+	struct {
+		uint8_t		msg_version;
+		uint32_t	msg_pid;
+		int		(*dump)(struct pfkey_sock *sk);
+		void		(*done)(struct pfkey_sock *sk);
+		union {
+			struct xfrm_policy_walk	policy;
+			struct xfrm_state_walk	state;
+		} u;
+	} dump;
 };
 
 static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
@@ -55,6 +66,27 @@ static inline struct pfkey_sock *pfkey_sk(struct sock *sk)
 	return (struct pfkey_sock *)sk;
 }
 
+static int pfkey_can_dump(struct sock *sk)
+{
+	if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf)
+		return 1;
+	return 0;
+}
+
+static int pfkey_do_dump(struct pfkey_sock *pfk)
+{
+	int rc;
+
+	rc = pfk->dump.dump(pfk);
+	if (rc == -ENOBUFS)
+		return 0;
+
+	pfk->dump.done(pfk);
+	pfk->dump.dump = NULL;
+	pfk->dump.done = NULL;
+	return rc;
+}
+
 static void pfkey_sock_destruct(struct sock *sk)
 {
 	skb_queue_purge(&sk->sk_receive_queue);
@@ -1709,45 +1741,60 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
 	return 0;
 }
 
-struct pfkey_dump_data
-{
-	struct sk_buff *skb;
-	struct sadb_msg *hdr;
-	struct sock *sk;
-};
-
 static int dump_sa(struct xfrm_state *x, int count, void *ptr)
 {
-	struct pfkey_dump_data *data = ptr;
+	struct pfkey_sock *pfk = ptr;
 	struct sk_buff *out_skb;
 	struct sadb_msg *out_hdr;
 
+	if (!pfkey_can_dump(&pfk->sk))
+		return -ENOBUFS;
+
 	out_skb = pfkey_xfrm_state2msg(x);
 	if (IS_ERR(out_skb))
 		return PTR_ERR(out_skb);
 
 	out_hdr = (struct sadb_msg *) out_skb->data;
-	out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+	out_hdr->sadb_msg_version = pfk->dump.msg_version;
 	out_hdr->sadb_msg_type = SADB_DUMP;
 	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
 	out_hdr->sadb_msg_errno = 0;
 	out_hdr->sadb_msg_reserved = 0;
 	out_hdr->sadb_msg_seq = count;
-	out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
 	return 0;
 }
 
+static int pfkey_dump_sa(struct pfkey_sock *pfk)
+{
+	return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk);
+}
+
+static void pfkey_dump_sa_done(struct pfkey_sock *pfk)
+{
+	xfrm_state_walk_done(&pfk->dump.u.state);
+}
+
 static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
 	u8 proto;
-	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+	struct pfkey_sock *pfk = pfkey_sk(sk);
+
+	if (pfk->dump.dump != NULL)
+		return -EBUSY;
 
 	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
 	if (proto == 0)
 		return -EINVAL;
 
-	return xfrm_state_walk(proto, dump_sa, &data);
+	pfk->dump.msg_version = hdr->sadb_msg_version;
+	pfk->dump.msg_pid = hdr->sadb_msg_pid;
+	pfk->dump.dump = pfkey_dump_sa;
+	pfk->dump.done = pfkey_dump_sa_done;
+	xfrm_state_walk_init(&pfk->dump.u.state, proto);
+
+	return pfkey_do_dump(pfk);
 }
 
 static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1780,7 +1827,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr)
 
 static u32 gen_reqid(void)
 {
+	struct xfrm_policy_walk walk;
 	u32 start;
+	int rc;
 	static u32 reqid = IPSEC_MANUAL_REQID_MAX;
 
 	start = reqid;
@@ -1788,8 +1837,10 @@ static u32 gen_reqid(void)
 		++reqid;
 		if (reqid == 0)
 			reqid = IPSEC_MANUAL_REQID_MAX+1;
-		if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid,
-				     (void*)&reqid) != -EEXIST)
+		xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN);
+		rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid);
+		xfrm_policy_walk_done(&walk);
+		if (rc != -EEXIST)
 			return reqid;
 	} while (reqid != start);
 	return 0;
@@ -2638,11 +2689,14 @@ out:
 
 static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
 {
-	struct pfkey_dump_data *data = ptr;
+	struct pfkey_sock *pfk = ptr;
 	struct sk_buff *out_skb;
 	struct sadb_msg *out_hdr;
 	int err;
 
+	if (!pfkey_can_dump(&pfk->sk))
+		return -ENOBUFS;
+
 	out_skb = pfkey_xfrm_policy2msg_prep(xp);
 	if (IS_ERR(out_skb))
 		return PTR_ERR(out_skb);
@@ -2652,21 +2706,40 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
 		return err;
 
 	out_hdr = (struct sadb_msg *) out_skb->data;
-	out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+	out_hdr->sadb_msg_version = pfk->dump.msg_version;
 	out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
 	out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
 	out_hdr->sadb_msg_errno = 0;
 	out_hdr->sadb_msg_seq = count;
-	out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
-	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+	out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
 	return 0;
 }
 
+static int pfkey_dump_sp(struct pfkey_sock *pfk)
+{
+	return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk);
+}
+
+static void pfkey_dump_sp_done(struct pfkey_sock *pfk)
+{
+	xfrm_policy_walk_done(&pfk->dump.u.policy);
+}
+
 static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
-	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+	struct pfkey_sock *pfk = pfkey_sk(sk);
+
+	if (pfk->dump.dump != NULL)
+		return -EBUSY;
+
+	pfk->dump.msg_version = hdr->sadb_msg_version;
+	pfk->dump.msg_pid = hdr->sadb_msg_pid;
+	pfk->dump.dump = pfkey_dump_sp;
+	pfk->dump.done = pfkey_dump_sp_done;
+	xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN);
 
-	return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data);
+	return pfkey_do_dump(pfk);
 }
 
 static int key_notify_policy_flush(struct km_event *c)
@@ -3671,6 +3744,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
 			 int flags)
 {
 	struct sock *sk = sock->sk;
+	struct pfkey_sock *pfk = pfkey_sk(sk);
 	struct sk_buff *skb;
 	int copied, err;
 
@@ -3698,6 +3772,10 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
 
 	err = (flags & MSG_TRUNC) ? skb->len : copied;
 
+	if (pfk->dump.dump != NULL &&
+	    3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
+		pfkey_do_dump(pfk);
+
 out_free:
 	skb_free_datagram(sk, skb);
 out:
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 8c50eb430c19..97101dcde4c0 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -188,7 +188,7 @@ static int llc_ui_release(struct socket *sock)
 	sock_hold(sk);
 	lock_sock(sk);
 	llc = llc_sk(sk);
-	dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
+	dprintk("%s: closing local(%02X) remote(%02X)\n", __func__,
 		llc->laddr.lsap, llc->daddr.lsap);
 	if (!llc_send_disc(sk))
 		llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo);
@@ -298,7 +298,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
 	struct llc_sap *sap;
 	int rc = -EINVAL;
 
-	dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap);
+	dprintk("%s: binding %02X\n", __func__, addr->sllc_sap);
 	if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
 		goto out;
 	rc = -EAFNOSUPPORT;
@@ -435,7 +435,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
 	rc = llc_establish_connection(sk, llc->dev->dev_addr,
 				      addr->sllc_mac, addr->sllc_sap);
 	if (rc) {
-		dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
+		dprintk("%s: llc_ui_send_conn failed :-(\n", __func__);
 		sock->state  = SS_UNCONNECTED;
 		sk->sk_state = TCP_CLOSE;
 		goto out;
@@ -607,7 +607,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
 	struct sk_buff *skb;
 	int rc = -EOPNOTSUPP;
 
-	dprintk("%s: accepting on %02X\n", __FUNCTION__,
+	dprintk("%s: accepting on %02X\n", __func__,
 		llc_sk(sk)->laddr.lsap);
 	lock_sock(sk);
 	if (unlikely(sk->sk_type != SOCK_STREAM))
@@ -622,7 +622,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
 		if (rc)
 			goto out;
 	}
-	dprintk("%s: got a new connection on %02X\n", __FUNCTION__,
+	dprintk("%s: got a new connection on %02X\n", __func__,
 		llc_sk(sk)->laddr.lsap);
 	skb = skb_dequeue(&sk->sk_receive_queue);
 	rc = -EINVAL;
@@ -643,7 +643,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
 	/* put original socket back into a clean listen state. */
 	sk->sk_state = TCP_LISTEN;
 	sk->sk_ack_backlog--;
-	dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
+	dprintk("%s: ok success on %02X, client on %02X\n", __func__,
 		llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap);
 frees:
 	kfree_skb(skb);
@@ -836,7 +836,7 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock,
 	size_t size = 0;
 	int rc = -EINVAL, copied = 0, hdrlen;
 
-	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__,
+	dprintk("%s: sending from %02X to %02X\n", __func__,
 		llc->laddr.lsap, llc->daddr.lsap);
 	lock_sock(sk);
 	if (addr) {
@@ -894,7 +894,7 @@ out:
 		kfree_skb(skb);
 release:
 		dprintk("%s: failed sending from %02X to %02X: %d\n",
-			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
+			__func__, llc->laddr.lsap, llc->daddr.lsap, rc);
 	}
 	release_sock(sk);
 	return rc ? : copied;
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index 71a00225bdb3..019c780512e8 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -1430,7 +1430,7 @@ static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb)
 {
 	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
 		printk(KERN_WARNING "%s: timer called on closed connection\n",
-		       __FUNCTION__);
+		       __func__);
 		kfree_skb(skb);
 	} else {
 		if (!sock_owned_by_user(sk))
diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
index c5deda246614..523fdd1cf781 100644
--- a/net/llc/llc_c_ev.c
+++ b/net/llc/llc_c_ev.c
@@ -228,7 +228,7 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
 		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
 	if (!rc)
 		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
-			__FUNCTION__, llc_sk(sk)->state, ns, vr);
+			__func__, llc_sk(sk)->state, ns, vr);
 	return rc;
 }
 
@@ -306,7 +306,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
 		 llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
 	if (!rc)
 		dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
-			__FUNCTION__, llc_sk(sk)->state, ns, vr);
+			__func__, llc_sk(sk)->state, ns, vr);
 	return rc;
 }
 
@@ -511,7 +511,7 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
 	    (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) &&
 	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
 		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
-			__FUNCTION__, llc_sk(sk)->state, vs, nr);
+			__func__, llc_sk(sk)->state, vs, nr);
 		rc = 0;
 	}
 	return rc;
@@ -530,7 +530,7 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
 	    nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
 		rc = 0;
 		dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
-			__FUNCTION__, llc_sk(sk)->state, vs, nr);
+			__func__, llc_sk(sk)->state, vs, nr);
 	}
 	return rc;
 }
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 441bc18f996d..5c6d89c6d51d 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -73,7 +73,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 	 */
 	rc = llc_conn_service(skb->sk, skb);
 	if (unlikely(rc != 0)) {
-		printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
+		printk(KERN_ERR "%s: llc_conn_service failed\n", __func__);
 		goto out_kfree_skb;
 	}
 
@@ -99,7 +99,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 			 * shouldn't happen
 			 */
 			printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n",
-			       __FUNCTION__);
+			       __func__);
 			kfree_skb(skb);
 		}
 		break;
@@ -132,13 +132,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 		 * FIXME:
 		 * RESET is not being notified to upper layers for now
 		 */
-		printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__);
+		printk(KERN_INFO "%s: received a reset ind!\n", __func__);
 		kfree_skb(skb);
 		break;
 	default:
 		if (ev->ind_prim) {
 			printk(KERN_INFO "%s: received unknown %d prim!\n",
-				__FUNCTION__, ev->ind_prim);
+				__func__, ev->ind_prim);
 			kfree_skb(skb);
 		}
 		/* No indication */
@@ -179,12 +179,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
 		 * FIXME:
 		 * RESET is not being notified to upper layers for now
 		 */
-		printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__);
+		printk(KERN_INFO "%s: received a reset conf!\n", __func__);
 		break;
 	default:
 		if (ev->cfm_prim) {
 			printk(KERN_INFO "%s: received unknown %d prim!\n",
-					__FUNCTION__, ev->cfm_prim);
+					__func__, ev->cfm_prim);
 			break;
 		}
 		goto out_skb_put; /* No confirmation */
@@ -700,7 +700,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk,
 					     struct llc_addr *saddr,
 					     struct llc_addr *daddr)
 {
-	struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC,
+	struct sock *newsk = llc_sk_alloc(sock_net(sk), sk->sk_family, GFP_ATOMIC,
 					  sk->sk_prot);
 	struct llc_sock *newllc, *llc = llc_sk(sk);
 
@@ -759,7 +759,7 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb)
 	if (!sock_owned_by_user(sk))
 		llc_conn_rcv(sk, skb);
 	else {
-		dprintk("%s: adding to backlog...\n", __FUNCTION__);
+		dprintk("%s: adding to backlog...\n", __func__);
 		llc_set_backlog_type(skb, LLC_PACKET);
 		sk_add_backlog(sk, skb);
 	}
@@ -807,7 +807,7 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 		else
 			goto out_kfree_skb;
 	} else {
-		printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);
+		printk(KERN_ERR "%s: invalid skb in backlog\n", __func__);
 		goto out_kfree_skb;
 	}
 out:
@@ -874,7 +874,7 @@ struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct pr
 #ifdef LLC_REFCNT_DEBUG
 	atomic_inc(&llc_sock_nr);
 	printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
-		__FUNCTION__, atomic_read(&llc_sock_nr));
+		__func__, atomic_read(&llc_sock_nr));
 #endif
 out:
 	return sk;
@@ -894,7 +894,7 @@ void llc_sk_free(struct sock *sk)
 	/* Stop all (possibly) running timers */
 	llc_conn_ac_stop_all_timers(sk, NULL);
 #ifdef DEBUG_LLC_CONN_ALLOC
-	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
+	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__,
 		skb_queue_len(&llc->pdu_unack_q),
 		skb_queue_len(&sk->sk_write_queue));
 #endif
@@ -904,13 +904,13 @@ void llc_sk_free(struct sock *sk)
 #ifdef LLC_REFCNT_DEBUG
 	if (atomic_read(&sk->sk_refcnt) != 1) {
 		printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
-			sk, __FUNCTION__, atomic_read(&sk->sk_refcnt));
+			sk, __func__, atomic_read(&sk->sk_refcnt));
 		printk(KERN_DEBUG "%d LLC sockets are still alive\n",
 			atomic_read(&llc_sock_nr));
 	} else {
 		atomic_dec(&llc_sock_nr);
 		printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
-			__FUNCTION__, atomic_read(&llc_sock_nr));
+			__func__, atomic_read(&llc_sock_nr));
 	}
 #endif
 	sock_put(sk);
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index bfd2567dd365..1c45f172991e 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -150,7 +150,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 	int (*rcv)(struct sk_buff *, struct net_device *,
 		   struct packet_type *, struct net_device *);
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	/*
@@ -158,7 +158,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 	 * receives, do not try to analyse it.
 	 */
 	if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
-		dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__);
+		dprintk("%s: PACKET_OTHERHOST\n", __func__);
 		goto drop;
 	}
 	skb = skb_share_check(skb, GFP_ATOMIC);
@@ -171,7 +171,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
 	       goto handle_station;
 	sap = llc_sap_find(pdu->dsap);
 	if (unlikely(!sap)) {/* unknown SAP */
-		dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__,
+		dprintk("%s: llc_sap_find(%02X) failed!\n", __func__,
 			pdu->dsap);
 		goto drop;
 	}
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 45c7c0c3875e..520a5180a4f6 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -32,15 +32,6 @@ config MAC80211_RC_DEFAULT_PID
 	  default rate control algorithm. You should choose
 	  this unless you know what you are doing.
 
-config MAC80211_RC_DEFAULT_SIMPLE
-	bool "Simple rate control algorithm"
-	select MAC80211_RC_SIMPLE
-	---help---
-	  Select the simple rate control as the default rate
-	  control algorithm. Note that this is a non-responsive,
-	  dumb algorithm. You should choose the PID rate control
-	  instead.
-
 config MAC80211_RC_DEFAULT_NONE
 	bool "No default algorithm"
 	depends on EMBEDDED
@@ -57,7 +48,6 @@ comment "build the algorithm into mac80211."
 config MAC80211_RC_DEFAULT
 	string
 	default "pid" if MAC80211_RC_DEFAULT_PID
-	default "simple" if MAC80211_RC_DEFAULT_SIMPLE
 	default ""
 
 config MAC80211_RC_PID
@@ -70,16 +60,16 @@ config MAC80211_RC_PID
 	  Say Y or M unless you're sure you want to use a
 	  different rate control algorithm.
 
-config MAC80211_RC_SIMPLE
-	tristate "Simple rate control algorithm (DEPRECATED)"
+endmenu
+
+config MAC80211_MESH
+	bool "Enable mac80211 mesh networking (pre-802.11s) support"
+	depends on MAC80211 && EXPERIMENTAL
 	---help---
-	  This option enables a very simple, non-responsive TX
-	  rate control algorithm. This algorithm is deprecated
-	  and will be removed from the kernel in the near future.
-	  It has been replaced by the PID algorithm.
+	 This options enables support of Draft 802.11s mesh networking.
+	 The implementation is based on Draft 1.08 of the Mesh Networking
+	 amendment. For more information visit http://o11s.org/.
 
-	  Say N unless you know what you are doing.
-endmenu
 
 config MAC80211_LEDS
 	bool "Enable LED triggers"
@@ -166,3 +156,10 @@ config MAC80211_VERBOSE_PS_DEBUG
 	---help---
 	  Say Y here to print out verbose powersave
 	  mode debug messages.
+
+config MAC80211_VERBOSE_MPL_DEBUG
+	bool "Verbose mesh peer link debugging"
+	depends on MAC80211_DEBUG && MAC80211_MESH
+	---help---
+	  Say Y here to print out verbose mesh peer link
+	  debug messages.
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 54f46bc80cfe..70f4b26c2d87 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -19,7 +19,6 @@ mac80211-y := \
 	ieee80211_iface.o \
 	ieee80211_rate.o \
 	michael.o \
-	regdomain.o \
 	tkip.o \
 	aes_ccm.o \
 	cfg.o \
@@ -37,11 +36,15 @@ mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
 	debugfs_netdev.o \
 	debugfs_key.o
 
+mac80211-$(CONFIG_MAC80211_MESH) += \
+	mesh.o \
+	mesh_pathtbl.o \
+	mesh_plink.o \
+	mesh_hwmp.o
+
 
 # Build rate control algorithm(s)
-CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE
 CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE
-mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o
 mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID))
 
 # Modular rate algorithms are assigned to mac80211-m - make separate modules
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 22c9619ba776..5f8db5cab65d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -15,6 +15,7 @@
 #include "ieee80211_i.h"
 #include "cfg.h"
 #include "ieee80211_rate.h"
+#include "mesh.h"
 
 static enum ieee80211_if_types
 nl80211_type_to_mac80211_type(enum nl80211_iftype type)
@@ -28,16 +29,24 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type)
 		return IEEE80211_IF_TYPE_STA;
 	case NL80211_IFTYPE_MONITOR:
 		return IEEE80211_IF_TYPE_MNTR;
+#ifdef CONFIG_MAC80211_MESH
+	case NL80211_IFTYPE_MESH_POINT:
+		return IEEE80211_IF_TYPE_MESH_POINT;
+#endif
 	default:
 		return IEEE80211_IF_TYPE_INVALID;
 	}
 }
 
 static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-			       enum nl80211_iftype type)
+			       enum nl80211_iftype type, u32 *flags,
+			       struct vif_params *params)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	enum ieee80211_if_types itype;
+	struct net_device *dev;
+	struct ieee80211_sub_if_data *sdata;
+	int err;
 
 	if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
 		return -ENODEV;
@@ -46,7 +55,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
 	if (itype == IEEE80211_IF_TYPE_INVALID)
 		return -EINVAL;
 
-	return ieee80211_if_add(local->mdev, name, NULL, itype);
+	err = ieee80211_if_add(local->mdev, name, &dev, itype, params);
+	if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags)
+		return err;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	sdata->u.mntr_flags = *flags;
+	return 0;
 }
 
 static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
@@ -69,7 +84,8 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
 }
 
 static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
-				  enum nl80211_iftype type)
+				  enum nl80211_iftype type, u32 *flags,
+				  struct vif_params *params)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
@@ -99,6 +115,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
 	ieee80211_if_reinit(dev);
 	ieee80211_if_set_type(dev, itype);
 
+	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
+		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+					     params->mesh_id_len,
+					     params->mesh_id);
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags)
+		return 0;
+
+	sdata->u.mntr_flags = *flags;
 	return 0;
 }
 
@@ -109,7 +134,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta = NULL;
 	enum ieee80211_key_alg alg;
-	int ret;
+	struct ieee80211_key *key;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -128,21 +153,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
 		return -EINVAL;
 	}
 
+	key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
+	if (!key)
+		return -ENOMEM;
+
 	if (mac_addr) {
 		sta = sta_info_get(sdata->local, mac_addr);
-		if (!sta)
+		if (!sta) {
+			ieee80211_key_free(key);
 			return -ENOENT;
+		}
 	}
 
-	ret = 0;
-	if (!ieee80211_key_alloc(sdata, sta, alg, key_idx,
-				 params->key_len, params->key))
-		ret = -ENOMEM;
-
-	if (sta)
-		sta_info_put(sta);
+	ieee80211_key_link(key, sdata, sta);
 
-	return ret;
+	return 0;
 }
 
 static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
@@ -160,12 +185,12 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 			return -ENOENT;
 
 		ret = 0;
-		if (sta->key)
+		if (sta->key) {
 			ieee80211_key_free(sta->key);
-		else
+			WARN_ON(sta->key);
+		} else
 			ret = -ENOENT;
 
-		sta_info_put(sta);
 		return ret;
 	}
 
@@ -173,6 +198,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
 		return -ENOENT;
 
 	ieee80211_key_free(sdata->keys[key_idx]);
+	WARN_ON(sdata->keys[key_idx]);
 
 	return 0;
 }
@@ -254,8 +280,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
 	err = 0;
 
  out:
-	if (sta)
-		sta_info_put(sta);
 	return err;
 }
 
@@ -271,29 +295,73 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
 	return 0;
 }
 
+static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
+{
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+	sinfo->filled = STATION_INFO_INACTIVE_TIME |
+			STATION_INFO_RX_BYTES |
+			STATION_INFO_TX_BYTES;
+
+	sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
+	sinfo->rx_bytes = sta->rx_bytes;
+	sinfo->tx_bytes = sta->tx_bytes;
+
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+#ifdef CONFIG_MAC80211_MESH
+		sinfo->filled |= STATION_INFO_LLID |
+				 STATION_INFO_PLID |
+				 STATION_INFO_PLINK_STATE;
+
+		sinfo->llid = le16_to_cpu(sta->llid);
+		sinfo->plid = le16_to_cpu(sta->plid);
+		sinfo->plink_state = sta->plink_state;
+#endif
+	}
+}
+
+
+static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev,
+				 int idx, u8 *mac, struct station_info *sinfo)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+	int ret = -ENOENT;
+
+	rcu_read_lock();
+
+	sta = sta_info_get_by_idx(local, idx, dev);
+	if (sta) {
+		ret = 0;
+		memcpy(mac, sta->addr, ETH_ALEN);
+		sta_set_sinfo(sta, sinfo);
+	}
+
+	rcu_read_unlock();
+
+	return ret;
+}
+
 static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
-				 u8 *mac, struct station_stats *stats)
+				 u8 *mac, struct station_info *sinfo)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
+	int ret = -ENOENT;
 
-	sta = sta_info_get(local, mac);
-	if (!sta)
-		return -ENOENT;
+	rcu_read_lock();
 
 	/* XXX: verify sta->dev == dev */
 
-	stats->filled = STATION_STAT_INACTIVE_TIME |
-			STATION_STAT_RX_BYTES |
-			STATION_STAT_TX_BYTES;
-
-	stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
-	stats->rx_bytes = sta->rx_bytes;
-	stats->tx_bytes = sta->tx_bytes;
+	sta = sta_info_get(local, mac);
+	if (sta) {
+		ret = 0;
+		sta_set_sinfo(sta, sinfo);
+	}
 
-	sta_info_put(sta);
+	rcu_read_unlock();
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -486,8 +554,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta)
 	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
 	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */
 
-	skb->dev = sta->dev;
-	skb->protocol = eth_type_trans(skb, sta->dev);
+	skb->dev = sta->sdata->dev;
+	skb->protocol = eth_type_trans(skb, sta->sdata->dev);
 	memset(skb->cb, 0, sizeof(skb->cb));
 	netif_rx(skb);
 }
@@ -498,7 +566,14 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 {
 	u32 rates;
 	int i, j;
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+	/*
+	 * FIXME: updating the flags is racy when this function is
+	 *	  called from ieee80211_change_station(), this will
+	 *	  be resolved in a future patch.
+	 */
 
 	if (params->station_flags & STATION_FLAG_CHANGED) {
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
@@ -514,6 +589,13 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 			sta->flags |= WLAN_STA_WME;
 	}
 
+	/*
+	 * FIXME: updating the following information is racy when this
+	 *	  function is called from ieee80211_change_station().
+	 *	  However, all this information should be static so
+	 *	  maybe we should just reject attemps to change it.
+	 */
+
 	if (params->aid) {
 		sta->aid = params->aid;
 		if (sta->aid > IEEE80211_MAX_AID)
@@ -525,15 +607,27 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 
 	if (params->supported_rates) {
 		rates = 0;
-		mode = local->oper_hw_mode;
+		sband = local->hw.wiphy->bands[local->oper_channel->band];
+
 		for (i = 0; i < params->supported_rates_len; i++) {
 			int rate = (params->supported_rates[i] & 0x7f) * 5;
-			for (j = 0; j < mode->num_rates; j++) {
-				if (mode->rates[j].rate == rate)
+			for (j = 0; j < sband->n_bitrates; j++) {
+				if (sband->bitrates[j].bitrate == rate)
 					rates |= BIT(j);
 			}
 		}
-		sta->supp_rates = rates;
+		sta->supp_rates[local->oper_channel->band] = rates;
+	}
+
+	if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
+		switch (params->plink_action) {
+		case PLINK_ACTION_OPEN:
+			mesh_plink_open(sta);
+			break;
+		case PLINK_ACTION_BLOCK:
+			mesh_plink_block(sta);
+			break;
+		}
 	}
 }
 
@@ -543,18 +637,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
+	int err;
 
 	/* Prevent a race with changing the rate control algorithm */
 	if (!netif_running(dev))
 		return -ENETDOWN;
 
-	/* XXX: get sta belonging to dev */
-	sta = sta_info_get(local, mac);
-	if (sta) {
-		sta_info_put(sta);
-		return -EEXIST;
-	}
-
 	if (params->vlan) {
 		sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
@@ -564,22 +652,36 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 	} else
 		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-	sta = sta_info_add(local, dev, mac, GFP_KERNEL);
+	if (compare_ether_addr(mac, dev->dev_addr) == 0)
+		return -EINVAL;
+
+	if (is_multicast_ether_addr(mac))
+		return -EINVAL;
+
+	sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
 	if (!sta)
 		return -ENOMEM;
 
-	sta->dev = sdata->dev;
-	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
-	    sdata->vif.type == IEEE80211_IF_TYPE_AP)
-		ieee80211_send_layer2_update(sta);
-
 	sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
 
 	sta_apply_parameters(local, sta, params);
 
 	rate_control_rate_init(sta, local);
 
-	sta_info_put(sta);
+	rcu_read_lock();
+
+	err = sta_info_insert(sta);
+	if (err) {
+		/* STA has been freed */
+		rcu_read_unlock();
+		return err;
+	}
+
+	if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN ||
+	    sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		ieee80211_send_layer2_update(sta);
+
+	rcu_read_unlock();
 
 	return 0;
 }
@@ -587,7 +689,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
 				 u8 *mac)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 
 	if (mac) {
@@ -596,10 +699,10 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev,
 		if (!sta)
 			return -ENOENT;
 
-		sta_info_free(sta);
-		sta_info_put(sta);
+		sta_info_unlink(&sta);
+		sta_info_destroy(sta);
 	} else
-		sta_info_flush(local, dev);
+		sta_info_flush(local, sdata);
 
 	return 0;
 }
@@ -618,23 +721,190 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 	if (!sta)
 		return -ENOENT;
 
-	if (params->vlan && params->vlan != sta->dev) {
+	if (params->vlan && params->vlan != sta->sdata->dev) {
 		vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 
 		if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN ||
 		    vlansdata->vif.type != IEEE80211_IF_TYPE_AP)
 			return -EINVAL;
 
-		sta->dev = params->vlan;
+		sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan);
 		ieee80211_send_layer2_update(sta);
 	}
 
 	sta_apply_parameters(local, sta, params);
 
-	sta_info_put(sta);
+	return 0;
+}
+
+#ifdef CONFIG_MAC80211_MESH
+static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev,
+				 u8 *dst, u8 *next_hop)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+	struct sta_info *sta;
+	int err;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+		return -ENOTSUPP;
+
+	rcu_read_lock();
+	sta = sta_info_get(local, next_hop);
+	if (!sta) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	err = mesh_path_add(dst, dev);
+	if (err) {
+		rcu_read_unlock();
+		return err;
+	}
+
+	mpath = mesh_path_lookup(dst, dev);
+	if (!mpath) {
+		rcu_read_unlock();
+		return -ENXIO;
+	}
+	mesh_path_fix_nexthop(mpath, sta);
+
+	rcu_read_unlock();
+	return 0;
+}
+
+static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
+				 u8 *dst)
+{
+	if (dst)
+		return mesh_path_del(dst, dev);
+
+	mesh_path_flush(dev);
+	return 0;
+}
+
+static int ieee80211_change_mpath(struct wiphy *wiphy,
+				    struct net_device *dev,
+				    u8 *dst, u8 *next_hop)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+	struct sta_info *sta;
+
+	if (!netif_running(dev))
+		return -ENETDOWN;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+		return -ENOTSUPP;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, next_hop);
+	if (!sta) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
 
+	mpath = mesh_path_lookup(dst, dev);
+	if (!mpath) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	mesh_path_fix_nexthop(mpath, sta);
+
+	rcu_read_unlock();
+	return 0;
+}
+
+static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
+			    struct mpath_info *pinfo)
+{
+	if (mpath->next_hop)
+		memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+	else
+		memset(next_hop, 0, ETH_ALEN);
+
+	pinfo->filled = MPATH_INFO_FRAME_QLEN |
+			MPATH_INFO_DSN |
+			MPATH_INFO_METRIC |
+			MPATH_INFO_EXPTIME |
+			MPATH_INFO_DISCOVERY_TIMEOUT |
+			MPATH_INFO_DISCOVERY_RETRIES |
+			MPATH_INFO_FLAGS;
+
+	pinfo->frame_qlen = mpath->frame_queue.qlen;
+	pinfo->dsn = mpath->dsn;
+	pinfo->metric = mpath->metric;
+	if (time_before(jiffies, mpath->exp_time))
+		pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies);
+	pinfo->discovery_timeout =
+			jiffies_to_msecs(mpath->discovery_timeout);
+	pinfo->discovery_retries = mpath->discovery_retries;
+	pinfo->flags = 0;
+	if (mpath->flags & MESH_PATH_ACTIVE)
+		pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE;
+	if (mpath->flags & MESH_PATH_RESOLVING)
+		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+	if (mpath->flags & MESH_PATH_DSN_VALID)
+		pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID;
+	if (mpath->flags & MESH_PATH_FIXED)
+		pinfo->flags |= NL80211_MPATH_FLAG_FIXED;
+	if (mpath->flags & MESH_PATH_RESOLVING)
+		pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING;
+
+	pinfo->flags = mpath->flags;
+}
+
+static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev,
+			       u8 *dst, u8 *next_hop, struct mpath_info *pinfo)
+
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+		return -ENOTSUPP;
+
+	rcu_read_lock();
+	mpath = mesh_path_lookup(dst, dev);
+	if (!mpath) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+	memcpy(dst, mpath->dst, ETH_ALEN);
+	mpath_set_pinfo(mpath, next_hop, pinfo);
+	rcu_read_unlock();
+	return 0;
+}
+
+static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev,
+				 int idx, u8 *dst, u8 *next_hop,
+				 struct mpath_info *pinfo)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)
+		return -ENOTSUPP;
+
+	rcu_read_lock();
+	mpath = mesh_path_lookup_by_idx(idx, dev);
+	if (!mpath) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+	memcpy(dst, mpath->dst, ETH_ALEN);
+	mpath_set_pinfo(mpath, next_hop, pinfo);
+	rcu_read_unlock();
 	return 0;
 }
+#endif
 
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
@@ -651,4 +921,12 @@ struct cfg80211_ops mac80211_config_ops = {
 	.del_station = ieee80211_del_station,
 	.change_station = ieee80211_change_station,
 	.get_station = ieee80211_get_station,
+	.dump_station = ieee80211_dump_station,
+#ifdef CONFIG_MAC80211_MESH
+	.add_mpath = ieee80211_add_mpath,
+	.del_mpath = ieee80211_del_mpath,
+	.change_mpath = ieee80211_change_mpath,
+	.get_mpath = ieee80211_get_mpath,
+	.dump_mpath = ieee80211_dump_mpath,
+#endif
 };
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 60514b2c97b9..4736c64937b4 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file)
 	return 0;
 }
 
-static const char *ieee80211_mode_str(int mode)
-{
-	switch (mode) {
-	case MODE_IEEE80211A:
-		return "IEEE 802.11a";
-	case MODE_IEEE80211B:
-		return "IEEE 802.11b";
-	case MODE_IEEE80211G:
-		return "IEEE 802.11g";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-static ssize_t modes_read(struct file *file, char __user *userbuf,
-			  size_t count, loff_t *ppos)
-{
-	struct ieee80211_local *local = file->private_data;
-	struct ieee80211_hw_mode *mode;
-	char buf[150], *p = buf;
-
-	/* FIXME: locking! */
-	list_for_each_entry(mode, &local->modes_list, list) {
-		p += scnprintf(p, sizeof(buf)+buf-p,
-			       "%s\n", ieee80211_mode_str(mode->mode));
-	}
-
-	return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
-}
-
-static const struct file_operations modes_ops = {
-	.read = modes_read,
-	.open = mac80211_open_file_generic,
-};
-
 #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...)		\
 static ssize_t name## _read(struct file *file, char __user *userbuf,	\
 			    size_t count, loff_t *ppos)			\
@@ -80,10 +45,8 @@ static const struct file_operations name## _ops = {			\
 	local->debugfs.name = NULL;
 
 
-DEBUGFS_READONLY_FILE(channel, 20, "%d",
-		      local->hw.conf.channel);
 DEBUGFS_READONLY_FILE(frequency, 20, "%d",
-		      local->hw.conf.freq);
+		      local->hw.conf.channel->center_freq);
 DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
 		      local->hw.conf.antenna_sel_tx);
 DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
@@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
 		      local->long_retry_limit);
 DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
 		      local->total_ps_buffered);
-DEBUGFS_READONLY_FILE(mode, 20, "%s",
-		      ieee80211_mode_str(local->hw.conf.phymode));
 DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
 		      local->wep_iv & 0xffffff);
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
@@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	local->debugfs.stations = debugfs_create_dir("stations", phyd);
 	local->debugfs.keys = debugfs_create_dir("keys", phyd);
 
-	DEBUGFS_ADD(channel);
 	DEBUGFS_ADD(frequency);
 	DEBUGFS_ADD(antenna_sel_tx);
 	DEBUGFS_ADD(antenna_sel_rx);
@@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
 	DEBUGFS_ADD(short_retry_limit);
 	DEBUGFS_ADD(long_retry_limit);
 	DEBUGFS_ADD(total_ps_buffered);
-	DEBUGFS_ADD(mode);
 	DEBUGFS_ADD(wep_iv);
-	DEBUGFS_ADD(modes);
 
 	statsd = debugfs_create_dir("statistics", phyd);
 	local->debugfs.statistics = statsd;
@@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
 
 void debugfs_hw_del(struct ieee80211_local *local)
 {
-	DEBUGFS_DEL(channel);
 	DEBUGFS_DEL(frequency);
 	DEBUGFS_DEL(antenna_sel_tx);
 	DEBUGFS_DEL(antenna_sel_rx);
@@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
 	DEBUGFS_DEL(short_retry_limit);
 	DEBUGFS_DEL(long_retry_limit);
 	DEBUGFS_DEL(total_ps_buffered);
-	DEBUGFS_DEL(mode);
 	DEBUGFS_DEL(wep_iv);
-	DEBUGFS_DEL(modes);
 
 	DEBUGFS_STATS_DEL(transmitted_fragment_count);
 	DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 829872a3ae81..3e19d42e61cb 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -31,14 +31,39 @@ static ssize_t ieee80211_if_read(
 	ssize_t ret = -EINVAL;
 
 	read_lock(&dev_base_lock);
-	if (sdata->dev->reg_state == NETREG_REGISTERED) {
+	if (sdata->dev->reg_state == NETREG_REGISTERED)
 		ret = (*format)(sdata, buf, sizeof(buf));
-		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
-	}
 	read_unlock(&dev_base_lock);
+
+	if (ret != -EINVAL)
+		ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+
 	return ret;
 }
 
+#ifdef CONFIG_MAC80211_MESH
+static ssize_t ieee80211_if_write(
+	struct ieee80211_sub_if_data *sdata,
+	char const __user *userbuf,
+	size_t count, loff_t *ppos,
+	int (*format)(struct ieee80211_sub_if_data *, char *))
+{
+	char buf[10];
+	int buf_size;
+
+	memset(buf, 0x00, sizeof(buf));
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, userbuf, buf_size))
+		return count;
+	read_lock(&dev_base_lock);
+	if (sdata->dev->reg_state == NETREG_REGISTERED)
+		(*format)(sdata, buf);
+	read_unlock(&dev_base_lock);
+
+	return count;
+}
+#endif
+
 #define IEEE80211_IF_FMT(name, field, format_string)			\
 static ssize_t ieee80211_if_fmt_##name(					\
 	const struct ieee80211_sub_if_data *sdata, char *buf,		\
@@ -46,6 +71,19 @@ static ssize_t ieee80211_if_fmt_##name(					\
 {									\
 	return scnprintf(buf, buflen, format_string, sdata->field);	\
 }
+#define IEEE80211_IF_WFMT(name, field, type)				\
+static int ieee80211_if_wfmt_##name(					\
+	struct ieee80211_sub_if_data *sdata, char *buf)			\
+{									\
+	unsigned long tmp;						\
+	char *endp;							\
+									\
+	tmp = simple_strtoul(buf, &endp, 0);				\
+	if ((endp == buf) || ((type)tmp != tmp))			\
+		return -EINVAL;						\
+	sdata->field = tmp;						\
+	return 0;							\
+}
 #define IEEE80211_IF_FMT_DEC(name, field)				\
 		IEEE80211_IF_FMT(name, field, "%d\n")
 #define IEEE80211_IF_FMT_HEX(name, field)				\
@@ -88,10 +126,37 @@ static const struct file_operations name##_ops = {			\
 		IEEE80211_IF_FMT_##format(name, field)			\
 		__IEEE80211_IF_FILE(name)
 
+#define __IEEE80211_IF_WFILE(name)					\
+static ssize_t ieee80211_if_read_##name(struct file *file,		\
+					char __user *userbuf,		\
+					size_t count, loff_t *ppos)	\
+{									\
+	return ieee80211_if_read(file->private_data,			\
+				 userbuf, count, ppos,			\
+				 ieee80211_if_fmt_##name);		\
+}									\
+static ssize_t ieee80211_if_write_##name(struct file *file,		\
+					const char __user *userbuf,	\
+					size_t count, loff_t *ppos)	\
+{									\
+	return ieee80211_if_write(file->private_data,			\
+				 userbuf, count, ppos,			\
+				 ieee80211_if_wfmt_##name);		\
+}									\
+static const struct file_operations name##_ops = {			\
+	.read = ieee80211_if_read_##name,				\
+	.write = ieee80211_if_write_##name,				\
+	.open = mac80211_open_file_generic,				\
+}
+
+#define IEEE80211_IF_WFILE(name, field, format, type)			\
+		IEEE80211_IF_FMT_##format(name, field)			\
+		IEEE80211_IF_WFMT(name, field, type)			\
+		__IEEE80211_IF_WFILE(name)
+
 /* common attributes */
 IEEE80211_IF_FILE(channel_use, channel_use, DEC);
 IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
-IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC);
 
 /* STA/IBSS attributes */
 IEEE80211_IF_FILE(state, u.sta.state, DEC);
@@ -107,6 +172,7 @@ IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
 IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
 IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
 IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC);
 
 static ssize_t ieee80211_if_fmt_flags(
 	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
@@ -140,6 +206,42 @@ __IEEE80211_IF_FILE(num_buffered_multicast);
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
+#ifdef CONFIG_MAC80211_MESH
+/* Mesh stats attributes */
+IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC);
+IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC);
+IEEE80211_IF_FILE(dropped_frames_no_route,
+		u.sta.mshstats.dropped_frames_no_route, DEC);
+IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC);
+
+/* Mesh parameters */
+IEEE80211_IF_WFILE(dot11MeshMaxRetries,
+		u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8);
+IEEE80211_IF_WFILE(dot11MeshRetryTimeout,
+		u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshConfirmTimeout,
+		u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHoldingTimeout,
+		u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8);
+IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, u8);
+IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks,
+		u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout,
+		u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32);
+IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval,
+		u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime,
+		u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16);
+IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries,
+		u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8);
+IEEE80211_IF_WFILE(path_refresh_time,
+		u.sta.mshcfg.path_refresh_time, DEC, u32);
+IEEE80211_IF_WFILE(min_discovery_timeout,
+		u.sta.mshcfg.min_discovery_timeout, DEC, u16);
+#endif
+
+
 #define DEBUGFS_ADD(name, type)\
 	sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
 		sdata->debugfsdir, sdata, &name##_ops);
@@ -148,7 +250,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, sta);
 	DEBUGFS_ADD(drop_unencrypted, sta);
-	DEBUGFS_ADD(ieee802_1x_pac, sta);
 	DEBUGFS_ADD(state, sta);
 	DEBUGFS_ADD(bssid, sta);
 	DEBUGFS_ADD(prev_bssid, sta);
@@ -163,13 +264,13 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_ADD(auth_alg, sta);
 	DEBUGFS_ADD(auth_transaction, sta);
 	DEBUGFS_ADD(flags, sta);
+	DEBUGFS_ADD(num_beacons_sta, sta);
 }
 
 static void add_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, ap);
 	DEBUGFS_ADD(drop_unencrypted, ap);
-	DEBUGFS_ADD(ieee802_1x_pac, ap);
 	DEBUGFS_ADD(num_sta_ps, ap);
 	DEBUGFS_ADD(dtim_count, ap);
 	DEBUGFS_ADD(num_beacons, ap);
@@ -182,7 +283,6 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, wds);
 	DEBUGFS_ADD(drop_unencrypted, wds);
-	DEBUGFS_ADD(ieee802_1x_pac, wds);
 	DEBUGFS_ADD(peer, wds);
 }
 
@@ -190,19 +290,63 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_ADD(channel_use, vlan);
 	DEBUGFS_ADD(drop_unencrypted, vlan);
-	DEBUGFS_ADD(ieee802_1x_pac, vlan);
 }
 
 static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
 }
 
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_ADD(name)\
+	sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\
+		sdata->mesh_stats_dir, sdata, &name##_ops);
+
+static void add_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+	sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats",
+				sdata->debugfsdir);
+	MESHSTATS_ADD(fwded_frames);
+	MESHSTATS_ADD(dropped_frames_ttl);
+	MESHSTATS_ADD(dropped_frames_no_route);
+	MESHSTATS_ADD(estab_plinks);
+}
+
+#define MESHPARAMS_ADD(name)\
+	sdata->mesh_config.name = debugfs_create_file(#name, 0644,\
+		sdata->mesh_config_dir, sdata, &name##_ops);
+
+static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+	sdata->mesh_config_dir = debugfs_create_dir("mesh_config",
+				sdata->debugfsdir);
+	MESHPARAMS_ADD(dot11MeshMaxRetries);
+	MESHPARAMS_ADD(dot11MeshRetryTimeout);
+	MESHPARAMS_ADD(dot11MeshConfirmTimeout);
+	MESHPARAMS_ADD(dot11MeshHoldingTimeout);
+	MESHPARAMS_ADD(dot11MeshTTL);
+	MESHPARAMS_ADD(auto_open_plinks);
+	MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
+	MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
+	MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval);
+	MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime);
+	MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries);
+	MESHPARAMS_ADD(path_refresh_time);
+	MESHPARAMS_ADD(min_discovery_timeout);
+}
+#endif
+
 static void add_files(struct ieee80211_sub_if_data *sdata)
 {
 	if (!sdata->debugfsdir)
 		return;
 
 	switch (sdata->vif.type) {
+	case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+		add_mesh_stats(sdata);
+		add_mesh_config(sdata);
+#endif
+		/* fall through */
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		add_sta_files(sdata);
@@ -234,7 +378,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, sta);
 	DEBUGFS_DEL(drop_unencrypted, sta);
-	DEBUGFS_DEL(ieee802_1x_pac, sta);
 	DEBUGFS_DEL(state, sta);
 	DEBUGFS_DEL(bssid, sta);
 	DEBUGFS_DEL(prev_bssid, sta);
@@ -249,13 +392,13 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
 	DEBUGFS_DEL(auth_alg, sta);
 	DEBUGFS_DEL(auth_transaction, sta);
 	DEBUGFS_DEL(flags, sta);
+	DEBUGFS_DEL(num_beacons_sta, sta);
 }
 
 static void del_ap_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, ap);
 	DEBUGFS_DEL(drop_unencrypted, ap);
-	DEBUGFS_DEL(ieee802_1x_pac, ap);
 	DEBUGFS_DEL(num_sta_ps, ap);
 	DEBUGFS_DEL(dtim_count, ap);
 	DEBUGFS_DEL(num_beacons, ap);
@@ -268,7 +411,6 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, wds);
 	DEBUGFS_DEL(drop_unencrypted, wds);
-	DEBUGFS_DEL(ieee802_1x_pac, wds);
 	DEBUGFS_DEL(peer, wds);
 }
 
@@ -276,19 +418,67 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
 {
 	DEBUGFS_DEL(channel_use, vlan);
 	DEBUGFS_DEL(drop_unencrypted, vlan);
-	DEBUGFS_DEL(ieee802_1x_pac, vlan);
 }
 
 static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
 {
 }
 
+#ifdef CONFIG_MAC80211_MESH
+#define MESHSTATS_DEL(name)			\
+	do {						\
+		debugfs_remove(sdata->mesh_stats.name);	\
+		sdata->mesh_stats.name = NULL;		\
+	} while (0)
+
+static void del_mesh_stats(struct ieee80211_sub_if_data *sdata)
+{
+	MESHSTATS_DEL(fwded_frames);
+	MESHSTATS_DEL(dropped_frames_ttl);
+	MESHSTATS_DEL(dropped_frames_no_route);
+	MESHSTATS_DEL(estab_plinks);
+	debugfs_remove(sdata->mesh_stats_dir);
+	sdata->mesh_stats_dir = NULL;
+}
+
+#define MESHPARAMS_DEL(name)			\
+	do {						\
+		debugfs_remove(sdata->mesh_config.name);	\
+		sdata->mesh_config.name = NULL;		\
+	} while (0)
+
+static void del_mesh_config(struct ieee80211_sub_if_data *sdata)
+{
+	MESHPARAMS_DEL(dot11MeshMaxRetries);
+	MESHPARAMS_DEL(dot11MeshRetryTimeout);
+	MESHPARAMS_DEL(dot11MeshConfirmTimeout);
+	MESHPARAMS_DEL(dot11MeshHoldingTimeout);
+	MESHPARAMS_DEL(dot11MeshTTL);
+	MESHPARAMS_DEL(auto_open_plinks);
+	MESHPARAMS_DEL(dot11MeshMaxPeerLinks);
+	MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout);
+	MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval);
+	MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime);
+	MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries);
+	MESHPARAMS_DEL(path_refresh_time);
+	MESHPARAMS_DEL(min_discovery_timeout);
+	debugfs_remove(sdata->mesh_config_dir);
+	sdata->mesh_config_dir = NULL;
+}
+#endif
+
 static void del_files(struct ieee80211_sub_if_data *sdata, int type)
 {
 	if (!sdata->debugfsdir)
 		return;
 
 	switch (type) {
+	case IEEE80211_IF_TYPE_MESH_POINT:
+#ifdef CONFIG_MAC80211_MESH
+		del_mesh_stats(sdata);
+		del_mesh_config(sdata);
+#endif
+		/* fall through */
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		del_sta_files(sdata);
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index 8f5944c53d4e..256ea880d28b 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -33,25 +33,16 @@ static ssize_t sta_ ##name## _read(struct file *file,			\
 #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
 #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
 
-#define STA_READ_RATE(name, field)					\
-static ssize_t sta_##name##_read(struct file *file,			\
-				 char __user *userbuf,			\
-				 size_t count, loff_t *ppos)		\
-{									\
-	struct sta_info *sta = file->private_data;			\
-	struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
-	struct ieee80211_hw_mode *mode = local->oper_hw_mode;		\
-	char buf[20];							\
-	int res = scnprintf(buf, sizeof(buf), "%d\n",			\
-			    (sta->field >= 0 &&				\
-			    sta->field < mode->num_rates) ?		\
-			    mode->rates[sta->field].rate : -1);		\
-	return simple_read_from_buffer(userbuf, count, ppos, buf, res);	\
+#define STA_OPS(name)							\
+static const struct file_operations sta_ ##name## _ops = {		\
+	.read = sta_##name##_read,					\
+	.open = mac80211_open_file_generic,				\
 }
 
-#define STA_OPS(name)							\
+#define STA_OPS_WR(name)						\
 static const struct file_operations sta_ ##name## _ops = {		\
 	.read = sta_##name##_read,					\
+	.write = sta_##name##_write,					\
 	.open = mac80211_open_file_generic,				\
 }
 
@@ -60,7 +51,7 @@ static const struct file_operations sta_ ##name## _ops = {		\
 		STA_OPS(name)
 
 STA_FILE(aid, aid, D);
-STA_FILE(dev, dev->name, S);
+STA_FILE(dev, sdata->dev->name, S);
 STA_FILE(rx_packets, rx_packets, LU);
 STA_FILE(tx_packets, tx_packets, LU);
 STA_FILE(rx_bytes, rx_bytes, LU);
@@ -70,27 +61,23 @@ STA_FILE(rx_fragments, rx_fragments, LU);
 STA_FILE(rx_dropped, rx_dropped, LU);
 STA_FILE(tx_fragments, tx_fragments, LU);
 STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(txrate, txrate, RATE);
-STA_FILE(last_txrate, last_txrate, RATE);
 STA_FILE(tx_retry_failed, tx_retry_failed, LU);
 STA_FILE(tx_retry_count, tx_retry_count, LU);
 STA_FILE(last_rssi, last_rssi, D);
 STA_FILE(last_signal, last_signal, D);
 STA_FILE(last_noise, last_noise, D);
 STA_FILE(channel_use, channel_use, D);
-STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D);
+STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
 
 static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
 			      size_t count, loff_t *ppos)
 {
 	char buf[100];
 	struct sta_info *sta = file->private_data;
-	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+	int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
 		sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
 		sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
 		sta->flags & WLAN_STA_PS ? "PS\n" : "",
-		sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
-		sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
 		sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
 		sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
 		sta->flags & WLAN_STA_WME ? "WME\n" : "",
@@ -111,31 +98,6 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file,
 }
 STA_OPS(num_ps_buf_frames);
 
-static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf,
-				      size_t count, loff_t *ppos)
-{
-	char buf[100];
-	struct sta_info *sta = file->private_data;
-	int res = scnprintf(buf, sizeof(buf), "%d %d %d\n",
-			    sta->last_ack_rssi[0],
-			    sta->last_ack_rssi[1],
-			    sta->last_ack_rssi[2]);
-	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-STA_OPS(last_ack_rssi);
-
-static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf,
-				    size_t count, loff_t *ppos)
-{
-	char buf[20];
-	struct sta_info *sta = file->private_data;
-	int res = scnprintf(buf, sizeof(buf), "%d\n",
-			    sta->last_ack ?
-			    jiffies_to_msecs(jiffies - sta->last_ack) : -1);
-	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
-}
-STA_OPS(last_ack_ms);
-
 static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
 				    size_t count, loff_t *ppos)
 {
@@ -191,6 +153,118 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
 STA_OPS(wme_tx_queue);
 #endif
 
+static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
+					size_t count, loff_t *ppos)
+{
+	char buf[768], *p = buf;
+	int i;
+	struct sta_info *sta = file->private_data;
+	p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n");
+	p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n "
+			"TIDs info is: \n TID :",
+			(sta->ampdu_mlme.dialog_token_allocator + 1));
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n RX  :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_state_rx[i]);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_state_rx[i]?
+			sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n TX  :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_state_tx[i]);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_state_tx[i]?
+			sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :");
+	for (i = 0; i < STA_TID_NUM; i++)
+		p += scnprintf(p, sizeof(buf)+buf-p, "%5d",
+			sta->ampdu_mlme.tid_state_tx[i]?
+			sta->ampdu_mlme.tid_tx[i]->ssn : 0);
+
+	p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t sta_agg_status_write(struct file *file,
+		const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct sta_info *sta = file->private_data;
+	struct net_device *dev = sta->sdata->dev;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	u8 *da = sta->addr;
+	static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0,
+					0, 0, 0, 0, 0, 0, 0, 0};
+	static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1,
+					1, 1, 1, 1, 1, 1, 1, 1};
+	char *endp;
+	char buf[32];
+	int buf_size, rs;
+	unsigned int tid_num;
+	char state[4];
+
+	memset(buf, 0x00, sizeof(buf));
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	tid_num = simple_strtoul(buf, &endp, 0);
+	if (endp == buf)
+		return -EINVAL;
+
+	if ((tid_num >= 100) && (tid_num <= 115)) {
+		/* toggle Rx aggregation command */
+		tid_num = tid_num - 100;
+		if (tid_static_rx[tid_num] == 1) {
+			strcpy(state, "off ");
+			ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0,
+					WLAN_REASON_QSTA_REQUIRE_SETUP);
+			sta->ampdu_mlme.tid_state_rx[tid_num] |=
+					HT_AGG_STATE_DEBUGFS_CTL;
+			tid_static_rx[tid_num] = 0;
+		} else {
+			strcpy(state, "on ");
+			sta->ampdu_mlme.tid_state_rx[tid_num] &=
+					~HT_AGG_STATE_DEBUGFS_CTL;
+			tid_static_rx[tid_num] = 1;
+		}
+		printk(KERN_DEBUG "debugfs - try switching tid %u %s\n",
+				tid_num, state);
+	} else if ((tid_num >= 0) && (tid_num <= 15)) {
+		/* toggle Tx aggregation command */
+		if (tid_static_tx[tid_num] == 0) {
+			strcpy(state, "on ");
+			rs =  ieee80211_start_tx_ba_session(hw, da, tid_num);
+			if (rs == 0)
+				tid_static_tx[tid_num] = 1;
+		} else {
+			strcpy(state, "off");
+			rs =  ieee80211_stop_tx_ba_session(hw, da, tid_num, 1);
+			if (rs == 0)
+				tid_static_tx[tid_num] = 0;
+		}
+		printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n",
+				tid_num, state, rs);
+	}
+
+	return count;
+}
+STA_OPS_WR(agg_status);
+
 #define DEBUGFS_ADD(name) \
 	sta->debugfs.name = debugfs_create_file(#name, 0444, \
 		sta->debugfs.dir, sta, &sta_ ##name## _ops);
@@ -203,12 +277,13 @@ STA_OPS(wme_tx_queue);
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
 	struct dentry *stations_dir = sta->local->debugfs.stations;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mbuf);
+	u8 *mac;
 
 	if (!stations_dir)
 		return;
 
-	print_mac(mac, sta->addr);
+	mac = print_mac(mbuf, sta->addr);
 
 	sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
 	if (!sta->debugfs.dir)
@@ -216,28 +291,26 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
 
 	DEBUGFS_ADD(flags);
 	DEBUGFS_ADD(num_ps_buf_frames);
-	DEBUGFS_ADD(last_ack_rssi);
-	DEBUGFS_ADD(last_ack_ms);
 	DEBUGFS_ADD(inactive_ms);
 	DEBUGFS_ADD(last_seq_ctrl);
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	DEBUGFS_ADD(wme_rx_queue);
 	DEBUGFS_ADD(wme_tx_queue);
 #endif
+	DEBUGFS_ADD(agg_status);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
 {
 	DEBUGFS_DEL(flags);
 	DEBUGFS_DEL(num_ps_buf_frames);
-	DEBUGFS_DEL(last_ack_rssi);
-	DEBUGFS_DEL(last_ack_ms);
 	DEBUGFS_DEL(inactive_ms);
 	DEBUGFS_DEL(last_seq_ctrl);
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	DEBUGFS_DEL(wme_rx_queue);
 	DEBUGFS_DEL(wme_tx_queue);
 #endif
+	DEBUGFS_DEL(agg_status);
 
 	debugfs_remove(sta->debugfs.dir);
 	sta->debugfs.dir = NULL;
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h
index 574a1cd54b96..8b608903259f 100644
--- a/net/mac80211/debugfs_sta.h
+++ b/net/mac80211/debugfs_sta.h
@@ -1,6 +1,8 @@
 #ifndef __MAC80211_DEBUGFS_STA_H
 #define __MAC80211_DEBUGFS_STA_H
 
+#include "sta_info.h"
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 void ieee80211_sta_debugfs_add(struct sta_info *sta);
 void ieee80211_sta_debugfs_remove(struct sta_info *sta);
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 8e586390a2ef..aaa5480e204a 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -26,6 +26,7 @@
 
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
+#include "mesh.h"
 #include "wep.h"
 #include "wme.h"
 #include "aes_ccm.h"
@@ -67,9 +68,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local)
 		new_flags |= FIF_ALLMULTI;
 
 	if (local->monitors)
-		new_flags |= FIF_CONTROL |
-			     FIF_OTHER_BSS |
-			     FIF_BCN_PRBRESP_PROMISC;
+		new_flags |= FIF_BCN_PRBRESP_PROMISC;
+
+	if (local->fif_fcsfail)
+		new_flags |= FIF_FCSFAIL;
+
+	if (local->fif_plcpfail)
+		new_flags |= FIF_PLCPFAIL;
+
+	if (local->fif_control)
+		new_flags |= FIF_CONTROL;
+
+	if (local->fif_other_bss)
+		new_flags |= FIF_OTHER_BSS;
 
 	changed_flags = local->filter_flags ^ new_flags;
 
@@ -128,9 +139,15 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev)
 
 static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
+	int meshhdrlen;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0;
+
 	/* FIX: what would be proper limits for MTU?
 	 * This interface uses 802.3 frames. */
-	if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+	if (new_mtu < 256 ||
+		new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
 		printk(KERN_WARNING "%s: invalid MTU %d\n",
 		       dev->name, new_mtu);
 		return -EINVAL;
@@ -166,6 +183,7 @@ static int ieee80211_open(struct net_device *dev)
 	struct ieee80211_if_init_conf conf;
 	int res;
 	bool need_hw_reconfig = 0;
+	struct sta_info *sta;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -173,8 +191,52 @@ static int ieee80211_open(struct net_device *dev)
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		struct net_device *ndev = nsdata->dev;
 
-		if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
-		    compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) {
+		if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+			/*
+			 * Allow only a single IBSS interface to be up at any
+			 * time. This is restricted because beacon distribution
+			 * cannot work properly if both are in the same IBSS.
+			 *
+			 * To remove this restriction we'd have to disallow them
+			 * from setting the same SSID on different IBSS interfaces
+			 * belonging to the same hardware. Then, however, we're
+			 * faced with having to adopt two different TSF timers...
+			 */
+			if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
+			    nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)
+				return -EBUSY;
+
+			/*
+			 * Disallow multiple IBSS/STA mode interfaces.
+			 *
+			 * This is a technical restriction, it is possible although
+			 * most likely not IEEE 802.11 compliant to have multiple
+			 * STAs with just a single hardware (the TSF timer will not
+			 * be adjusted properly.)
+			 *
+			 * However, because mac80211 uses the master device's BSS
+			 * information for each STA/IBSS interface, doing this will
+			 * currently corrupt that BSS information completely, unless,
+			 * a not very useful case, both STAs are associated to the
+			 * same BSS.
+			 *
+			 * To remove this restriction, the BSS information needs to
+			 * be embedded in the STA/IBSS mode sdata instead of using
+			 * the master device's BSS structure.
+			 */
+			if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+			     sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+			    (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
+			     nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
+				return -EBUSY;
+
+			/*
+			 * The remaining checks are only performed for interfaces
+			 * with the same MAC address.
+			 */
+			if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+				continue;
+
 			/*
 			 * check whether it may have the same address
 			 */
@@ -186,8 +248,7 @@ static int ieee80211_open(struct net_device *dev)
 			 * can only add VLANs to enabled APs
 			 */
 			if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
-			    nsdata->vif.type == IEEE80211_IF_TYPE_AP &&
-			    netif_running(nsdata->dev))
+			    nsdata->vif.type == IEEE80211_IF_TYPE_AP)
 				sdata->u.vlan.ap = nsdata;
 		}
 	}
@@ -196,6 +257,20 @@ static int ieee80211_open(struct net_device *dev)
 	case IEEE80211_IF_TYPE_WDS:
 		if (is_zero_ether_addr(sdata->u.wds.remote_addr))
 			return -ENOLINK;
+
+		/* Create STA entry for the WDS peer */
+		sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+				     GFP_KERNEL);
+		if (!sta)
+			return -ENOMEM;
+
+		sta->flags |= WLAN_STA_AUTHORIZED;
+
+		res = sta_info_insert(sta);
+		if (res) {
+			/* STA has been freed */
+			return res;
+		}
 		break;
 	case IEEE80211_IF_TYPE_VLAN:
 		if (!sdata->u.vlan.ap)
@@ -205,6 +280,7 @@ static int ieee80211_open(struct net_device *dev)
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_MNTR:
 	case IEEE80211_IF_TYPE_IBSS:
+	case IEEE80211_IF_TYPE_MESH_POINT:
 		/* no special treatment */
 		break;
 	case IEEE80211_IF_TYPE_INVALID:
@@ -229,15 +305,28 @@ static int ieee80211_open(struct net_device *dev)
 		/* no need to tell driver */
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs++;
+			break;
+		}
+
 		/* must be before the call to ieee80211_configure_filter */
 		local->monitors++;
-		if (local->monitors == 1) {
-			netif_tx_lock_bh(local->mdev);
-			ieee80211_configure_filter(local);
-			netif_tx_unlock_bh(local->mdev);
-
+		if (local->monitors == 1)
 			local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
-		}
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control++;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss++;
+
+		netif_tx_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_tx_unlock_bh(local->mdev);
 		break;
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
@@ -305,24 +394,46 @@ static int ieee80211_open(struct net_device *dev)
 
 static int ieee80211_stop(struct net_device *dev)
 {
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_init_conf conf;
 	struct sta_info *sta;
-	int i;
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	/*
+	 * Stop TX on this interface first.
+	 */
+	netif_stop_queue(dev);
 
-	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->dev == dev)
-			for (i = 0; i <  STA_TID_NUM; i++)
-				ieee80211_sta_stop_rx_ba_session(sta->dev,
-						sta->addr, i,
-						WLAN_BACK_RECIPIENT,
-						WLAN_REASON_QSTA_LEAVE_QBSS);
+	/*
+	 * Now delete all active aggregation sessions.
+	 */
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		if (sta->sdata == sdata)
+			ieee80211_sta_tear_down_BA_sessions(dev, sta->addr);
 	}
 
-	netif_stop_queue(dev);
+	rcu_read_unlock();
+
+	/*
+	 * Remove all stations associated with this interface.
+	 *
+	 * This must be done before calling ops->remove_interface()
+	 * because otherwise we can later invoke ops->sta_notify()
+	 * whenever the STAs are removed, and that invalidates driver
+	 * assumptions about always getting a vif pointer that is valid
+	 * (because if we remove a STA after ops->remove_interface()
+	 * the driver will have removed the vif info already!)
+	 *
+	 * We could relax this and only unlink the stations from the
+	 * hash table and list but keep them on a per-sdata list that
+	 * will be inserted back again when the interface is brought
+	 * up again, but I don't currently see a use case for that,
+	 * except with WDS which gets a STA entry created when it is
+	 * brought up.
+	 */
+	sta_info_flush(local, sdata);
 
 	/*
 	 * Don't count this interface for promisc/allmulti while it
@@ -364,15 +475,29 @@ static int ieee80211_stop(struct net_device *dev)
 		/* no need to tell driver */
 		break;
 	case IEEE80211_IF_TYPE_MNTR:
-		local->monitors--;
-		if (local->monitors == 0) {
-			netif_tx_lock_bh(local->mdev);
-			ieee80211_configure_filter(local);
-			netif_tx_unlock_bh(local->mdev);
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) {
+			local->cooked_mntrs--;
+			break;
+		}
 
+		local->monitors--;
+		if (local->monitors == 0)
 			local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
-		}
+
+		if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL)
+			local->fif_fcsfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL)
+			local->fif_plcpfail--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL)
+			local->fif_control--;
+		if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
+			local->fif_other_bss--;
+
+		netif_tx_lock_bh(local->mdev);
+		ieee80211_configure_filter(local);
+		netif_tx_unlock_bh(local->mdev);
 		break;
+	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		sdata->u.sta.state = IEEE80211_DISABLED;
@@ -426,6 +551,359 @@ static int ieee80211_stop(struct net_device *dev)
 	return 0;
 }
 
+int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata;
+	u16 start_seq_num = 0;
+	u8 *state;
+	int ret;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Open BA session requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		printk(KERN_DEBUG "Could not find the station\n");
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	/* we have tried too many times, receiver does not want A-MPDU */
+	if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
+		ret = -EBUSY;
+		goto start_ba_exit;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	/* check if the TID is not in aggregation flow already */
+	if (*state != HT_AGG_STATE_IDLE) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - session is not "
+				 "idle on tid %u\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -EAGAIN;
+		goto start_ba_exit;
+	}
+
+	/* prepare A-MPDU MLME for Tx aggregation */
+	sta->ampdu_mlme.tid_tx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_tx[tid]) {
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
+					tid);
+		ret = -ENOMEM;
+		goto start_ba_exit;
+	}
+	/* Tx timer */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
+			sta_addba_resp_timer_expired;
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data =
+			(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+
+	/* ensure that TX flow won't interrupt us
+	 * until the end of the call to requeue function */
+	spin_lock_bh(&local->mdev->queue_lock);
+
+	/* create a new queue for this aggregation */
+	ret = ieee80211_ht_agg_queue_add(local, sta, tid);
+
+	/* case no queue is available to aggregation
+	 * don't switch to aggregation */
+	if (ret) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - queue unavailable for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto start_ba_err;
+	}
+	sdata = sta->sdata;
+
+	/* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
+	 * call back right away, it must see that the flow has begun */
+	*state |= HT_ADDBA_REQUESTED_MSK;
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
+						ra, tid, &start_seq_num);
+
+	if (ret) {
+		/* No need to requeue the packets in the agg queue, since we
+		 * held the tx lock: no packet could be enqueued to the newly
+		 * allocated queue */
+		 ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "BA request denied - HW unavailable for"
+					" tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		*state = HT_AGG_STATE_IDLE;
+		goto start_ba_err;
+	}
+
+	/* Will put all the packets in the new SW queue */
+	ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
+	spin_unlock_bh(&local->mdev->queue_lock);
+
+	/* send an addBA request */
+	sta->ampdu_mlme.dialog_token_allocator++;
+	sta->ampdu_mlme.tid_tx[tid]->dialog_token =
+			sta->ampdu_mlme.dialog_token_allocator;
+	sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
+	ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
+			 sta->ampdu_mlme.tid_tx[tid]->dialog_token,
+			 sta->ampdu_mlme.tid_tx[tid]->ssn,
+			 0x40, 5000);
+
+	/* activate the timer for the recipient's addBA response */
+	sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
+				jiffies + ADDBA_RESP_INTERVAL;
+	add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+	printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
+	goto start_ba_exit;
+
+start_ba_err:
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	spin_unlock_bh(&local->mdev->queue_lock);
+	ret = -EBUSY;
+start_ba_exit:
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_session);
+
+int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
+				 u8 *ra, u16 tid,
+				 enum ieee80211_back_parties initiator)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int ret = 0;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM)
+		return -EINVAL;
+
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n",
+				print_mac(mac, ra), tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		return -ENOENT;
+	}
+
+	/* check if the TID is in aggregation */
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (*state != HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "Try to stop Tx aggregation on"
+				" non active TID\n");
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		ret = -ENOENT;
+		goto stop_BA_exit;
+	}
+
+	ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]);
+
+	*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
+		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
+
+	if (local->ops->ampdu_action)
+		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP,
+						ra, tid, NULL);
+
+	/* case HW denied going back to legacy */
+	if (ret) {
+		WARN_ON(ret != -EBUSY);
+		*state = HT_AGG_STATE_OPERATIONAL;
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		goto stop_BA_exit;
+	}
+
+stop_BA_exit:
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	rcu_read_unlock();
+	return ret;
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
+
+void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+		return;
+	}
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		rcu_read_unlock();
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
+				*state);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		rcu_read_unlock();
+		return;
+	}
+
+	WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+
+	*state |= HT_ADDBA_DRV_READY_MSK;
+
+	if (*state == HT_AGG_STATE_OPERATIONAL) {
+		printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+		ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+	}
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
+
+void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct sta_info *sta;
+	u8 *state;
+	int agg_queue;
+	DECLARE_MAC_BUF(mac);
+
+	if (tid >= STA_TID_NUM) {
+		printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
+				tid, STA_TID_NUM);
+		return;
+	}
+
+	printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n",
+				print_mac(mac, ra), tid);
+
+	rcu_read_lock();
+	sta = sta_info_get(local, ra);
+	if (!sta) {
+		printk(KERN_DEBUG "Could not find station: %s\n",
+				print_mac(mac, ra));
+		rcu_read_unlock();
+		return;
+	}
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+	if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+		printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		rcu_read_unlock();
+		return;
+	}
+
+	if (*state & HT_AGG_STATE_INITIATOR_MSK)
+		ieee80211_send_delba(sta->sdata->dev, ra, tid,
+			WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+
+	agg_queue = sta->tid_to_tx_q[tid];
+
+	/* avoid ordering issues: we are the only one that can modify
+	 * the content of the qdiscs */
+	spin_lock_bh(&local->mdev->queue_lock);
+	/* remove the queue for this aggregation */
+	ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+	spin_unlock_bh(&local->mdev->queue_lock);
+
+	/* we just requeued the all the frames that were in the removed
+	 * queue, and since we might miss a softirq we do netif_schedule.
+	 * ieee80211_wake_queue is not used here as this queue is not
+	 * necessarily stopped */
+	netif_schedule(local->mdev);
+	*state = HT_AGG_STATE_IDLE;
+	sta->ampdu_mlme.addba_req_num[tid] = 0;
+	kfree(sta->ampdu_mlme.tid_tx[tid]);
+	sta->ampdu_mlme.tid_tx[tid] = NULL;
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb);
+
+void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				      const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping start BA session", skb->dev->name);
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_ADDBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
+
+void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
+				     const u8 *ra, u16 tid)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_ra_tid *ra_tid;
+	struct sk_buff *skb = dev_alloc_skb(0);
+
+	if (unlikely(!skb)) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%s: Not enough memory, "
+			       "dropping stop BA session", skb->dev->name);
+		return;
+	}
+	ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+	memcpy(&ra_tid->ra, ra, ETH_ALEN);
+	ra_tid->tid = tid;
+
+	skb->pkt_type = IEEE80211_DELBA_MSG;
+	skb_queue_tail(&local->skb_queue, skb);
+	tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
+
 static void ieee80211_set_multicast_list(struct net_device *dev)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -477,41 +955,6 @@ void ieee80211_if_setup(struct net_device *dev)
 	dev->destructor = ieee80211_if_free;
 }
 
-/* WDS specialties */
-
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct sta_info *sta;
-	DECLARE_MAC_BUF(mac);
-
-	if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
-		return 0;
-
-	/* Create STA entry for the new peer */
-	sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
-	if (!sta)
-		return -ENOMEM;
-	sta_info_put(sta);
-
-	/* Remove STA entry for the old peer */
-	sta = sta_info_get(local, sdata->u.wds.remote_addr);
-	if (sta) {
-		sta_info_free(sta);
-		sta_info_put(sta);
-	} else {
-		printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
-		       "peer %s\n",
-		       dev->name, print_mac(mac, sdata->u.wds.remote_addr));
-	}
-
-	/* Update WDS link data */
-	memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
-	return 0;
-}
-
 /* everything else */
 
 static int __ieee80211_if_config(struct net_device *dev,
@@ -532,6 +975,9 @@ static int __ieee80211_if_config(struct net_device *dev,
 		conf.bssid = sdata->u.sta.bssid;
 		conf.ssid = sdata->u.sta.ssid;
 		conf.ssid_len = sdata->u.sta.ssid_len;
+	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		conf.beacon = beacon;
+		ieee80211_start_mesh(dev);
 	} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
 		conf.ssid = sdata->u.ap.ssid;
 		conf.ssid_len = sdata->u.ap.ssid_len;
@@ -544,6 +990,11 @@ static int __ieee80211_if_config(struct net_device *dev,
 
 int ieee80211_if_config(struct net_device *dev)
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
+	    (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+		return ieee80211_if_config_beacon(dev);
 	return __ieee80211_if_config(dev, NULL, NULL);
 }
 
@@ -565,37 +1016,28 @@ int ieee80211_if_config_beacon(struct net_device *dev)
 
 int ieee80211_hw_config(struct ieee80211_local *local)
 {
-	struct ieee80211_hw_mode *mode;
 	struct ieee80211_channel *chan;
 	int ret = 0;
 
-	if (local->sta_sw_scanning) {
+	if (local->sta_sw_scanning)
 		chan = local->scan_channel;
-		mode = local->scan_hw_mode;
-	} else {
+	else
 		chan = local->oper_channel;
-		mode = local->oper_hw_mode;
-	}
 
-	local->hw.conf.channel = chan->chan;
-	local->hw.conf.channel_val = chan->val;
-	if (!local->hw.conf.power_level) {
-		local->hw.conf.power_level = chan->power_level;
-	} else {
-		local->hw.conf.power_level = min(chan->power_level,
-						 local->hw.conf.power_level);
-	}
-	local->hw.conf.freq = chan->freq;
-	local->hw.conf.phymode = mode->mode;
-	local->hw.conf.antenna_max = chan->antenna_max;
-	local->hw.conf.chan = chan;
-	local->hw.conf.mode = mode;
+	local->hw.conf.channel = chan;
+
+	if (!local->hw.conf.power_level)
+		local->hw.conf.power_level = chan->max_power;
+	else
+		local->hw.conf.power_level = min(chan->max_power,
+					       local->hw.conf.power_level);
+
+	local->hw.conf.max_antenna_gain = chan->max_antenna_gain;
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
-	       "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
-	       local->hw.conf.phymode);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n",
+	       wiphy_name(local->hw.wiphy), chan->center_freq);
+#endif
 
 	if (local->open_count)
 		ret = local->ops->config(local_to_hw(local), &local->hw.conf);
@@ -613,11 +1055,13 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
 			   struct ieee80211_ht_bss_info *req_bss_cap)
 {
 	struct ieee80211_conf *conf = &local->hw.conf;
-	struct ieee80211_hw_mode *mode = conf->mode;
+	struct ieee80211_supported_band *sband;
 	int i;
 
+	sband = local->hw.wiphy->bands[conf->channel->band];
+
 	/* HT is not supported */
-	if (!mode->ht_info.ht_supported) {
+	if (!sband->ht_info.ht_supported) {
 		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
 		return -EOPNOTSUPP;
 	}
@@ -627,17 +1071,17 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
 		conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
 	} else {
 		conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
-		conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap;
+		conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
 		conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
 		conf->ht_conf.cap |=
-			mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+			sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
 		conf->ht_bss_conf.primary_channel =
 			req_bss_cap->primary_channel;
 		conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
 		conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
 		for (i = 0; i < SUPP_MCS_SET_LEN; i++)
 			conf->ht_conf.supp_mcs_set[i] =
-				mode->ht_info.supp_mcs_set[i] &
+				sband->ht_info.supp_mcs_set[i] &
 				  req_ht_cap->supp_mcs_set[i];
 
 		/* In STA mode, this gives us indication
@@ -725,6 +1169,7 @@ static void ieee80211_tasklet_handler(unsigned long data)
 	struct sk_buff *skb;
 	struct ieee80211_rx_status rx_status;
 	struct ieee80211_tx_status *tx_status;
+	struct ieee80211_ra_tid *ra_tid;
 
 	while ((skb = skb_dequeue(&local->skb_queue)) ||
 	       (skb = skb_dequeue(&local->skb_queue_unreliable))) {
@@ -745,6 +1190,18 @@ static void ieee80211_tasklet_handler(unsigned long data)
 					    skb, tx_status);
 			kfree(tx_status);
 			break;
+		case IEEE80211_DELBA_MSG:
+			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+			ieee80211_stop_tx_ba_cb(local_to_hw(local),
+						ra_tid->ra, ra_tid->tid);
+			dev_kfree_skb(skb);
+			break;
+		case IEEE80211_ADDBA_MSG:
+			ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
+			ieee80211_start_tx_ba_cb(local_to_hw(local),
+						 ra_tid->ra, ra_tid->tid);
+			dev_kfree_skb(skb);
+			break ;
 		default: /* should never get here! */
 			printk(KERN_ERR "%s: Unknown message type (%d)\n",
 			       wiphy_name(local->hw.wiphy), skb->pkt_type);
@@ -822,6 +1279,77 @@ no_key:
 	}
 }
 
+static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
+					    struct sta_info *sta,
+					    struct sk_buff *skb,
+					    struct ieee80211_tx_status *status)
+{
+	sta->tx_filtered_count++;
+
+	/*
+	 * Clear the TX filter mask for this STA when sending the next
+	 * packet. If the STA went to power save mode, this will happen
+	 * happen when it wakes up for the next time.
+	 */
+	sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+
+	/*
+	 * This code races in the following way:
+	 *
+	 *  (1) STA sends frame indicating it will go to sleep and does so
+	 *  (2) hardware/firmware adds STA to filter list, passes frame up
+	 *  (3) hardware/firmware processes TX fifo and suppresses a frame
+	 *  (4) we get TX status before having processed the frame and
+	 *	knowing that the STA has gone to sleep.
+	 *
+	 * This is actually quite unlikely even when both those events are
+	 * processed from interrupts coming in quickly after one another or
+	 * even at the same time because we queue both TX status events and
+	 * RX frames to be processed by a tasklet and process them in the
+	 * same order that they were received or TX status last. Hence, there
+	 * is no race as long as the frame RX is processed before the next TX
+	 * status, which drivers can ensure, see below.
+	 *
+	 * Note that this can only happen if the hardware or firmware can
+	 * actually add STAs to the filter list, if this is done by the
+	 * driver in response to set_tim() (which will only reduce the race
+	 * this whole filtering tries to solve, not completely solve it)
+	 * this situation cannot happen.
+	 *
+	 * To completely solve this race drivers need to make sure that they
+	 *  (a) don't mix the irq-safe/not irq-safe TX status/RX processing
+	 *	functions and
+	 *  (b) always process RX events before TX status events if ordering
+	 *      can be unknown, for example with different interrupt status
+	 *	bits.
+	 */
+	if (sta->flags & WLAN_STA_PS &&
+	    skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
+		ieee80211_remove_tx_extra(local, sta->key, skb,
+					  &status->control);
+		skb_queue_tail(&sta->tx_filtered, skb);
+		return;
+	}
+
+	if (!(sta->flags & WLAN_STA_PS) &&
+	    !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+		/* Software retry the packet once */
+		status->control.flags |= IEEE80211_TXCTL_REQUEUE;
+		ieee80211_remove_tx_extra(local, sta->key, skb,
+					  &status->control);
+		dev_queue_xmit(skb);
+		return;
+	}
+
+	if (net_ratelimit())
+		printk(KERN_DEBUG "%s: dropped TX filtered frame, "
+		       "queue_len=%d PS=%d @%lu\n",
+		       wiphy_name(local->hw.wiphy),
+		       skb_queue_len(&sta->tx_filtered),
+		       !!(sta->flags & WLAN_STA_PS), jiffies);
+	dev_kfree_skb(skb);
+}
+
 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 			 struct ieee80211_tx_status *status)
 {
@@ -831,7 +1359,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 	u16 frag, type;
 	struct ieee80211_tx_status_rtap_hdr *rthdr;
 	struct ieee80211_sub_if_data *sdata;
-	int monitors;
+	struct net_device *prev_dev = NULL;
 
 	if (!status) {
 		printk(KERN_ERR
@@ -841,18 +1369,24 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 		return;
 	}
 
+	rcu_read_lock();
+
 	if (status->excessive_retries) {
 		struct sta_info *sta;
 		sta = sta_info_get(local, hdr->addr1);
 		if (sta) {
 			if (sta->flags & WLAN_STA_PS) {
-				/* The STA is in power save mode, so assume
+				/*
+				 * The STA is in power save mode, so assume
 				 * that this TX packet failed because of that.
 				 */
 				status->excessive_retries = 0;
 				status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+				ieee80211_handle_filtered_frame(local, sta,
+								skb, status);
+				rcu_read_unlock();
+				return;
 			}
-			sta_info_put(sta);
 		}
 	}
 
@@ -860,53 +1394,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 		struct sta_info *sta;
 		sta = sta_info_get(local, hdr->addr1);
 		if (sta) {
-			sta->tx_filtered_count++;
-
-			/* Clear the TX filter mask for this STA when sending
-			 * the next packet. If the STA went to power save mode,
-			 * this will happen when it is waking up for the next
-			 * time. */
-			sta->clear_dst_mask = 1;
-
-			/* TODO: Is the WLAN_STA_PS flag always set here or is
-			 * the race between RX and TX status causing some
-			 * packets to be filtered out before 80211.o gets an
-			 * update for PS status? This seems to be the case, so
-			 * no changes are likely to be needed. */
-			if (sta->flags & WLAN_STA_PS &&
-			    skb_queue_len(&sta->tx_filtered) <
-			    STA_MAX_TX_BUFFER) {
-				ieee80211_remove_tx_extra(local, sta->key,
-							  skb,
-							  &status->control);
-				skb_queue_tail(&sta->tx_filtered, skb);
-			} else if (!(sta->flags & WLAN_STA_PS) &&
-				   !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
-				/* Software retry the packet once */
-				status->control.flags |= IEEE80211_TXCTL_REQUEUE;
-				ieee80211_remove_tx_extra(local, sta->key,
-							  skb,
-							  &status->control);
-				dev_queue_xmit(skb);
-			} else {
-				if (net_ratelimit()) {
-					printk(KERN_DEBUG "%s: dropped TX "
-					       "filtered frame queue_len=%d "
-					       "PS=%d @%lu\n",
-					       wiphy_name(local->hw.wiphy),
-					       skb_queue_len(
-						       &sta->tx_filtered),
-					       !!(sta->flags & WLAN_STA_PS),
-					       jiffies);
-				}
-				dev_kfree_skb(skb);
-			}
-			sta_info_put(sta);
+			ieee80211_handle_filtered_frame(local, sta, skb,
+							status);
+			rcu_read_unlock();
 			return;
 		}
 	} else
 		rate_control_tx_status(local->mdev, skb, status);
 
+	rcu_read_unlock();
+
 	ieee80211_led_tx(local, 0);
 
 	/* SNMP counters
@@ -944,7 +1441,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 	/* this was a transmitted frame, but now we want to reuse it */
 	skb_orphan(skb);
 
-	if (!local->monitors) {
+	/*
+	 * This is a bit racy but we can avoid a lot of work
+	 * with this test...
+	 */
+	if (!local->monitors && !local->cooked_mntrs) {
 		dev_kfree_skb(skb);
 		return;
 	}
@@ -978,51 +1479,44 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
 
 	rthdr->data_retries = status->retry_count;
 
+	/* XXX: is this sufficient for BPF? */
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+	memset(skb->cb, 0, sizeof(skb->cb));
+
 	rcu_read_lock();
-	monitors = local->monitors;
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-		/*
-		 * Using the monitors counter is possibly racy, but
-		 * if the value is wrong we simply either clone the skb
-		 * once too much or forget sending it to one monitor iface
-		 * The latter case isn't nice but fixing the race is much
-		 * more complicated.
-		 */
-		if (!monitors || !skb)
-			goto out;
-
 		if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) {
 			if (!netif_running(sdata->dev))
 				continue;
-			monitors--;
-			if (monitors)
+
+			if (prev_dev) {
 				skb2 = skb_clone(skb, GFP_ATOMIC);
-			else
-				skb2 = NULL;
-			skb->dev = sdata->dev;
-			/* XXX: is this sufficient for BPF? */
-			skb_set_mac_header(skb, 0);
-			skb->ip_summed = CHECKSUM_UNNECESSARY;
-			skb->pkt_type = PACKET_OTHERHOST;
-			skb->protocol = htons(ETH_P_802_2);
-			memset(skb->cb, 0, sizeof(skb->cb));
-			netif_rx(skb);
-			skb = skb2;
+				if (skb2) {
+					skb2->dev = prev_dev;
+					netif_rx(skb2);
+				}
+			}
+
+			prev_dev = sdata->dev;
 		}
 	}
- out:
+	if (prev_dev) {
+		skb->dev = prev_dev;
+		netif_rx(skb);
+		skb = NULL;
+	}
 	rcu_read_unlock();
-	if (skb)
-		dev_kfree_skb(skb);
+	dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(ieee80211_tx_status);
 
 struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 					const struct ieee80211_ops *ops)
 {
-	struct net_device *mdev;
 	struct ieee80211_local *local;
-	struct ieee80211_sub_if_data *sdata;
 	int priv_size;
 	struct wiphy *wiphy;
 
@@ -1068,25 +1562,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	BUG_ON(!ops->configure_filter);
 	local->ops = ops;
 
-	/* for now, mdev needs sub_if_data :/ */
-	mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
-			    "wmaster%d", ether_setup);
-	if (!mdev) {
-		wiphy_free(wiphy);
-		return NULL;
-	}
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
-	mdev->ieee80211_ptr = &sdata->wdev;
-	sdata->wdev.wiphy = wiphy;
-
 	local->hw.queues = 1; /* default */
 
-	local->mdev = mdev;
-	local->rx_pre_handlers = ieee80211_rx_pre_handlers;
-	local->rx_handlers = ieee80211_rx_handlers;
-	local->tx_handlers = ieee80211_tx_handlers;
-
 	local->bridge_packets = 1;
 
 	local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
@@ -1095,33 +1572,12 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 	local->long_retry_limit = 4;
 	local->hw.conf.radio_enabled = 1;
 
-	local->enabled_modes = ~0;
-
-	INIT_LIST_HEAD(&local->modes_list);
-
 	INIT_LIST_HEAD(&local->interfaces);
 
 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
-	ieee80211_rx_bss_list_init(mdev);
 
 	sta_info_init(local);
 
-	mdev->hard_start_xmit = ieee80211_master_start_xmit;
-	mdev->open = ieee80211_master_open;
-	mdev->stop = ieee80211_master_stop;
-	mdev->type = ARPHRD_IEEE80211;
-	mdev->header_ops = &ieee80211_header_ops;
-	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
-
-	sdata->vif.type = IEEE80211_IF_TYPE_AP;
-	sdata->dev = mdev;
-	sdata->local = local;
-	sdata->u.ap.force_unicast_rateidx = -1;
-	sdata->u.ap.max_ratectrl_rateidx = -1;
-	ieee80211_if_sdata_init(sdata);
-	/* no RCU needed since we're still during init phase */
-	list_add_tail(&sdata->list, &local->interfaces);
-
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
 		     (unsigned long)local);
 	tasklet_disable(&local->tx_pending_tasklet);
@@ -1143,11 +1599,63 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	struct ieee80211_local *local = hw_to_local(hw);
 	const char *name;
 	int result;
+	enum ieee80211_band band;
+	struct net_device *mdev;
+	struct ieee80211_sub_if_data *sdata;
+
+	/*
+	 * generic code guarantees at least one band,
+	 * set this very early because much code assumes
+	 * that hw.conf.channel is assigned
+	 */
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[band];
+		if (sband) {
+			/* init channel we're on */
+			local->hw.conf.channel =
+			local->oper_channel =
+			local->scan_channel = &sband->channels[0];
+			break;
+		}
+	}
 
 	result = wiphy_register(local->hw.wiphy);
 	if (result < 0)
 		return result;
 
+	/* for now, mdev needs sub_if_data :/ */
+	mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+			    "wmaster%d", ether_setup);
+	if (!mdev)
+		goto fail_mdev_alloc;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
+	mdev->ieee80211_ptr = &sdata->wdev;
+	sdata->wdev.wiphy = local->hw.wiphy;
+
+	local->mdev = mdev;
+
+	ieee80211_rx_bss_list_init(mdev);
+
+	mdev->hard_start_xmit = ieee80211_master_start_xmit;
+	mdev->open = ieee80211_master_open;
+	mdev->stop = ieee80211_master_stop;
+	mdev->type = ARPHRD_IEEE80211;
+	mdev->header_ops = &ieee80211_header_ops;
+	mdev->set_multicast_list = ieee80211_master_set_multicast_list;
+
+	sdata->vif.type = IEEE80211_IF_TYPE_AP;
+	sdata->dev = mdev;
+	sdata->local = local;
+	sdata->u.ap.force_unicast_rateidx = -1;
+	sdata->u.ap.max_ratectrl_rateidx = -1;
+	ieee80211_if_sdata_init(sdata);
+
+	/* no RCU needed since we're still during init phase */
+	list_add_tail(&sdata->list, &local->interfaces);
+
 	name = wiphy_dev(local->hw.wiphy)->driver->name;
 	local->hw.workqueue = create_singlethread_workqueue(name);
 	if (!local->hw.workqueue) {
@@ -1215,7 +1723,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
 	/* add one default STA interface */
 	result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
-				  IEEE80211_IF_TYPE_STA);
+				  IEEE80211_IF_TYPE_STA, NULL);
 	if (result)
 		printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
 		       wiphy_name(local->hw.wiphy));
@@ -1239,49 +1747,18 @@ fail_sta_info:
 	debugfs_hw_del(local);
 	destroy_workqueue(local->hw.workqueue);
 fail_workqueue:
+	ieee80211_if_free(local->mdev);
+	local->mdev = NULL;
+fail_mdev_alloc:
 	wiphy_unregister(local->hw.wiphy);
 	return result;
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
 
-int ieee80211_register_hwmode(struct ieee80211_hw *hw,
-			      struct ieee80211_hw_mode *mode)
-{
-	struct ieee80211_local *local = hw_to_local(hw);
-	struct ieee80211_rate *rate;
-	int i;
-
-	INIT_LIST_HEAD(&mode->list);
-	list_add_tail(&mode->list, &local->modes_list);
-
-	local->hw_modes |= (1 << mode->mode);
-	for (i = 0; i < mode->num_rates; i++) {
-		rate = &(mode->rates[i]);
-		rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
-	}
-	ieee80211_prepare_rates(local, mode);
-
-	if (!local->oper_hw_mode) {
-		/* Default to this mode */
-		local->hw.conf.phymode = mode->mode;
-		local->oper_hw_mode = local->scan_hw_mode = mode;
-		local->oper_channel = local->scan_channel = &mode->channels[0];
-		local->hw.conf.mode = local->oper_hw_mode;
-		local->hw.conf.chan = local->oper_channel;
-	}
-
-	if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
-		ieee80211_set_default_regdomain(mode);
-
-	return 0;
-}
-EXPORT_SYMBOL(ieee80211_register_hwmode);
-
 void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata, *tmp;
-	int i;
 
 	tasklet_kill(&local->tx_pending_tasklet);
 	tasklet_kill(&local->tasklet);
@@ -1322,11 +1799,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	rate_control_deinitialize(local);
 	debugfs_hw_del(local);
 
-	for (i = 0; i < NUM_IEEE80211_MODES; i++) {
-		kfree(local->supp_rates[i]);
-		kfree(local->basic_rates[i]);
-	}
-
 	if (skb_queue_len(&local->skb_queue)
 			|| skb_queue_len(&local->skb_queue_unreliable))
 		printk(KERN_WARNING "%s: skb_queue not empty\n",
@@ -1338,6 +1810,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	wiphy_unregister(local->hw.wiphy);
 	ieee80211_wep_free(local);
 	ieee80211_led_exit(local);
+	ieee80211_if_free(local->mdev);
+	local->mdev = NULL;
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
@@ -1345,7 +1819,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 
-	ieee80211_if_free(local->mdev);
 	wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
@@ -1357,13 +1830,9 @@ static int __init ieee80211_init(void)
 
 	BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
 
-	ret = rc80211_simple_init();
-	if (ret)
-		goto out;
-
 	ret = rc80211_pid_init();
 	if (ret)
-		goto out_cleanup_simple;
+		goto out;
 
 	ret = ieee80211_wme_register();
 	if (ret) {
@@ -1373,23 +1842,22 @@ static int __init ieee80211_init(void)
 	}
 
 	ieee80211_debugfs_netdev_init();
-	ieee80211_regdomain_init();
 
 	return 0;
 
  out_cleanup_pid:
 	rc80211_pid_exit();
- out_cleanup_simple:
-	rc80211_simple_exit();
  out:
 	return ret;
 }
 
 static void __exit ieee80211_exit(void)
 {
-	rc80211_simple_exit();
 	rc80211_pid_exit();
 
+	if (mesh_allocated)
+		ieee80211s_stop();
+
 	ieee80211_wme_unregister();
 	ieee80211_debugfs_netdev_exit();
 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 72ecbf7bf962..6c62dd42f915 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -69,18 +69,26 @@ struct ieee80211_fragment_entry {
 	u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
 };
 
+struct bss_mesh_config {
+	u32 path_proto_id;
+	u32 path_metric_id;
+	u32 cong_control_id;
+	u32 channel_precedence;
+	u8 mesh_version;
+};
+
 
 struct ieee80211_sta_bss {
 	struct list_head list;
 	struct ieee80211_sta_bss *hnext;
+	size_t ssid_len;
+
 	atomic_t users;
 
 	u8 bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	size_t ssid_len;
 	u16 capability; /* host byte order */
-	int hw_mode;
-	int channel;
+	enum ieee80211_band band;
 	int freq;
 	int rssi, signal, noise;
 	u8 *wpa_ie;
@@ -91,11 +99,16 @@ struct ieee80211_sta_bss {
 	size_t wmm_ie_len;
 	u8 *ht_ie;
 	size_t ht_ie_len;
+#ifdef CONFIG_MAC80211_MESH
+	u8 *mesh_id;
+	size_t mesh_id_len;
+	struct bss_mesh_config *mesh_cfg;
+#endif
 #define IEEE80211_MAX_SUPP_RATES 32
 	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
 	size_t supp_rates_len;
-	int beacon_int;
 	u64 timestamp;
+	int beacon_int;
 
 	int probe_resp;
 	unsigned long last_update;
@@ -108,56 +121,99 @@ struct ieee80211_sta_bss {
 	u8 erp_value;
 };
 
+static inline
+struct bss_mesh_config *bss_mesh_cfg(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+	return bss->mesh_cfg;
+#endif
+	return NULL;
+}
 
-typedef enum {
-	TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
-} ieee80211_txrx_result;
+static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+	return bss->mesh_id;
+#endif
+	return NULL;
+}
 
-/* flags used in struct ieee80211_txrx_data.flags */
-/* whether the MSDU was fragmented */
-#define IEEE80211_TXRXD_FRAGMENTED		BIT(0)
-#define IEEE80211_TXRXD_TXUNICAST		BIT(1)
-#define IEEE80211_TXRXD_TXPS_BUFFERED		BIT(2)
-#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG	BIT(3)
-#define IEEE80211_TXRXD_RXIN_SCAN		BIT(4)
-/* frame is destined to interface currently processed (incl. multicast frames) */
-#define IEEE80211_TXRXD_RXRA_MATCH		BIT(5)
-#define IEEE80211_TXRXD_TX_INJECTED		BIT(6)
-#define IEEE80211_TXRXD_RX_AMSDU		BIT(7)
-struct ieee80211_txrx_data {
+static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss)
+{
+#ifdef CONFIG_MAC80211_MESH
+	return bss->mesh_id_len;
+#endif
+	return 0;
+}
+
+
+typedef unsigned __bitwise__ ieee80211_tx_result;
+#define TX_CONTINUE	((__force ieee80211_tx_result) 0u)
+#define TX_DROP		((__force ieee80211_tx_result) 1u)
+#define TX_QUEUED	((__force ieee80211_tx_result) 2u)
+
+#define IEEE80211_TX_FRAGMENTED		BIT(0)
+#define IEEE80211_TX_UNICAST		BIT(1)
+#define IEEE80211_TX_PS_BUFFERED	BIT(2)
+#define IEEE80211_TX_PROBE_LAST_FRAG	BIT(3)
+#define IEEE80211_TX_INJECTED		BIT(4)
+
+struct ieee80211_tx_data {
 	struct sk_buff *skb;
 	struct net_device *dev;
 	struct ieee80211_local *local;
 	struct ieee80211_sub_if_data *sdata;
 	struct sta_info *sta;
+	struct ieee80211_key *key;
+
+	struct ieee80211_tx_control *control;
+	struct ieee80211_channel *channel;
+	struct ieee80211_rate *rate;
+	/* use this rate (if set) for last fragment; rate can
+	 * be set to lower rate for the first fragments, e.g.,
+	 * when using CTS protection with IEEE 802.11g. */
+	struct ieee80211_rate *last_frag_rate;
+
+	/* Extra fragments (in addition to the first fragment
+	 * in skb) */
+	struct sk_buff **extra_frag;
+	int num_extra_frag;
+
 	u16 fc, ethertype;
+	unsigned int flags;
+};
+
+
+typedef unsigned __bitwise__ ieee80211_rx_result;
+#define RX_CONTINUE		((__force ieee80211_rx_result) 0u)
+#define RX_DROP_UNUSABLE	((__force ieee80211_rx_result) 1u)
+#define RX_DROP_MONITOR		((__force ieee80211_rx_result) 2u)
+#define RX_QUEUED		((__force ieee80211_rx_result) 3u)
+
+#define IEEE80211_RX_IN_SCAN		BIT(0)
+/* frame is destined to interface currently processed (incl. multicast frames) */
+#define IEEE80211_RX_RA_MATCH		BIT(1)
+#define IEEE80211_RX_AMSDU		BIT(2)
+#define IEEE80211_RX_CMNTR_REPORTED	BIT(3)
+#define IEEE80211_RX_FRAGMENTED		BIT(4)
+
+struct ieee80211_rx_data {
+	struct sk_buff *skb;
+	struct net_device *dev;
+	struct ieee80211_local *local;
+	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta;
 	struct ieee80211_key *key;
+	struct ieee80211_rx_status *status;
+	struct ieee80211_rate *rate;
+
+	u16 fc, ethertype;
 	unsigned int flags;
-	union {
-		struct {
-			struct ieee80211_tx_control *control;
-			struct ieee80211_hw_mode *mode;
-			struct ieee80211_rate *rate;
-			/* use this rate (if set) for last fragment; rate can
-			 * be set to lower rate for the first fragments, e.g.,
-			 * when using CTS protection with IEEE 802.11g. */
-			struct ieee80211_rate *last_frag_rate;
-			int last_frag_hwrate;
-
-			/* Extra fragments (in addition to the first fragment
-			 * in skb) */
-			int num_extra_frag;
-			struct sk_buff **extra_frag;
-		} tx;
-		struct {
-			struct ieee80211_rx_status *status;
-			int sent_ps_buffered;
-			int queue;
-			int load;
-			u32 tkip_iv32;
-			u16 tkip_iv16;
-		} rx;
-	} u;
+	int sent_ps_buffered;
+	int queue;
+	int load;
+	u32 tkip_iv32;
+	u16 tkip_iv16;
 };
 
 /* flags used in struct ieee80211_tx_packet_data.flags */
@@ -165,6 +221,7 @@ struct ieee80211_txrx_data {
 #define IEEE80211_TXPD_DO_NOT_ENCRYPT	BIT(1)
 #define IEEE80211_TXPD_REQUEUE		BIT(2)
 #define IEEE80211_TXPD_EAPOL_FRAME	BIT(3)
+#define IEEE80211_TXPD_AMPDU		BIT(4)
 /* Stored in sk_buff->cb */
 struct ieee80211_tx_packet_data {
 	int ifindex;
@@ -176,20 +233,12 @@ struct ieee80211_tx_packet_data {
 struct ieee80211_tx_stored_packet {
 	struct ieee80211_tx_control control;
 	struct sk_buff *skb;
-	int num_extra_frag;
 	struct sk_buff **extra_frag;
-	int last_frag_rateidx;
-	int last_frag_hwrate;
 	struct ieee80211_rate *last_frag_rate;
+	int num_extra_frag;
 	unsigned int last_frag_rate_ctrl_probe;
 };
 
-typedef ieee80211_txrx_result (*ieee80211_tx_handler)
-(struct ieee80211_txrx_data *tx);
-
-typedef ieee80211_txrx_result (*ieee80211_rx_handler)
-(struct ieee80211_txrx_data *rx);
-
 struct beacon_data {
 	u8 *head, *tail;
 	int head_len, tail_len;
@@ -206,10 +255,10 @@ struct ieee80211_if_ap {
 
 	/* yes, this looks ugly, but guarantees that we can later use
 	 * bitmap_empty :)
-	 * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */
+	 * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
 	u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
-	atomic_t num_sta_ps; /* number of stations in PS mode */
 	struct sk_buff_head ps_bc_buf;
+	atomic_t num_sta_ps; /* number of stations in PS mode */
 	int dtim_count;
 	int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
 	int max_ratectrl_rateidx; /* max TX rateidx for rate control */
@@ -217,8 +266,8 @@ struct ieee80211_if_ap {
 };
 
 struct ieee80211_if_wds {
-	u8 remote_addr[ETH_ALEN];
 	struct sta_info *sta;
+	u8 remote_addr[ETH_ALEN];
 };
 
 struct ieee80211_if_vlan {
@@ -226,6 +275,41 @@ struct ieee80211_if_vlan {
 	struct list_head list;
 };
 
+struct mesh_stats {
+	__u32 fwded_frames;		/* Mesh forwarded frames */
+	__u32 dropped_frames_ttl;	/* Not transmitted since mesh_ttl == 0*/
+	__u32 dropped_frames_no_route;	/* Not transmitted, no route found */
+	atomic_t estab_plinks;
+};
+
+#define PREQ_Q_F_START		0x1
+#define PREQ_Q_F_REFRESH	0x2
+struct mesh_preq_queue {
+	struct list_head list;
+	u8 dst[ETH_ALEN];
+	u8 flags;
+};
+
+struct mesh_config {
+	/* Timeouts in ms */
+	/* Mesh plink management parameters */
+	u16 dot11MeshRetryTimeout;
+	u16 dot11MeshConfirmTimeout;
+	u16 dot11MeshHoldingTimeout;
+	u16 dot11MeshMaxPeerLinks;
+	u8  dot11MeshMaxRetries;
+	u8  dot11MeshTTL;
+	bool auto_open_plinks;
+	/* HWMP parameters */
+	u8  dot11MeshHWMPmaxPREQretries;
+	u32 path_refresh_time;
+	u16 min_discovery_timeout;
+	u32 dot11MeshHWMPactivePathTimeout;
+	u16 dot11MeshHWMPpreqMinInterval;
+	u16 dot11MeshHWMPnetDiameterTraversalTime;
+};
+
+
 /* flags used in struct ieee80211_if_sta.flags */
 #define IEEE80211_STA_SSID_SET		BIT(0)
 #define IEEE80211_STA_BSSID_SET		BIT(1)
@@ -241,18 +325,47 @@ struct ieee80211_if_vlan {
 #define IEEE80211_STA_AUTO_CHANNEL_SEL	BIT(12)
 #define IEEE80211_STA_PRIVACY_INVOKED	BIT(13)
 struct ieee80211_if_sta {
-	enum {
-		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
-		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
-	} state;
 	struct timer_list timer;
 	struct work_struct work;
 	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	enum {
+		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
+		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
+		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED,
+		IEEE80211_MESH_UP
+	} state;
 	size_t ssid_len;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
+#ifdef CONFIG_MAC80211_MESH
+	struct timer_list mesh_path_timer;
+	u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
+	size_t mesh_id_len;
+	/* Active Path Selection Protocol Identifier */
+	u8 mesh_pp_id[4];
+	/* Active Path Selection Metric Identifier */
+	u8 mesh_pm_id[4];
+	/* Congestion Control Mode Identifier */
+	u8 mesh_cc_id[4];
+	/* Local mesh Destination Sequence Number */
+	u32 dsn;
+	/* Last used PREQ ID */
+	u32 preq_id;
+	atomic_t mpaths;
+	/* Timestamp of last DSN update */
+	unsigned long last_dsn_update;
+	/* Timestamp of last DSN sent */
+	unsigned long last_preq;
+	struct mesh_rmc *rmc;
+	spinlock_t mesh_preq_queue_lock;
+	struct mesh_preq_queue preq_queue;
+	int preq_queue_len;
+	struct mesh_stats mshstats;
+	struct mesh_config mshcfg;
+	u8 mesh_seqnum[3];
+	bool accepting_plinks;
+#endif
 	u16 aid;
 	u16 ap_capab, capab;
 	u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -262,16 +375,18 @@ struct ieee80211_if_sta {
 	u8 *assocreq_ies, *assocresp_ies;
 	size_t assocreq_ies_len, assocresp_ies_len;
 
+	struct sk_buff_head skb_queue;
+
 	int auth_tries, assoc_tries;
 
+	unsigned long request;
+
+	unsigned long last_probe;
+
 	unsigned int flags;
 #define IEEE80211_STA_REQ_SCAN 0
 #define IEEE80211_STA_REQ_AUTH 1
 #define IEEE80211_STA_REQ_RUN  2
-	unsigned long request;
-	struct sk_buff_head skb_queue;
-
-	unsigned long last_probe;
 
 #define IEEE80211_AUTH_ALG_OPEN BIT(0)
 #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
@@ -282,16 +397,34 @@ struct ieee80211_if_sta {
 
 	unsigned long ibss_join_req;
 	struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
-	u32 supp_rates_bits;
+	u32 supp_rates_bits[IEEE80211_NUM_BANDS];
 
 	int wmm_last_param_set;
+	int num_beacons; /* number of TXed beacon frames by this STA */
 };
 
+static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta,
+						u8 mesh_id_len, u8 *mesh_id)
+{
+#ifdef CONFIG_MAC80211_MESH
+	ifsta->mesh_id_len = mesh_id_len;
+	memcpy(ifsta->mesh_id, mesh_id, mesh_id_len);
+#endif
+}
+
+#ifdef CONFIG_MAC80211_MESH
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name)	\
+	do { (sta)->mshstats.name++; } while (0)
+#else
+#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \
+	do { } while (0)
+#endif
 
 /* flags used in struct ieee80211_sub_if_data.flags */
 #define IEEE80211_SDATA_ALLMULTI	BIT(0)
 #define IEEE80211_SDATA_PROMISC		BIT(1)
 #define IEEE80211_SDATA_USERSPACE_MLME	BIT(2)
+#define IEEE80211_SDATA_OPERATING_GMODE	BIT(3)
 struct ieee80211_sub_if_data {
 	struct list_head list;
 
@@ -306,11 +439,11 @@ struct ieee80211_sub_if_data {
 	unsigned int flags;
 
 	int drop_unencrypted;
+
 	/*
-	 * IEEE 802.1X Port access control in effect,
-	 * drop packets to/from unauthorized port
+	 * basic rates of this AP or the AP we're associated to
 	 */
-	int ieee802_1x_pac;
+	u64 basic_rates;
 
 	u16 sequence;
 
@@ -338,6 +471,7 @@ struct ieee80211_sub_if_data {
 		struct ieee80211_if_wds wds;
 		struct ieee80211_if_vlan vlan;
 		struct ieee80211_if_sta sta;
+		u32 mntr_flags;
 	} u;
 	int channel_use;
 	int channel_use_raw;
@@ -348,7 +482,6 @@ struct ieee80211_sub_if_data {
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *ieee802_1x_pac;
 			struct dentry *state;
 			struct dentry *bssid;
 			struct dentry *prev_bssid;
@@ -363,11 +496,11 @@ struct ieee80211_sub_if_data {
 			struct dentry *auth_alg;
 			struct dentry *auth_transaction;
 			struct dentry *flags;
+			struct dentry *num_beacons_sta;
 		} sta;
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *ieee802_1x_pac;
 			struct dentry *num_sta_ps;
 			struct dentry *dtim_count;
 			struct dentry *num_beacons;
@@ -378,19 +511,46 @@ struct ieee80211_sub_if_data {
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *ieee802_1x_pac;
 			struct dentry *peer;
 		} wds;
 		struct {
 			struct dentry *channel_use;
 			struct dentry *drop_unencrypted;
-			struct dentry *ieee802_1x_pac;
 		} vlan;
 		struct {
 			struct dentry *mode;
 		} monitor;
 		struct dentry *default_key;
 	} debugfs;
+
+#ifdef CONFIG_MAC80211_MESH
+	struct dentry *mesh_stats_dir;
+	struct {
+		struct dentry *fwded_frames;
+		struct dentry *dropped_frames_ttl;
+		struct dentry *dropped_frames_no_route;
+		struct dentry *estab_plinks;
+		struct timer_list mesh_path_timer;
+	} mesh_stats;
+
+	struct dentry *mesh_config_dir;
+	struct {
+		struct dentry *dot11MeshRetryTimeout;
+		struct dentry *dot11MeshConfirmTimeout;
+		struct dentry *dot11MeshHoldingTimeout;
+		struct dentry *dot11MeshMaxRetries;
+		struct dentry *dot11MeshTTL;
+		struct dentry *auto_open_plinks;
+		struct dentry *dot11MeshMaxPeerLinks;
+		struct dentry *dot11MeshHWMPactivePathTimeout;
+		struct dentry *dot11MeshHWMPpreqMinInterval;
+		struct dentry *dot11MeshHWMPnetDiameterTraversalTime;
+		struct dentry *dot11MeshHWMPmaxPREQretries;
+		struct dentry *path_refresh_time;
+		struct dentry *min_discovery_timeout;
+	} mesh_config;
+#endif
+
 #endif
 	/* must be last, dynamically sized area in this! */
 	struct ieee80211_vif vif;
@@ -407,6 +567,8 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p)
 enum {
 	IEEE80211_RX_MSG	= 1,
 	IEEE80211_TX_STATUS_MSG	= 2,
+	IEEE80211_DELBA_MSG	= 3,
+	IEEE80211_ADDBA_MSG	= 4,
 };
 
 struct ieee80211_local {
@@ -417,15 +579,15 @@ struct ieee80211_local {
 
 	const struct ieee80211_ops *ops;
 
-	/* List of registered struct ieee80211_hw_mode */
-	struct list_head modes_list;
-
 	struct net_device *mdev; /* wmaster# - "master" 802.11 device */
 	int open_count;
-	int monitors;
+	int monitors, cooked_mntrs;
+	/* number of interfaces with corresponding FIF_ flags */
+	int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss;
 	unsigned int filter_flags; /* FIF_* */
 	struct iw_statistics wstats;
 	u8 wstats_flags;
+	bool tim_in_locked_section; /* see ieee80211_beacon_get() */
 	int tx_headroom; /* required headroom for hardware/radiotap */
 
 	enum {
@@ -443,15 +605,23 @@ struct ieee80211_local {
 	struct sk_buff_head skb_queue;
 	struct sk_buff_head skb_queue_unreliable;
 
-	/* Station data structures */
-	rwlock_t sta_lock; /* protects STA data structures */
-	int num_sta; /* number of stations in sta_list */
+	/* Station data */
+	/*
+	 * The lock only protects the list, hash, timer and counter
+	 * against manipulation, reads are done in RCU. Additionally,
+	 * the lock protects each BSS's TIM bitmap and a few items
+	 * in a STA info structure.
+	 */
+	spinlock_t sta_lock;
+	unsigned long num_sta;
 	struct list_head sta_list;
+	struct list_head sta_flush_list;
+	struct work_struct sta_flush_work;
 	struct sta_info *sta_hash[STA_HASH_SIZE];
 	struct timer_list sta_cleanup;
 
-	unsigned long state[NUM_TX_DATA_QUEUES];
-	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+	unsigned long state[NUM_TX_DATA_QUEUES_AMPDU];
+	struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU];
 	struct tasklet_struct tx_pending_tasklet;
 
 	/* number of interfaces with corresponding IFF_ flags */
@@ -459,11 +629,6 @@ struct ieee80211_local {
 
 	struct rate_control_ref *rate_ctrl;
 
-	/* Supported and basic rate filters for different modes. These are
-	 * pointers to -1 terminated lists and rates in 100 kbps units. */
-	int *supp_rates[NUM_IEEE80211_MODES];
-	int *basic_rates[NUM_IEEE80211_MODES];
-
 	int rts_threshold;
 	int fragmentation_threshold;
 	int short_retry_limit; /* dot11ShortRetryLimit */
@@ -477,21 +642,18 @@ struct ieee80211_local {
 			     * deliver multicast frames both back to wireless
 			     * media and to the local net stack */
 
-	ieee80211_rx_handler *rx_pre_handlers;
-	ieee80211_rx_handler *rx_handlers;
-	ieee80211_tx_handler *tx_handlers;
-
 	struct list_head interfaces;
 
 	bool sta_sw_scanning;
 	bool sta_hw_scanning;
 	int scan_channel_idx;
+	enum ieee80211_band scan_band;
+
 	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
 	unsigned long last_scan_completed;
 	struct delayed_work scan_work;
 	struct net_device *scan_dev;
 	struct ieee80211_channel *oper_channel, *scan_channel;
-	struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
 	u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
 	size_t scan_ssid_len;
 	struct list_head sta_bss_list;
@@ -560,14 +722,8 @@ struct ieee80211_local {
 	int wifi_wme_noack_test;
 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
 
-	unsigned int enabled_modes; /* bitfield of allowed modes;
-				      * (1 << MODE_*) */
-	unsigned int hw_modes; /* bitfield of supported hardware modes;
-				* (1 << MODE_*) */
-
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct local_debugfsdentries {
-		struct dentry *channel;
 		struct dentry *frequency;
 		struct dentry *antenna_sel_tx;
 		struct dentry *antenna_sel_rx;
@@ -577,9 +733,7 @@ struct ieee80211_local {
 		struct dentry *short_retry_limit;
 		struct dentry *long_retry_limit;
 		struct dentry *total_ps_buffered;
-		struct dentry *mode;
 		struct dentry *wep_iv;
-		struct dentry *modes;
 		struct dentry *statistics;
 		struct local_debugfsdentries_statsdentries {
 			struct dentry *transmitted_fragment_count;
@@ -627,6 +781,63 @@ struct ieee80211_local {
 #endif
 };
 
+/* this struct represents 802.11n's RA/TID combination */
+struct ieee80211_ra_tid {
+	u8 ra[ETH_ALEN];
+	u16 tid;
+};
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	/* pointers to IEs */
+	u8 *ssid;
+	u8 *supp_rates;
+	u8 *fh_params;
+	u8 *ds_params;
+	u8 *cf_params;
+	u8 *tim;
+	u8 *ibss_params;
+	u8 *challenge;
+	u8 *wpa;
+	u8 *rsn;
+	u8 *erp_info;
+	u8 *ext_supp_rates;
+	u8 *wmm_info;
+	u8 *wmm_param;
+	u8 *ht_cap_elem;
+	u8 *ht_info_elem;
+	u8 *mesh_config;
+	u8 *mesh_id;
+	u8 *peer_link;
+	u8 *preq;
+	u8 *prep;
+	u8 *perr;
+
+	/* length of them, respectively */
+	u8 ssid_len;
+	u8 supp_rates_len;
+	u8 fh_params_len;
+	u8 ds_params_len;
+	u8 cf_params_len;
+	u8 tim_len;
+	u8 ibss_params_len;
+	u8 challenge_len;
+	u8 wpa_len;
+	u8 rsn_len;
+	u8 erp_info_len;
+	u8 ext_supp_rates_len;
+	u8 wmm_info_len;
+	u8 wmm_param_len;
+	u8 ht_cap_elem_len;
+	u8 ht_info_elem_len;
+	u8 mesh_config_len;
+	u8 mesh_id_len;
+	u8 peer_link_len;
+	u8 preq_len;
+	u8 prep_len;
+	u8 perr_len;
+};
+
 static inline struct ieee80211_local *hw_to_local(
 	struct ieee80211_hw *hw)
 {
@@ -650,57 +861,6 @@ struct sta_attribute {
 	ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
 };
 
-static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
-{
-	/*
-	 * This format has been mandated by the IEEE specifications,
-	 * so this line may not be changed to use the __set_bit() format.
-	 */
-	bss->tim[aid / 8] |= (1 << (aid % 8));
-}
-
-static inline void bss_tim_set(struct ieee80211_local *local,
-			       struct ieee80211_if_ap *bss, u16 aid)
-{
-	read_lock_bh(&local->sta_lock);
-	__bss_tim_set(bss, aid);
-	read_unlock_bh(&local->sta_lock);
-}
-
-static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
-{
-	/*
-	 * This format has been mandated by the IEEE specifications,
-	 * so this line may not be changed to use the __clear_bit() format.
-	 */
-	bss->tim[aid / 8] &= ~(1 << (aid % 8));
-}
-
-static inline void bss_tim_clear(struct ieee80211_local *local,
-				 struct ieee80211_if_ap *bss, u16 aid)
-{
-	read_lock_bh(&local->sta_lock);
-	__bss_tim_clear(bss, aid);
-	read_unlock_bh(&local->sta_lock);
-}
-
-/**
- * ieee80211_is_erp_rate - Check if a rate is an ERP rate
- * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
- * @rate: Transmission rate to check, in 100 kbps
- *
- * Check if a given rate is an Extended Rate PHY (ERP) rate.
- */
-static inline int ieee80211_is_erp_rate(int phymode, int rate)
-{
-	if (phymode == MODE_IEEE80211G) {
-		if (rate != 10 && rate != 20 &&
-		    rate != 55 && rate != 110)
-			return 1;
-	}
-	return 0;
-}
-
 static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 {
 	return compare_ether_addr(raddr, addr) == 0 ||
@@ -712,13 +872,8 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 int ieee80211_hw_config(struct ieee80211_local *local);
 int ieee80211_if_config(struct net_device *dev);
 int ieee80211_if_config_beacon(struct net_device *dev);
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode);
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 void ieee80211_if_setup(struct net_device *dev);
-struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local,
-					  int phymode, int hwrate);
 int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht,
 			   struct ieee80211_ht_info *req_ht_cap,
 			   struct ieee80211_ht_bss_info *req_bss_cap);
@@ -749,8 +904,9 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;
 /* ieee80211_ioctl.c */
 int ieee80211_set_compression(struct ieee80211_local *local,
 			      struct net_device *dev, struct sta_info *sta);
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+int ieee80211_set_freq(struct ieee80211_local *local, int freq);
 /* ieee80211_sta.c */
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
 void ieee80211_sta_timer(unsigned long data);
 void ieee80211_sta_work(struct work_struct *work);
 void ieee80211_sta_scan_work(struct work_struct *work);
@@ -763,9 +919,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
 void ieee80211_sta_req_auth(struct net_device *dev,
 			    struct ieee80211_if_sta *ifsta);
 int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
-ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev,
-					    struct sk_buff *skb,
-			   struct ieee80211_rx_status *rx_status);
+ieee80211_rx_result ieee80211_sta_rx_scan(
+	struct net_device *dev, struct sk_buff *skb,
+	struct ieee80211_rx_status *rx_status);
 void ieee80211_rx_bss_list_init(struct net_device *dev);
 void ieee80211_rx_bss_list_deinit(struct net_device *dev);
 int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
@@ -782,12 +938,36 @@ int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie,
 int ieee80211_ht_addt_info_ie_to_ht_bss_info(
 			struct ieee80211_ht_addt_info *ht_add_info_ie,
 			struct ieee80211_ht_bss_info *bss_info);
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+				  u16 tid, u8 dialog_token, u16 start_seq_num,
+				  u16 agg_size, u16 timeout);
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+				u16 initiator, u16 reason_code);
+
 void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da,
 				u16 tid, u16 initiator, u16 reason);
 void sta_rx_agg_session_timer_expired(unsigned long data);
+void sta_addba_resp_timer_expired(unsigned long data);
+void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr);
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+			    struct ieee802_11_elems *elems,
+			    enum ieee80211_band band);
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+		int encrypt);
+void ieee802_11_parse_elems(u8 *start, size_t len,
+				   struct ieee802_11_elems *elems);
+
+#ifdef CONFIG_MAC80211_MESH
+void ieee80211_start_mesh(struct net_device *dev);
+#else
+static inline void ieee80211_start_mesh(struct net_device *dev)
+{}
+#endif
+
 /* ieee80211_iface.c */
 int ieee80211_if_add(struct net_device *dev, const char *name,
-		     struct net_device **new_dev, int type);
+		     struct net_device **new_dev, int type,
+		     struct vif_params *params);
 void ieee80211_if_set_type(struct net_device *dev, int type);
 void ieee80211_if_reinit(struct net_device *dev);
 void __ieee80211_if_del(struct ieee80211_local *local,
@@ -796,16 +976,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
 void ieee80211_if_free(struct net_device *dev);
 void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
 
-/* regdomain.c */
-void ieee80211_regdomain_init(void);
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
-
-/* rx handling */
-extern ieee80211_rx_handler ieee80211_rx_pre_handlers[];
-extern ieee80211_rx_handler ieee80211_rx_handlers[];
-
 /* tx handling */
-extern ieee80211_tx_handler ieee80211_tx_handlers[];
 void ieee80211_clear_tx_pending(struct ieee80211_local *local);
 void ieee80211_tx_pending(unsigned long data);
 int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev);
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 92f1eb2da311..80954a512185 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -15,6 +15,7 @@
 #include "ieee80211_i.h"
 #include "sta_info.h"
 #include "debugfs_netdev.h"
+#include "mesh.h"
 
 void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
 {
@@ -39,7 +40,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
 
 /* Must be called with rtnl lock held. */
 int ieee80211_if_add(struct net_device *dev, const char *name,
-		     struct net_device **new_dev, int type)
+		     struct net_device **new_dev, int type,
+		     struct vif_params *params)
 {
 	struct net_device *ndev;
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -78,6 +80,12 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
 	ieee80211_debugfs_add_netdev(sdata);
 	ieee80211_if_set_type(ndev, type);
 
+	if (ieee80211_vif_is_mesh(&sdata->vif) &&
+	    params && params->mesh_id_len)
+		ieee80211_if_sta_set_mesh_id(&sdata->u.sta,
+					     params->mesh_id_len,
+					     params->mesh_id);
+
 	/* we're under RTNL so all this is fine */
 	if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
 		__ieee80211_if_del(local, sdata);
@@ -118,6 +126,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 	sdata->bss = NULL;
 	sdata->vif.type = type;
 
+	sdata->basic_rates = 0;
+
 	switch (type) {
 	case IEEE80211_IF_TYPE_WDS:
 		/* nothing special */
@@ -132,6 +142,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 		sdata->bss = &sdata->u.ap;
 		INIT_LIST_HEAD(&sdata->u.ap.vlans);
 		break;
+	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS: {
 		struct ieee80211_sub_if_data *msdata;
@@ -153,15 +164,20 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
 
 		msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
 		sdata->bss = &msdata->u.ap;
+
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			ieee80211_mesh_init_sdata(sdata);
 		break;
 	}
 	case IEEE80211_IF_TYPE_MNTR:
 		dev->type = ARPHRD_IEEE80211_RADIOTAP;
 		dev->hard_start_xmit = ieee80211_monitor_start_xmit;
+		sdata->u.mntr_flags = MONITOR_FLAG_CONTROL |
+				      MONITOR_FLAG_OTHER_BSS;
 		break;
 	default:
 		printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
-		       dev->name, __FUNCTION__, type);
+		       dev->name, __func__, type);
 	}
 	ieee80211_debugfs_change_if_type(sdata, oldtype);
 }
@@ -171,8 +187,8 @@ void ieee80211_if_reinit(struct net_device *dev)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct sta_info *sta;
 	struct sk_buff *skb;
+	int flushed;
 
 	ASSERT_RTNL();
 
@@ -180,6 +196,10 @@ void ieee80211_if_reinit(struct net_device *dev)
 
 	ieee80211_if_sdata_deinit(sdata);
 
+	/* Need to handle mesh specially to allow eliding the function call */
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		mesh_rmc_free(dev);
+
 	switch (sdata->vif.type) {
 	case IEEE80211_IF_TYPE_INVALID:
 		/* cannot happen */
@@ -189,6 +209,7 @@ void ieee80211_if_reinit(struct net_device *dev)
 		/* Remove all virtual interfaces that use this BSS
 		 * as their sdata->bss */
 		struct ieee80211_sub_if_data *tsdata, *n;
+		struct beacon_data *beacon;
 
 		list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
 			if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
@@ -206,7 +227,10 @@ void ieee80211_if_reinit(struct net_device *dev)
 			}
 		}
 
-		kfree(sdata->u.ap.beacon);
+		beacon = sdata->u.ap.beacon;
+		rcu_assign_pointer(sdata->u.ap.beacon, NULL);
+		synchronize_rcu();
+		kfree(beacon);
 
 		while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
 			local->total_ps_buffered--;
@@ -216,17 +240,9 @@ void ieee80211_if_reinit(struct net_device *dev)
 		break;
 	}
 	case IEEE80211_IF_TYPE_WDS:
-		sta = sta_info_get(local, sdata->u.wds.remote_addr);
-		if (sta) {
-			sta_info_free(sta);
-			sta_info_put(sta);
-		} else {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			printk(KERN_DEBUG "%s: Someone had deleted my STA "
-			       "entry for the WDS link\n", dev->name);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-		}
+		/* nothing to do */
 		break;
+	case IEEE80211_IF_TYPE_MESH_POINT:
 	case IEEE80211_IF_TYPE_STA:
 	case IEEE80211_IF_TYPE_IBSS:
 		kfree(sdata->u.sta.extra_ie);
@@ -249,8 +265,8 @@ void ieee80211_if_reinit(struct net_device *dev)
 		break;
 	}
 
-	/* remove all STAs that are bound to this virtual interface */
-	sta_info_flush(local, dev);
+	flushed = sta_info_flush(local, sdata);
+	WARN_ON(flushed);
 
 	memset(&sdata->u, 0, sizeof(sdata->u));
 	ieee80211_if_sdata_init(sdata);
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 5024d3733834..b047eebb6330 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -33,7 +33,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
 				    size_t key_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	int ret = 0;
 	struct sta_info *sta;
 	struct ieee80211_key *key;
 	struct ieee80211_sub_if_data *sdata;
@@ -46,59 +45,52 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
 		return -EINVAL;
 	}
 
-	if (is_broadcast_ether_addr(sta_addr)) {
-		sta = NULL;
-		key = sdata->keys[idx];
-	} else {
-		set_tx_key = 0;
-		/*
-		 * According to the standard, the key index of a pairwise
-		 * key must be zero. However, some AP are broken when it
-		 * comes to WEP key indices, so we work around this.
-		 */
-		if (idx != 0 && alg != ALG_WEP) {
-			printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
-			       "individual key\n", dev->name);
-			return -EINVAL;
+	if (remove) {
+		if (is_broadcast_ether_addr(sta_addr)) {
+			key = sdata->keys[idx];
+		} else {
+			sta = sta_info_get(local, sta_addr);
+			if (!sta)
+				return -ENOENT;
+			key = sta->key;
 		}
 
-		sta = sta_info_get(local, sta_addr);
-		if (!sta) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			DECLARE_MAC_BUF(mac);
-			printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
-			       "%s\n",
-			       dev->name, print_mac(mac, sta_addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+		ieee80211_key_free(key);
+		return 0;
+	} else {
+		key = ieee80211_key_alloc(alg, idx, key_len, _key);
+		if (!key)
+			return -ENOMEM;
 
-			return -ENOENT;
-		}
+		sta = NULL;
 
-		key = sta->key;
-	}
+		if (!is_broadcast_ether_addr(sta_addr)) {
+			set_tx_key = 0;
+			/*
+			 * According to the standard, the key index of a
+			 * pairwise key must be zero. However, some AP are
+			 * broken when it comes to WEP key indices, so we
+			 * work around this.
+			 */
+			if (idx != 0 && alg != ALG_WEP) {
+				ieee80211_key_free(key);
+				return -EINVAL;
+			}
 
-	if (remove) {
-		ieee80211_key_free(key);
-		key = NULL;
-	} else {
-		/*
-		 * Automatically frees any old key if present.
-		 */
-		key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
-		if (!key) {
-			ret = -ENOMEM;
-			goto err_out;
+			sta = sta_info_get(local, sta_addr);
+			if (!sta) {
+				ieee80211_key_free(key);
+				return -ENOENT;
+			}
 		}
-	}
 
-	if (set_tx_key || (!sta && !sdata->default_key && key))
-		ieee80211_set_default_key(sdata, idx);
+		ieee80211_key_link(key, sdata, sta);
 
-	ret = 0;
- err_out:
-	if (sta)
-		sta_info_put(sta);
-	return ret;
+		if (set_tx_key || (!sta && !sdata->default_key && key))
+			ieee80211_set_default_key(sdata, idx);
+	}
+
+	return 0;
 }
 
 static int ieee80211_ioctl_siwgenie(struct net_device *dev,
@@ -129,22 +121,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev,
 				   struct iw_request_info *info,
 				   char *name, char *extra)
 {
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
-	switch (local->hw.conf.phymode) {
-	case MODE_IEEE80211A:
-		strcpy(name, "IEEE 802.11a");
-		break;
-	case MODE_IEEE80211B:
-		strcpy(name, "IEEE 802.11b");
-		break;
-	case MODE_IEEE80211G:
-		strcpy(name, "IEEE 802.11g");
-		break;
-	default:
-		strcpy(name, "IEEE 802.11");
-		break;
-	}
+	strcpy(name, "IEEE 802.11");
 
 	return 0;
 }
@@ -156,7 +133,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct iw_range *range = (struct iw_range *) extra;
-	struct ieee80211_hw_mode *mode = NULL;
+	enum ieee80211_band band;
 	int c = 0;
 
 	data->length = sizeof(struct iw_range);
@@ -191,24 +168,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
 	range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
 			  IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
 
-	list_for_each_entry(mode, &local->modes_list, list) {
-		int i = 0;
 
-		if (!(local->enabled_modes & (1 << mode->mode)) ||
-		    (local->hw_modes & local->enabled_modes &
-		     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+	for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+		int i;
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[band];
+
+		if (!sband)
 			continue;
 
-		while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
-			struct ieee80211_channel *chan = &mode->channels[i];
+		for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
+			struct ieee80211_channel *chan = &sband->channels[i];
 
-			if (chan->flag & IEEE80211_CHAN_W_SCAN) {
-				range->freq[c].i = chan->chan;
-				range->freq[c].m = chan->freq * 100000;
-				range->freq[c].e = 1;
+			if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
+				range->freq[c].i =
+					ieee80211_frequency_to_channel(
+						chan->center_freq);
+				range->freq[c].m = chan->center_freq;
+				range->freq[c].e = 6;
 				c++;
 			}
-			i++;
 		}
 	}
 	range->num_channels = c;
@@ -294,31 +274,17 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev,
 	return 0;
 }
 
-int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz)
 {
-	struct ieee80211_hw_mode *mode;
-	int c, set = 0;
 	int ret = -EINVAL;
+	struct ieee80211_channel *chan;
 
-	list_for_each_entry(mode, &local->modes_list, list) {
-		if (!(local->enabled_modes & (1 << mode->mode)))
-			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct ieee80211_channel *chan = &mode->channels[c];
-			if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-			    ((chan->chan == channel) || (chan->freq == freq))) {
-				local->oper_channel = chan;
-				local->oper_hw_mode = mode;
-				set = 1;
-				break;
-			}
-		}
-		if (set)
-			break;
-	}
+	chan = ieee80211_get_channel(local->hw.wiphy, freqMHz);
+
+	if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+		local->oper_channel = chan;
 
-	if (set) {
-		if (local->sta_sw_scanning)
+		if (local->sta_sw_scanning || local->sta_hw_scanning)
 			ret = 0;
 		else
 			ret = ieee80211_hw_config(local);
@@ -347,13 +313,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
 					IEEE80211_STA_AUTO_CHANNEL_SEL;
 			return 0;
 		} else
-			return ieee80211_set_channel(local, freq->m, -1);
+			return ieee80211_set_freq(local,
+				ieee80211_channel_to_frequency(freq->m));
 	} else {
 		int i, div = 1000000;
 		for (i = 0; i < freq->e; i++)
 			div /= 10;
 		if (div > 0)
-			return ieee80211_set_channel(local, -1, freq->m / div);
+			return ieee80211_set_freq(local, freq->m / div);
 		else
 			return -EINVAL;
 	}
@@ -366,10 +333,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
-	/* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
-	 * driver for the current channel with firmware-based management */
-
-	freq->m = local->hw.conf.freq;
+	freq->m = local->hw.conf.channel->center_freq;
 	freq->e = 6;
 
 	return 0;
@@ -480,10 +444,20 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
 		ieee80211_sta_req_auth(dev, &sdata->u.sta);
 		return 0;
 	} else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) {
-		if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
-			   ETH_ALEN) == 0)
-			return 0;
-		return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
+		/*
+		 * If it is necessary to update the WDS peer address
+		 * while the interface is running, then we need to do
+		 * more work here, namely if it is running we need to
+		 * add a new and remove the old STA entry, this is
+		 * normally handled by _open() and _stop().
+		 */
+		if (netif_running(dev))
+			return -EBUSY;
+
+		memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
+		       ETH_ALEN);
+
+		return 0;
 	}
 
 	return -EOPNOTSUPP;
@@ -526,6 +500,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev,
 
 	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
 	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT &&
 	    sdata->vif.type != IEEE80211_IF_TYPE_AP)
 		return -EOPNOTSUPP;
 
@@ -566,15 +541,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 				  struct iw_param *rate, char *extra)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
-	int i;
+	int i, err = -EINVAL;
 	u32 target_rate = rate->value / 100000;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (!sdata->bss)
 		return -ENODEV;
-	mode = local->oper_hw_mode;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
 	 * target_rate = X, rate->fixed = 1 means only rate X
 	 * target_rate = X, rate->fixed = 0 means all rates <= X */
@@ -582,18 +559,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev,
 	sdata->bss->force_unicast_rateidx = -1;
 	if (rate->value < 0)
 		return 0;
-	for (i=0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rates = &mode->rates[i];
-		int this_rate = rates->rate;
+
+	for (i=0; i< sband->n_bitrates; i++) {
+		struct ieee80211_rate *brate = &sband->bitrates[i];
+		int this_rate = brate->bitrate;
 
 		if (target_rate == this_rate) {
 			sdata->bss->max_ratectrl_rateidx = i;
 			if (rate->fixed)
 				sdata->bss->force_unicast_rateidx = i;
-			return 0;
+			err = 0;
+			break;
 		}
 	}
-	return -EINVAL;
+	return err;
 }
 
 static int ieee80211_ioctl_giwrate(struct net_device *dev,
@@ -603,19 +582,25 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
 	if (sdata->vif.type == IEEE80211_IF_TYPE_STA)
 		sta = sta_info_get(local, sdata->u.sta.bssid);
 	else
 		return -EOPNOTSUPP;
 	if (!sta)
 		return -ENODEV;
-	if (sta->txrate < local->oper_hw_mode->num_rates)
-		rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	if (sta->txrate_idx < sband->n_bitrates)
+		rate->value = sband->bitrates[sta->txrate_idx].bitrate;
 	else
 		rate->value = 0;
-	sta_info_put(sta);
+	rate->value *= 100000;
+
 	return 0;
 }
 
@@ -625,7 +610,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	bool need_reconfig = 0;
-	u8 new_power_level;
+	int new_power_level;
 
 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
 		return -EINVAL;
@@ -635,13 +620,15 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
 	if (data->txpower.fixed) {
 		new_power_level = data->txpower.value;
 	} else {
-		/* Automatic power level. Get the px power from the current
-		 * channel. */
-		struct ieee80211_channel* chan = local->oper_channel;
+		/*
+		 * Automatic power level. Use maximum power for the current
+		 * channel. Should be part of rate control.
+		 */
+		struct ieee80211_channel* chan = local->hw.conf.channel;
 		if (!chan)
 			return -EINVAL;
 
-		new_power_level = chan->power_level;
+		new_power_level = chan->max_power;
 	}
 
 	if (local->hw.conf.power_level != new_power_level) {
@@ -988,7 +975,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
 		wstats->qual.qual = sta->last_signal;
 		wstats->qual.noise = sta->last_noise;
 		wstats->qual.updated = local->wstats_flags;
-		sta_info_put(sta);
 	}
 	return wstats;
 }
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h
index fc770e98d47b..d670e6dbfa39 100644
--- a/net/mac80211/ieee80211_key.h
+++ b/net/mac80211/ieee80211_key.h
@@ -13,6 +13,7 @@
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/crypto.h>
+#include <linux/rcupdate.h>
 #include <net/mac80211.h>
 
 /* ALG_TKIP
@@ -45,7 +46,19 @@ struct ieee80211_local;
 struct ieee80211_sub_if_data;
 struct sta_info;
 
-#define KEY_FLAG_UPLOADED_TO_HARDWARE	(1<<0)
+/**
+ * enum ieee80211_internal_key_flags - internal key flags
+ *
+ * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
+ *	in the hardware for TX crypto hardware acceleration.
+ * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this
+ *	key is present in the hardware (but it cannot be used for
+ *	hardware acceleration any more!)
+ */
+enum ieee80211_internal_key_flags {
+	KEY_FLAG_UPLOADED_TO_HARDWARE	= BIT(0),
+	KEY_FLAG_REMOVE_FROM_HARDWARE	= BIT(1),
+};
 
 struct ieee80211_key {
 	struct ieee80211_local *local;
@@ -112,12 +125,17 @@ struct ieee80211_key {
 	struct ieee80211_key_conf conf;
 };
 
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-					  struct sta_info *sta,
-					  enum ieee80211_key_alg alg,
+struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
 					  int idx,
 					  size_t key_len,
 					  const u8 *key_data);
+/*
+ * Insert a key into data structures (sdata, sta if necessary)
+ * to make it used, free old key.
+ */
+void ieee80211_key_link(struct ieee80211_key *key,
+			struct ieee80211_sub_if_data *sdata,
+			struct sta_info *sta);
 void ieee80211_key_free(struct ieee80211_key *key);
 void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx);
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c
index b957e67c5fba..4de06f128d90 100644
--- a/net/mac80211/ieee80211_rate.c
+++ b/net/mac80211/ieee80211_rate.c
@@ -163,34 +163,37 @@ static void rate_control_release(struct kref *kref)
 }
 
 void rate_control_get_rate(struct net_device *dev,
-			   struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+			   struct ieee80211_supported_band *sband,
+			   struct sk_buff *skb,
 			   struct rate_selection *sel)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct rate_control_ref *ref = local->rate_ctrl;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct sta_info *sta = sta_info_get(local, hdr->addr1);
+	struct sta_info *sta;
 	int i;
 
+	rcu_read_lock();
+	sta = sta_info_get(local, hdr->addr1);
+
 	memset(sel, 0, sizeof(struct rate_selection));
 
-	ref->ops->get_rate(ref->priv, dev, mode, skb, sel);
+	ref->ops->get_rate(ref->priv, dev, sband, skb, sel);
 
 	/* Select a non-ERP backup rate. */
 	if (!sel->nonerp) {
-		for (i = 0; i < mode->num_rates - 1; i++) {
-			struct ieee80211_rate *rate = &mode->rates[i];
-			if (sel->rate->rate < rate->rate)
+		for (i = 0; i < sband->n_bitrates; i++) {
+			struct ieee80211_rate *rate = &sband->bitrates[i];
+			if (sel->rate->bitrate < rate->bitrate)
 				break;
 
-			if (rate_supported(sta, mode, i) &&
-			    !(rate->flags & IEEE80211_RATE_ERP))
+			if (rate_supported(sta, sband->band, i) &&
+			    !(rate->flags & IEEE80211_RATE_ERP_G))
 				sel->nonerp = rate;
 		}
 	}
 
-	if (sta)
-		sta_info_put(sta);
+	rcu_read_unlock();
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h
index 73f19e8aa51c..5b45f33cb766 100644
--- a/net/mac80211/ieee80211_rate.h
+++ b/net/mac80211/ieee80211_rate.h
@@ -14,10 +14,12 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/types.h>
+#include <linux/kref.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
+/* TODO: kdoc */
 struct rate_selection {
 	/* Selected transmission rate */
 	struct ieee80211_rate *rate;
@@ -34,7 +36,8 @@ struct rate_control_ops {
 			  struct sk_buff *skb,
 			  struct ieee80211_tx_status *status);
 	void (*get_rate)(void *priv, struct net_device *dev,
-			 struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+			 struct ieee80211_supported_band *band,
+			 struct sk_buff *skb,
 			 struct rate_selection *sel);
 	void (*rate_init)(void *priv, void *priv_sta,
 			  struct ieee80211_local *local, struct sta_info *sta);
@@ -66,7 +69,8 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
 struct rate_control_ref *rate_control_alloc(const char *name,
 					    struct ieee80211_local *local);
 void rate_control_get_rate(struct net_device *dev,
-			   struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+			   struct ieee80211_supported_band *sband,
+			   struct sk_buff *skb,
 			   struct rate_selection *sel);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
@@ -127,23 +131,23 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 #endif
 }
 
-static inline int
-rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index)
+static inline int rate_supported(struct sta_info *sta,
+				 enum ieee80211_band band,
+				 int index)
 {
-	return (sta == NULL || sta->supp_rates & BIT(index)) &&
-	       (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED);
+	return (sta == NULL || sta->supp_rates[band] & BIT(index));
 }
 
 static inline int
-rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+rate_lowest_index(struct ieee80211_local *local,
+		  struct ieee80211_supported_band *sband,
 		  struct sta_info *sta)
 {
 	int i;
 
-	for (i = 0; i < mode->num_rates; i++) {
-		if (rate_supported(sta, mode, i))
+	for (i = 0; i < sband->n_bitrates; i++)
+		if (rate_supported(sta, sband->band, i))
 			return i;
-	}
 
 	/* warn when we cannot find a rate. */
 	WARN_ON(1);
@@ -152,10 +156,11 @@ rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
 }
 
 static inline struct ieee80211_rate *
-rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+rate_lowest(struct ieee80211_local *local,
+	    struct ieee80211_supported_band *sband,
 	    struct sta_info *sta)
 {
-	return &mode->rates[rate_lowest_index(local, mode, sta)];
+	return &sband->bitrates[rate_lowest_index(local, sband, sta)];
 }
 
 
@@ -166,21 +171,6 @@ void rate_control_deinitialize(struct ieee80211_local *local);
 
 
 /* Rate control algorithms */
-#if defined(RC80211_SIMPLE_COMPILE) || \
-	(defined(CONFIG_MAC80211_RC_SIMPLE) && \
-	 !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE))
-extern int rc80211_simple_init(void);
-extern void rc80211_simple_exit(void);
-#else
-static inline int rc80211_simple_init(void)
-{
-	return 0;
-}
-static inline void rc80211_simple_exit(void)
-{
-}
-#endif
-
 #if defined(RC80211_PID_COMPILE) || \
 	(defined(CONFIG_MAC80211_RC_PID) && \
 	 !defined(CONFIG_MAC80211_RC_PID_MODULE))
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index e0c72d04584b..c20ef89acad6 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -24,19 +24,23 @@
 #include <linux/wireless.h>
 #include <linux/random.h>
 #include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
 #include <net/iw_handler.h>
 #include <asm/types.h>
+#include <asm/unaligned.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "ieee80211_led.h"
+#include "mesh.h"
 
 #define IEEE80211_AUTH_TIMEOUT (HZ / 5)
 #define IEEE80211_AUTH_MAX_TRIES 3
 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
 #define IEEE80211_ASSOC_MAX_TRIES 3
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
+#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ)
 #define IEEE80211_PROBE_INTERVAL (60 * HZ)
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
 #define IEEE80211_SCAN_INTERVAL (2 * HZ)
@@ -49,6 +53,7 @@
 #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
 #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
 #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ)
 
 #define IEEE80211_IBSS_MAX_STA_ENTRIES 128
 
@@ -74,7 +79,7 @@
 static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 				     u8 *ssid, size_t ssid_len);
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len);
 static void ieee80211_rx_bss_put(struct net_device *dev,
 				 struct ieee80211_sta_bss *bss);
@@ -87,46 +92,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta);
 
 
-/* Parsed Information Elements */
-struct ieee802_11_elems {
-	/* pointers to IEs */
-	u8 *ssid;
-	u8 *supp_rates;
-	u8 *fh_params;
-	u8 *ds_params;
-	u8 *cf_params;
-	u8 *tim;
-	u8 *ibss_params;
-	u8 *challenge;
-	u8 *wpa;
-	u8 *rsn;
-	u8 *erp_info;
-	u8 *ext_supp_rates;
-	u8 *wmm_info;
-	u8 *wmm_param;
-	u8 *ht_cap_elem;
-	u8 *ht_info_elem;
-	/* length of them, respectively */
-	u8 ssid_len;
-	u8 supp_rates_len;
-	u8 fh_params_len;
-	u8 ds_params_len;
-	u8 cf_params_len;
-	u8 tim_len;
-	u8 ibss_params_len;
-	u8 challenge_len;
-	u8 wpa_len;
-	u8 rsn_len;
-	u8 erp_info_len;
-	u8 ext_supp_rates_len;
-	u8 wmm_info_len;
-	u8 wmm_param_len;
-	u8 ht_cap_elem_len;
-	u8 ht_info_elem_len;
-};
-
-static void ieee802_11_parse_elems(u8 *start, size_t len,
-				   struct ieee802_11_elems *elems)
+void ieee802_11_parse_elems(u8 *start, size_t len,
+			    struct ieee802_11_elems *elems)
 {
 	size_t left = len;
 	u8 *pos = start;
@@ -215,6 +182,30 @@ static void ieee802_11_parse_elems(u8 *start, size_t len,
 			elems->ht_info_elem = pos;
 			elems->ht_info_elem_len = elen;
 			break;
+		case WLAN_EID_MESH_ID:
+			elems->mesh_id = pos;
+			elems->mesh_id_len = elen;
+			break;
+		case WLAN_EID_MESH_CONFIG:
+			elems->mesh_config = pos;
+			elems->mesh_config_len = elen;
+			break;
+		case WLAN_EID_PEER_LINK:
+			elems->peer_link = pos;
+			elems->peer_link_len = elen;
+			break;
+		case WLAN_EID_PREQ:
+			elems->preq = pos;
+			elems->preq_len = elen;
+			break;
+		case WLAN_EID_PREP:
+			elems->prep = pos;
+			elems->prep_len = elen;
+			break;
+		case WLAN_EID_PERR:
+			elems->perr = pos;
+			elems->perr_len = elen;
+			break;
 		default:
 			break;
 		}
@@ -227,12 +218,61 @@ static void ieee802_11_parse_elems(u8 *start, size_t len,
 
 static int ecw2cw(int ecw)
 {
-	int cw = 1;
-	while (ecw > 0) {
-		cw <<= 1;
-		ecw--;
+	return (1 << ecw) - 1;
+}
+
+
+static void ieee80211_sta_def_wmm_params(struct net_device *dev,
+					 struct ieee80211_sta_bss *bss,
+					 int ibss)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	int i, have_higher_than_11mbit = 0;
+
+
+	/* cf. IEEE 802.11 9.2.12 */
+	for (i = 0; i < bss->supp_rates_len; i++)
+		if ((bss->supp_rates[i] & 0x7f) * 5 > 110)
+			have_higher_than_11mbit = 1;
+
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+	    have_higher_than_11mbit)
+		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+	else
+		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+
+	if (local->ops->conf_tx) {
+		struct ieee80211_tx_queue_params qparam;
+
+		memset(&qparam, 0, sizeof(qparam));
+
+		qparam.aifs = 2;
+
+		if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+		    !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
+			qparam.cw_min = 31;
+		else
+			qparam.cw_min = 15;
+
+		qparam.cw_max = 1023;
+		qparam.txop = 0;
+
+		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
+			local->ops->conf_tx(local_to_hw(local),
+					   i + IEEE80211_TX_QUEUE_DATA0,
+					   &qparam);
+
+		if (ibss) {
+			/* IBSS uses different parameters for Beacon sending */
+			qparam.cw_min++;
+			qparam.cw_min *= 2;
+			qparam.cw_min--;
+			local->ops->conf_tx(local_to_hw(local),
+					   IEEE80211_TX_QUEUE_BEACON, &qparam);
+		}
 	}
-	return cw - 1;
 }
 
 static void ieee80211_sta_wmm_params(struct net_device *dev,
@@ -297,12 +337,13 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
 		params.aifs = pos[0] & 0x0f;
 		params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
 		params.cw_min = ecw2cw(pos[1] & 0x0f);
-		/* TXOP is in units of 32 usec; burst_time in 0.1 ms */
-		params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+		params.txop = pos[2] | (pos[3] << 8);
+#ifdef CONFIG_MAC80211_DEBUG
 		printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
-		       "cWmin=%d cWmax=%d burst=%d\n",
+		       "cWmin=%d cWmax=%d txop=%d\n",
 		       dev->name, queue, aci, acm, params.aifs, params.cw_min,
-		       params.cw_max, params.burst_time);
+		       params.cw_max, params.txop);
+#endif
 		/* TODO: handle ACM (block TX, fallback to next lowest allowed
 		 * AC for now) */
 		if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
@@ -465,7 +506,7 @@ static void ieee80211_set_associated(struct net_device *dev,
 			return;
 
 		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-					   local->hw.conf.channel,
+					   local->hw.conf.channel->center_freq,
 					   ifsta->ssid, ifsta->ssid_len);
 		if (bss) {
 			if (bss->has_erp_value)
@@ -480,8 +521,8 @@ static void ieee80211_set_associated(struct net_device *dev,
 		memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
 		ieee80211_sta_send_associnfo(dev, ifsta);
 	} else {
+		ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid);
 		ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-
 		netif_carrier_off(dev);
 		ieee80211_reset_erp_info(dev);
 		memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
@@ -491,6 +532,7 @@ static void ieee80211_set_associated(struct net_device *dev,
 	ifsta->last_probe = jiffies;
 	ieee80211_led_assoc(local, assoc);
 
+	sdata->bss_conf.assoc = assoc;
 	ieee80211_bss_info_change_notify(sdata, changed);
 }
 
@@ -503,8 +545,8 @@ static void ieee80211_set_disassoc(struct net_device *dev,
 	ieee80211_set_associated(dev, ifsta, 0);
 }
 
-static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
-			     int encrypt)
+void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+		      int encrypt)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_tx_packet_data *pkt_data;
@@ -591,7 +633,6 @@ static void ieee80211_send_assoc(struct net_device *dev,
 				 struct ieee80211_if_sta *ifsta)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, *ies;
@@ -599,6 +640,7 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	u16 capab;
 	struct ieee80211_sta_bss *bss;
 	int wmm = 0;
+	struct ieee80211_supported_band *sband;
 
 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
 			    sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
@@ -610,13 +652,19 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	}
 	skb_reserve(skb, local->hw.extra_tx_headroom);
 
-	mode = local->oper_hw_mode;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	capab = ifsta->capab;
-	if (mode->mode == MODE_IEEE80211G) {
-		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-			WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+		if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE))
+			capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
 	}
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+				   local->hw.conf.channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (bss) {
 		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
@@ -655,23 +703,23 @@ static void ieee80211_send_assoc(struct net_device *dev,
 	*pos++ = ifsta->ssid_len;
 	memcpy(pos, ifsta->ssid, ifsta->ssid_len);
 
-	len = mode->num_rates;
+	len = sband->n_bitrates;
 	if (len > 8)
 		len = 8;
 	pos = skb_put(skb, len + 2);
 	*pos++ = WLAN_EID_SUPP_RATES;
 	*pos++ = len;
 	for (i = 0; i < len; i++) {
-		int rate = mode->rates[i].rate;
+		int rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
-	if (mode->num_rates > len) {
-		pos = skb_put(skb, mode->num_rates - len + 2);
+	if (sband->n_bitrates > len) {
+		pos = skb_put(skb, sband->n_bitrates - len + 2);
 		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = mode->num_rates - len;
-		for (i = len; i < mode->num_rates; i++) {
-			int rate = mode->rates[i].rate;
+		*pos++ = sband->n_bitrates - len;
+		for (i = len; i < sband->n_bitrates; i++) {
+			int rate = sband->bitrates[i].bitrate;
 			*pos++ = (u8) (rate / 5);
 		}
 	}
@@ -694,17 +742,18 @@ static void ieee80211_send_assoc(struct net_device *dev,
 		*pos++ = 0;
 	}
 	/* wmm support is a must to HT */
-	if (wmm && mode->ht_info.ht_supported) {
-		__le16 tmp = cpu_to_le16(mode->ht_info.cap);
+	if (wmm && sband->ht_info.ht_supported) {
+		__le16 tmp = cpu_to_le16(sband->ht_info.cap);
 		pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2);
 		*pos++ = WLAN_EID_HT_CAPABILITY;
 		*pos++ = sizeof(struct ieee80211_ht_cap);
 		memset(pos, 0, sizeof(struct ieee80211_ht_cap));
 		memcpy(pos, &tmp, sizeof(u16));
 		pos += sizeof(u16);
-		*pos++ = (mode->ht_info.ampdu_factor |
-				(mode->ht_info.ampdu_density << 2));
-		memcpy(pos, mode->ht_info.supp_mcs_set, 16);
+		/* TODO: needs a define here for << 2 */
+		*pos++ = sband->ht_info.ampdu_factor |
+			 (sband->ht_info.ampdu_density << 2);
+		memcpy(pos, sband->ht_info.supp_mcs_set, 16);
 	}
 
 	kfree(ifsta->assocreq_ies);
@@ -787,7 +836,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev,
 	if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
 		return 0;
 
-	bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel,
+	bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
+				   local->hw.conf.channel->center_freq,
 				   ifsta->ssid, ifsta->ssid_len);
 	if (!bss)
 		return 0;
@@ -850,6 +900,8 @@ static void ieee80211_associated(struct net_device *dev,
 
 	ifsta->state = IEEE80211_ASSOCIATED;
 
+	rcu_read_lock();
+
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
 		printk(KERN_DEBUG "%s: No STA entry for own AP %s\n",
@@ -865,7 +917,7 @@ static void ieee80211_associated(struct net_device *dev,
 				       "range\n",
 				       dev->name, print_mac(mac, ifsta->bssid));
 				disassoc = 1;
-				sta_info_free(sta);
+				sta_info_unlink(&sta);
 			} else
 				ieee80211_send_probe_req(dev, ifsta->bssid,
 							 local->scan_ssid,
@@ -881,8 +933,16 @@ static void ieee80211_associated(struct net_device *dev,
 							 ifsta->ssid_len);
 			}
 		}
-		sta_info_put(sta);
 	}
+
+	rcu_read_unlock();
+
+	if (disassoc && sta) {
+		rtnl_lock();
+		sta_info_destroy(sta);
+		rtnl_unlock();
+	}
+
 	if (disassoc) {
 		ifsta->state = IEEE80211_DISABLED;
 		ieee80211_set_associated(dev, ifsta, 0);
@@ -897,7 +957,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 				     u8 *ssid, size_t ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	struct sk_buff *skb;
 	struct ieee80211_mgmt *mgmt;
 	u8 *pos, *supp_rates, *esupp_rates = NULL;
@@ -931,11 +991,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 	supp_rates = skb_put(skb, 2);
 	supp_rates[0] = WLAN_EID_SUPP_RATES;
 	supp_rates[1] = 0;
-	mode = local->oper_hw_mode;
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-		if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
-			continue;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct ieee80211_rate *rate = &sband->bitrates[i];
 		if (esupp_rates) {
 			pos = skb_put(skb, 1);
 			esupp_rates[1]++;
@@ -948,7 +1007,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
 			pos = skb_put(skb, 1);
 			supp_rates[1]++;
 		}
-		*pos = rate->rate / 5;
+		*pos = rate->bitrate / 5;
 	}
 
 	ieee80211_sta_tx(dev, skb, 0);
@@ -1043,6 +1102,58 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid,
 	return;
 }
 
+void ieee80211_send_addba_request(struct net_device *dev, const u8 *da,
+				u16 tid, u8 dialog_token, u16 start_seq_num,
+				u16 agg_size, u16 timeout)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	u16 capab;
+
+	skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 +
+				sizeof(mgmt->u.action.u.addba_req));
+
+
+	if (!skb) {
+		printk(KERN_ERR "%s: failed to allocate buffer "
+				"for addba request frame\n", dev->name);
+		return;
+	}
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+	memset(mgmt, 0, 24);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP)
+		memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN);
+	else
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					IEEE80211_STYPE_ACTION);
+
+	skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req));
+
+	mgmt->u.action.category = WLAN_CATEGORY_BACK;
+	mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ;
+
+	mgmt->u.action.u.addba_req.dialog_token = dialog_token;
+	capab = (u16)(1 << 1);		/* bit 1 aggregation policy */
+	capab |= (u16)(tid << 2); 	/* bit 5:2 TID number */
+	capab |= (u16)(agg_size << 6);	/* bit 15:6 max size of aggergation */
+
+	mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab);
+
+	mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout);
+	mgmt->u.action.u.addba_req.start_seq_num =
+					cpu_to_le16(start_seq_num << 4);
+
+	ieee80211_sta_tx(dev, skb, 0);
+}
+
 static void ieee80211_sta_process_addba_request(struct net_device *dev,
 						struct ieee80211_mgmt *mgmt,
 						size_t len)
@@ -1057,9 +1168,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 	int ret = -EOPNOTSUPP;
 	DECLARE_MAC_BUF(mac);
 
+	rcu_read_lock();
+
 	sta = sta_info_get(local, mgmt->sa);
-	if (!sta)
+	if (!sta) {
+		rcu_read_unlock();
 		return;
+	}
 
 	/* extract session parameters from addba request frame */
 	dialog_token = mgmt->u.action.u.addba_req.dialog_token;
@@ -1083,7 +1198,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 		status = WLAN_STATUS_INVALID_QOS_PARAM;
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
-			printk(KERN_DEBUG "Block Ack Req with bad params from "
+			printk(KERN_DEBUG "AddBA Req with bad params from "
 				"%s on tid %u. policy %d, buffer size %d\n",
 				print_mac(mac, mgmt->sa), tid, ba_policy,
 				buf_size);
@@ -1092,26 +1207,45 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 	}
 	/* determine default buffer size */
 	if (buf_size == 0) {
-		struct ieee80211_hw_mode *mode = conf->mode;
+		struct ieee80211_supported_band *sband;
+
+		sband = local->hw.wiphy->bands[conf->channel->band];
 		buf_size = IEEE80211_MIN_AMPDU_BUF;
-		buf_size = buf_size << mode->ht_info.ampdu_factor;
+		buf_size = buf_size << sband->ht_info.ampdu_factor;
 	}
 
-	tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid];
 
 	/* examine state machine */
 	spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
 
-	if (tid_agg_rx->state != HT_AGG_STATE_IDLE) {
+	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
 		if (net_ratelimit())
-			printk(KERN_DEBUG "unexpected Block Ack Req from "
+			printk(KERN_DEBUG "unexpected AddBA Req from "
 				"%s on tid %u\n",
 				print_mac(mac, mgmt->sa), tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 		goto end;
 	}
 
+	/* prepare A-MPDU MLME for Rx aggregation */
+	sta->ampdu_mlme.tid_rx[tid] =
+			kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+	if (!sta->ampdu_mlme.tid_rx[tid]) {
+		if (net_ratelimit())
+			printk(KERN_ERR "allocate rx mlme to tid %d failed\n",
+					tid);
+		goto end;
+	}
+	/* rx timer */
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.function =
+				sta_rx_agg_session_timer_expired;
+	sta->ampdu_mlme.tid_rx[tid]->session_timer.data =
+				(unsigned long)&sta->timer_to_tid[tid];
+	init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
+
+	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
 	/* prepare reordering buffer */
 	tid_agg_rx->reorder_buf =
 		kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC);
@@ -1119,6 +1253,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 		if (net_ratelimit())
 			printk(KERN_ERR "can not allocate reordering buffer "
 			       "to tid %d\n", tid);
+		kfree(sta->ampdu_mlme.tid_rx[tid]);
 		goto end;
 	}
 	memset(tid_agg_rx->reorder_buf, 0,
@@ -1126,18 +1261,20 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev,
 
 	if (local->ops->ampdu_action)
 		ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START,
-					       sta->addr, tid, start_seq_num);
+					       sta->addr, tid, &start_seq_num);
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	if (ret) {
 		kfree(tid_agg_rx->reorder_buf);
+		kfree(tid_agg_rx);
+		sta->ampdu_mlme.tid_rx[tid] = NULL;
 		goto end;
 	}
 
 	/* change state and send addba resp */
-	tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL;
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL;
 	tid_agg_rx->dialog_token = dialog_token;
 	tid_agg_rx->ssn = start_seq_num;
 	tid_agg_rx->head_seq_num = start_seq_num;
@@ -1149,13 +1286,89 @@ end:
 	spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
 
 end_no_lock:
-	ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token,
-				status, 1, buf_size, timeout);
-	sta_info_put(sta);
+	ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid,
+				  dialog_token, status, 1, buf_size, timeout);
+	rcu_read_unlock();
 }
 
-static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
-				 u16 initiator, u16 reason_code)
+static void ieee80211_sta_process_addba_resp(struct net_device *dev,
+					     struct ieee80211_mgmt *mgmt,
+					     size_t len)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	u16 capab;
+	u16 tid;
+	u8 *state;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab);
+	tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:"
+			"%d\n", *state);
+		goto addba_resp_exit;
+	}
+
+	if (mgmt->u.action.u.addba_resp.dialog_token !=
+		sta->ampdu_mlme.tid_tx[tid]->dialog_token) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+		printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+		goto addba_resp_exit;
+	}
+
+	del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
+	printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+	if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
+			== WLAN_STATUS_SUCCESS) {
+		if (*state & HT_ADDBA_RECEIVED_MSK)
+			printk(KERN_DEBUG "double addBA response\n");
+
+		*state |= HT_ADDBA_RECEIVED_MSK;
+		sta->ampdu_mlme.addba_req_num[tid] = 0;
+
+		if (*state == HT_AGG_STATE_OPERATIONAL) {
+			printk(KERN_DEBUG "Aggregation on for tid %d \n", tid);
+			ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+		}
+
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid);
+	} else {
+		printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid);
+
+		sta->ampdu_mlme.addba_req_num[tid]++;
+		/* this will allow the state check in stop_BA_session */
+		*state = HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		ieee80211_stop_tx_ba_session(hw, sta->addr, tid,
+					     WLAN_BACK_INITIATOR);
+	}
+
+addba_resp_exit:
+	rcu_read_unlock();
+}
+
+void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid,
+			  u16 initiator, u16 reason_code)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -1206,19 +1419,23 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
 	struct sta_info *sta;
 	int ret, i;
 
+	rcu_read_lock();
+
 	sta = sta_info_get(local, ra);
-	if (!sta)
+	if (!sta) {
+		rcu_read_unlock();
 		return;
+	}
 
 	/* check if TID is in operational state */
 	spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
-	if (sta->ampdu_mlme.tid_rx[tid].state
+	if (sta->ampdu_mlme.tid_state_rx[tid]
 				!= HT_AGG_STATE_OPERATIONAL) {
 		spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
-		sta_info_put(sta);
+		rcu_read_unlock();
 		return;
 	}
-	sta->ampdu_mlme.tid_rx[tid].state =
+	sta->ampdu_mlme.tid_state_rx[tid] =
 		HT_AGG_STATE_REQ_STOP_BA_MSK |
 		(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 		spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
@@ -1228,35 +1445,38 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid,
 	BUG_ON(!local->ops->ampdu_action);
 
 	ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP,
-					ra, tid, EINVAL);
+					ra, tid, NULL);
 	if (ret)
 		printk(KERN_DEBUG "HW problem - can not stop rx "
 				"aggergation for tid %d\n", tid);
 
 	/* shutdown timer has not expired */
 	if (initiator != WLAN_BACK_TIMER)
-		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid].
-					session_timer);
+		del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer);
 
 	/* check if this is a self generated aggregation halt */
 	if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER)
 		ieee80211_send_delba(dev, ra, tid, 0, reason);
 
 	/* free the reordering buffer */
-	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) {
-		if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) {
+	for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) {
+		if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) {
 			/* release the reordered frames */
-			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]);
-			sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--;
-			sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL;
+			dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]);
+			sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--;
+			sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL;
 		}
 	}
-	kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf);
+	/* free resources */
+	kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf);
+	kfree(sta->ampdu_mlme.tid_rx[tid]);
+	sta->ampdu_mlme.tid_rx[tid] = NULL;
+	sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE;
 
-	sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE;
-	sta_info_put(sta);
+	rcu_read_unlock();
 }
 
+
 static void ieee80211_sta_process_delba(struct net_device *dev,
 			struct ieee80211_mgmt *mgmt, size_t len)
 {
@@ -1266,9 +1486,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
 	u16 initiator;
 	DECLARE_MAC_BUF(mac);
 
+	rcu_read_lock();
+
 	sta = sta_info_get(local, mgmt->sa);
-	if (!sta)
+	if (!sta) {
+		rcu_read_unlock();
 		return;
+	}
 
 	params = le16_to_cpu(mgmt->u.action.u.delba.params);
 	tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12;
@@ -1276,27 +1500,87 @@ static void ieee80211_sta_process_delba(struct net_device *dev,
 
 #ifdef CONFIG_MAC80211_HT_DEBUG
 	if (net_ratelimit())
-		printk(KERN_DEBUG "delba from %s on tid %d reason code %d\n",
-			print_mac(mac, mgmt->sa), tid,
+		printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n",
+			print_mac(mac, mgmt->sa),
+			initiator ? "initiator" : "recipient", tid,
 			mgmt->u.action.u.delba.reason_code);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
 	if (initiator == WLAN_BACK_INITIATOR)
 		ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid,
 						 WLAN_BACK_INITIATOR, 0);
-	sta_info_put(sta);
+	else { /* WLAN_BACK_RECIPIENT */
+		spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+		sta->ampdu_mlme.tid_state_tx[tid] =
+				HT_AGG_STATE_OPERATIONAL;
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid,
+					     WLAN_BACK_RECIPIENT);
+	}
+	rcu_read_unlock();
+}
+
+/*
+ * After sending add Block Ack request we activated a timer until
+ * add Block Ack response will arrive from the recipient.
+ * If this timer expires sta_addba_resp_timer_expired will be executed.
+ */
+void sta_addba_resp_timer_expired(unsigned long data)
+{
+	/* not an elegant detour, but there is no choice as the timer passes
+	 * only one argument, and both sta_info and TID are needed, so init
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
+	 * array gives the sta through container_of */
+	u16 tid = *(int *)data;
+	struct sta_info *temp_sta = container_of((void *)data,
+		struct sta_info, timer_to_tid[tid]);
+
+	struct ieee80211_local *local = temp_sta->local;
+	struct ieee80211_hw *hw = &local->hw;
+	struct sta_info *sta;
+	u8 *state;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, temp_sta->addr);
+	if (!sta) {
+		rcu_read_unlock();
+		return;
+	}
+
+	state = &sta->ampdu_mlme.tid_state_tx[tid];
+	/* check if the TID waits for addBA response */
+	spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+	if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+		*state = HT_AGG_STATE_IDLE;
+		printk(KERN_DEBUG "timer expired on tid %d but we are not "
+				"expecting addBA response there", tid);
+		goto timer_expired_exit;
+	}
+
+	printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid);
+
+	/* go through the state check in stop_BA_session */
+	*state = HT_AGG_STATE_OPERATIONAL;
+	spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+	ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid,
+				     WLAN_BACK_INITIATOR);
+
+timer_expired_exit:
+	rcu_read_unlock();
 }
 
 /*
- * After receiving Block Ack Request (BAR) we activated a
- * timer after each frame arrives from the originator.
+ * After accepting the AddBA Request we activated a timer,
+ * resetting it after each frame that arrives from the originator.
  * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed.
  */
 void sta_rx_agg_session_timer_expired(unsigned long data)
 {
 	/* not an elegant detour, but there is no choice as the timer passes
 	 * only one argument, and verious sta_info are needed here, so init
-	 * flow in sta_info_add gives the TID as data, while the timer_to_id
+	 * flow in sta_info_create gives the TID as data, while the timer_to_id
 	 * array gives the sta through container_of */
 	u8 *ptid = (u8 *)data;
 	u8 *timer_to_id = ptid - *ptid;
@@ -1304,11 +1588,24 @@ void sta_rx_agg_session_timer_expired(unsigned long data)
 					 timer_to_tid[0]);
 
 	printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid);
-	ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid,
-					 WLAN_BACK_TIMER,
+	ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
+					 (u16)*ptid, WLAN_BACK_TIMER,
 					 WLAN_REASON_QSTA_TIMEOUT);
 }
 
+void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int i;
+
+	for (i = 0; i <  STA_TID_NUM; i++) {
+		ieee80211_stop_tx_ba_session(&local->hw, addr, i,
+					     WLAN_BACK_INITIATOR);
+		ieee80211_sta_stop_rx_ba_session(dev, addr, i,
+						 WLAN_BACK_RECIPIENT,
+						 WLAN_REASON_QSTA_LEAVE_QBSS);
+	}
+}
 
 static void ieee80211_rx_mgmt_auth(struct net_device *dev,
 				   struct ieee80211_if_sta *ifsta,
@@ -1535,15 +1832,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 {
 	struct ieee80211_local *local = sdata->local;
 	struct net_device *dev = sdata->dev;
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	struct sta_info *sta;
-	u32 rates;
+	u64 rates, basic_rates;
 	u16 capab_info, status_code, aid;
 	struct ieee802_11_elems elems;
 	struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf;
 	u8 *pos;
 	int i, j;
 	DECLARE_MAC_BUF(mac);
+	bool have_higher_than_11mbit = false;
 
 	/* AssocResp and ReassocResp have identical structure, so process both
 	 * of them in this function. */
@@ -1613,22 +1911,23 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 	if (ifsta->assocresp_ies)
 		memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
 
-	/* set AID, ieee80211_set_associated() will tell the driver */
-	bss_conf->aid = aid;
-	ieee80211_set_associated(dev, ifsta, 1);
+	rcu_read_lock();
 
 	/* Add STA entry for the AP */
 	sta = sta_info_get(local, ifsta->bssid);
 	if (!sta) {
 		struct ieee80211_sta_bss *bss;
-		sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL);
+		int err;
+
+		sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
 		if (!sta) {
-			printk(KERN_DEBUG "%s: failed to add STA entry for the"
-			       " AP\n", dev->name);
+			printk(KERN_DEBUG "%s: failed to alloc STA entry for"
+			       " the AP\n", dev->name);
+			rcu_read_unlock();
 			return;
 		}
 		bss = ieee80211_rx_bss_get(dev, ifsta->bssid,
-					   local->hw.conf.channel,
+					   local->hw.conf.channel->center_freq,
 					   ifsta->ssid, ifsta->ssid_len);
 		if (bss) {
 			sta->last_rssi = bss->rssi;
@@ -1636,26 +1935,70 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 			sta->last_noise = bss->noise;
 			ieee80211_rx_bss_put(dev, bss);
 		}
+
+		err = sta_info_insert(sta);
+		if (err) {
+			printk(KERN_DEBUG "%s: failed to insert STA entry for"
+			       " the AP (error %d)\n", dev->name, err);
+			rcu_read_unlock();
+			return;
+		}
 	}
 
-	sta->dev = dev;
-	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP;
+	/*
+	 * FIXME: Do we really need to update the sta_info's information here?
+	 *	  We already know about the AP (we found it in our list) so it
+	 *	  should already be filled with the right info, no?
+	 *	  As is stands, all this is racy because typically we assume
+	 *	  the information that is filled in here (except flags) doesn't
+	 *	  change while a STA structure is alive. As such, it should move
+	 *	  to between the sta_info_alloc() and sta_info_insert() above.
+	 */
+
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
+		      WLAN_STA_AUTHORIZED;
 
 	rates = 0;
-	mode = local->oper_hw_mode;
+	basic_rates = 0;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	for (i = 0; i < elems.supp_rates_len; i++) {
 		int rate = (elems.supp_rates[i] & 0x7f) * 5;
-		for (j = 0; j < mode->num_rates; j++)
-			if (mode->rates[j].rate == rate)
+
+		if (rate > 110)
+			have_higher_than_11mbit = true;
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate)
 				rates |= BIT(j);
+			if (elems.supp_rates[i] & 0x80)
+				basic_rates |= BIT(j);
+		}
 	}
+
 	for (i = 0; i < elems.ext_supp_rates_len; i++) {
 		int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-		for (j = 0; j < mode->num_rates; j++)
-			if (mode->rates[j].rate == rate)
+
+		if (rate > 110)
+			have_higher_than_11mbit = true;
+
+		for (j = 0; j < sband->n_bitrates; j++) {
+			if (sband->bitrates[j].bitrate == rate)
 				rates |= BIT(j);
+			if (elems.ext_supp_rates[i] & 0x80)
+				basic_rates |= BIT(j);
+		}
 	}
-	sta->supp_rates = rates;
+
+	sta->supp_rates[local->hw.conf.channel->band] = rates;
+	sdata->basic_rates = basic_rates;
+
+	/* cf. IEEE 802.11 9.2.12 */
+	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+	    have_higher_than_11mbit)
+		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+	else
+		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
 	if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
 	    local->ops->conf_ht) {
@@ -1674,12 +2017,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
 	if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
 		sta->flags |= WLAN_STA_WME;
+		rcu_read_unlock();
 		ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
 					 elems.wmm_param_len);
-	}
-
+	} else
+		rcu_read_unlock();
 
-	sta_info_put(sta);
+	/* set AID, ieee80211_set_associated() will tell the driver */
+	bss_conf->aid = aid;
+	ieee80211_set_associated(dev, ifsta, 1);
 
 	ieee80211_associated(dev, ifsta);
 }
@@ -1690,8 +2036,16 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
 					struct ieee80211_sta_bss *bss)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)];
-	local->sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+	u8 hash_idx;
+
+	if (bss_mesh_cfg(bss))
+		hash_idx = mesh_id_hash(bss_mesh_id(bss),
+					bss_mesh_id_len(bss));
+	else
+		hash_idx = STA_HASH(bss->bssid);
+
+	bss->hnext = local->sta_bss_hash[hash_idx];
+	local->sta_bss_hash[hash_idx] = bss;
 }
 
 
@@ -1718,7 +2072,7 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
 
 
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -1730,7 +2084,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
 	atomic_inc(&bss->users);
 	atomic_inc(&bss->users);
 	memcpy(bss->bssid, bssid, ETH_ALEN);
-	bss->channel = channel;
+	bss->freq = freq;
 	if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) {
 		memcpy(bss->ssid, ssid, ssid_len);
 		bss->ssid_len = ssid_len;
@@ -1744,9 +2098,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel,
 	return bss;
 }
 
-
 static struct ieee80211_sta_bss *
-ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq,
 		     u8 *ssid, u8 ssid_len)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
@@ -1755,8 +2108,9 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
 	spin_lock_bh(&local->sta_bss_lock);
 	bss = local->sta_bss_hash[STA_HASH(bssid)];
 	while (bss) {
-		if (!memcmp(bss->bssid, bssid, ETH_ALEN) &&
-		    bss->channel == channel &&
+		if (!bss_mesh_cfg(bss) &&
+		    !memcmp(bss->bssid, bssid, ETH_ALEN) &&
+		    bss->freq == freq &&
 		    bss->ssid_len == ssid_len &&
 		    (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) {
 			atomic_inc(&bss->users);
@@ -1768,6 +2122,85 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel,
 	return bss;
 }
 
+#ifdef CONFIG_MAC80211_MESH
+static inline u32 bss_mesh_cfg_get(u8 *mesh_cfg, u8 offset)
+{
+	return be32_to_cpu(get_unaligned((__be32 *) (mesh_cfg + offset)));
+}
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+			  u8 *mesh_cfg, int freq)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+
+	spin_lock_bh(&local->sta_bss_lock);
+	bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)];
+	while (bss) {
+		if (bss_mesh_cfg(bss) &&
+		    !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) &&
+		    bss->freq == freq &&
+		    mesh_id_len == bss->mesh_id_len &&
+		    (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id,
+						 mesh_id_len))) {
+			atomic_inc(&bss->users);
+			break;
+		}
+		bss = bss->hnext;
+	}
+	spin_unlock_bh(&local->sta_bss_lock);
+	return bss;
+}
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len,
+			  u8 *mesh_cfg, int mesh_config_len, int freq)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sta_bss *bss;
+
+	if (mesh_config_len != MESH_CFG_LEN)
+		return NULL;
+
+	bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
+	if (!bss)
+		return NULL;
+
+	bss->mesh_cfg = kmalloc(sizeof(struct bss_mesh_config), GFP_ATOMIC);
+	if (!bss->mesh_cfg) {
+		kfree(bss);
+		return NULL;
+	}
+
+	if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) {
+		bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC);
+		if (!bss->mesh_id) {
+			kfree(bss->mesh_cfg);
+			kfree(bss);
+			return NULL;
+		}
+		memcpy(bss->mesh_id, mesh_id, mesh_id_len);
+	}
+
+	atomic_inc(&bss->users);
+	atomic_inc(&bss->users);
+	bss->mesh_cfg->mesh_version = mesh_cfg[0];
+	bss->mesh_cfg->path_proto_id = bss_mesh_cfg_get(mesh_cfg, PP_OFFSET);
+	bss->mesh_cfg->path_metric_id = bss_mesh_cfg_get(mesh_cfg, PM_OFFSET);
+	bss->mesh_cfg->cong_control_id = bss_mesh_cfg_get(mesh_cfg, CC_OFFSET);
+	bss->mesh_cfg->channel_precedence = bss_mesh_cfg_get(mesh_cfg,
+							     CP_OFFSET);
+	bss->mesh_id_len = mesh_id_len;
+	bss->freq = freq;
+	spin_lock_bh(&local->sta_bss_lock);
+	/* TODO: order by RSSI? */
+	list_add_tail(&bss->list, &local->sta_bss_list);
+	__ieee80211_rx_bss_hash_add(dev, bss);
+	spin_unlock_bh(&local->sta_bss_lock);
+	return bss;
+}
+#endif
 
 static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 {
@@ -1775,6 +2208,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
 	kfree(bss->rsn_ie);
 	kfree(bss->wmm_ie);
 	kfree(bss->ht_ie);
+	kfree(bss_mesh_id(bss));
+	kfree(bss_mesh_cfg(bss));
 	kfree(bss);
 }
 
@@ -1812,6 +2247,204 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev)
 }
 
 
+static int ieee80211_sta_join_ibss(struct net_device *dev,
+				   struct ieee80211_if_sta *ifsta,
+				   struct ieee80211_sta_bss *bss)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	int res, rates, i, j;
+	struct sk_buff *skb;
+	struct ieee80211_mgmt *mgmt;
+	struct ieee80211_tx_control control;
+	struct rate_selection ratesel;
+	u8 *pos;
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	/* Remove possible STA entries from other IBSS networks. */
+	sta_info_flush_delayed(sdata);
+
+	if (local->ops->reset_tsf) {
+		/* Reset own TSF to allow time synchronization work. */
+		local->ops->reset_tsf(local_to_hw(local));
+	}
+	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+	res = ieee80211_if_config(dev);
+	if (res)
+		return res;
+
+	local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+
+	sdata->drop_unencrypted = bss->capability &
+		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+	res = ieee80211_set_freq(local, bss->freq);
+
+	if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) {
+		printk(KERN_DEBUG "%s: IBSS not allowed on frequency "
+		       "%d MHz\n", dev->name, local->oper_channel->center_freq);
+		return -1;
+	}
+
+	/* Set beacon template */
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	do {
+		if (!skb)
+			break;
+
+		skb_reserve(skb, local->hw.extra_tx_headroom);
+
+		mgmt = (struct ieee80211_mgmt *)
+			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						   IEEE80211_STYPE_BEACON);
+		memset(mgmt->da, 0xff, ETH_ALEN);
+		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+		mgmt->u.beacon.beacon_int =
+			cpu_to_le16(local->hw.conf.beacon_int);
+		mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+
+		pos = skb_put(skb, 2 + ifsta->ssid_len);
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = ifsta->ssid_len;
+		memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+		rates = bss->supp_rates_len;
+		if (rates > 8)
+			rates = 8;
+		pos = skb_put(skb, 2 + rates);
+		*pos++ = WLAN_EID_SUPP_RATES;
+		*pos++ = rates;
+		memcpy(pos, bss->supp_rates, rates);
+
+		if (bss->band == IEEE80211_BAND_2GHZ) {
+			pos = skb_put(skb, 2 + 1);
+			*pos++ = WLAN_EID_DS_PARAMS;
+			*pos++ = 1;
+			*pos++ = ieee80211_frequency_to_channel(bss->freq);
+		}
+
+		pos = skb_put(skb, 2 + 2);
+		*pos++ = WLAN_EID_IBSS_PARAMS;
+		*pos++ = 2;
+		/* FIX: set ATIM window based on scan results */
+		*pos++ = 0;
+		*pos++ = 0;
+
+		if (bss->supp_rates_len > 8) {
+			rates = bss->supp_rates_len - 8;
+			pos = skb_put(skb, 2 + rates);
+			*pos++ = WLAN_EID_EXT_SUPP_RATES;
+			*pos++ = rates;
+			memcpy(pos, &bss->supp_rates[8], rates);
+		}
+
+		memset(&control, 0, sizeof(control));
+		rate_control_get_rate(dev, sband, skb, &ratesel);
+		if (!ratesel.rate) {
+			printk(KERN_DEBUG "%s: Failed to determine TX rate "
+			       "for IBSS beacon\n", dev->name);
+			break;
+		}
+		control.vif = &sdata->vif;
+		control.tx_rate = ratesel.rate;
+		if (sdata->bss_conf.use_short_preamble &&
+		    ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+			control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
+		control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+		control.flags |= IEEE80211_TXCTL_NO_ACK;
+		control.retry_limit = 1;
+
+		ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
+		if (ifsta->probe_resp) {
+			mgmt = (struct ieee80211_mgmt *)
+				ifsta->probe_resp->data;
+			mgmt->frame_control =
+				IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					     IEEE80211_STYPE_PROBE_RESP);
+		} else {
+			printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
+			       "template for IBSS\n", dev->name);
+		}
+
+		if (local->ops->beacon_update &&
+		    local->ops->beacon_update(local_to_hw(local),
+					     skb, &control) == 0) {
+			printk(KERN_DEBUG "%s: Configured IBSS beacon "
+			       "template\n", dev->name);
+			skb = NULL;
+		}
+
+		rates = 0;
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+		for (i = 0; i < bss->supp_rates_len; i++) {
+			int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+			for (j = 0; j < sband->n_bitrates; j++)
+				if (sband->bitrates[j].bitrate == bitrate)
+					rates |= BIT(j);
+		}
+		ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
+
+		ieee80211_sta_def_wmm_params(dev, bss, 1);
+	} while (0);
+
+	if (skb) {
+		printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
+		       "template\n", dev->name);
+		dev_kfree_skb(skb);
+	}
+
+	ifsta->state = IEEE80211_IBSS_JOINED;
+	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+	ieee80211_rx_bss_put(dev, bss);
+
+	return res;
+}
+
+u64 ieee80211_sta_get_rates(struct ieee80211_local *local,
+			    struct ieee802_11_elems *elems,
+			    enum ieee80211_band band)
+{
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *bitrates;
+	size_t num_rates;
+	u64 supp_rates;
+	int i, j;
+	sband = local->hw.wiphy->bands[band];
+
+	if (!sband) {
+		WARN_ON(1);
+		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	}
+
+	bitrates = sband->bitrates;
+	num_rates = sband->n_bitrates;
+	supp_rates = 0;
+	for (i = 0; i < elems->supp_rates_len +
+		     elems->ext_supp_rates_len; i++) {
+		u8 rate = 0;
+		int own_rate;
+		if (i < elems->supp_rates_len)
+			rate = elems->supp_rates[i];
+		else if (elems->ext_supp_rates)
+			rate = elems->ext_supp_rates
+				[i - elems->supp_rates_len];
+		own_rate = 5 * (rate & 0x7f);
+		for (j = 0; j < num_rates; j++)
+			if (bitrates[j].bitrate == own_rate)
+				supp_rates |= BIT(j);
+	}
+	return supp_rates;
+}
+
+
 static void ieee80211_rx_bss_info(struct net_device *dev,
 				  struct ieee80211_mgmt *mgmt,
 				  size_t len,
@@ -1821,11 +2454,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee802_11_elems elems;
 	size_t baselen;
-	int channel, clen;
+	int freq, clen;
 	struct ieee80211_sta_bss *bss;
 	struct sta_info *sta;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	u64 timestamp;
+	u64 beacon_timestamp, rx_timestamp;
+	struct ieee80211_channel *channel;
 	DECLARE_MAC_BUF(mac);
 	DECLARE_MAC_BUF(mac2);
 
@@ -1842,104 +2476,77 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 	if (baselen > len)
 		return;
 
-	timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+	beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
 
-	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
-	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-		static unsigned long last_tsf_debug = 0;
-		u64 tsf;
-		if (local->ops->get_tsf)
-			tsf = local->ops->get_tsf(local_to_hw(local));
-		else
-			tsf = -1LLU;
-		if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-			printk(KERN_DEBUG "RX beacon SA=%s BSSID="
-			       "%s TSF=0x%llx BCN=0x%llx diff=%lld "
-			       "@%lu\n",
-			       print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid),
-			       (unsigned long long)tsf,
-			       (unsigned long long)timestamp,
-			       (unsigned long long)(tsf - timestamp),
-			       jiffies);
-			last_tsf_debug = jiffies;
-		}
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+	if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id &&
+	    elems.mesh_config && mesh_matches_local(&elems, dev)) {
+		u64 rates = ieee80211_sta_get_rates(local, &elems,
+						rx_status->band);
+
+		mesh_neighbour_update(mgmt->sa, rates, dev,
+				      mesh_peer_accepts_plinks(&elems, dev));
 	}
 
-	ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+	rcu_read_lock();
 
 	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
 	    memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
 	    (sta = sta_info_get(local, mgmt->sa))) {
-		struct ieee80211_hw_mode *mode;
-		struct ieee80211_rate *rates;
-		size_t num_rates;
-		u32 supp_rates, prev_rates;
-		int i, j;
-
-		mode = local->sta_sw_scanning ?
-		       local->scan_hw_mode : local->oper_hw_mode;
-
-		if (local->sta_hw_scanning) {
-			/* search for the correct mode matches the beacon */
-			list_for_each_entry(mode, &local->modes_list, list)
-				if (mode->mode == rx_status->phymode)
-					break;
-
-			if (mode == NULL)
-				mode = local->oper_hw_mode;
-		}
-		rates = mode->rates;
-		num_rates = mode->num_rates;
-
-		supp_rates = 0;
-		for (i = 0; i < elems.supp_rates_len +
-			     elems.ext_supp_rates_len; i++) {
-			u8 rate = 0;
-			int own_rate;
-			if (i < elems.supp_rates_len)
-				rate = elems.supp_rates[i];
-			else if (elems.ext_supp_rates)
-				rate = elems.ext_supp_rates
-					[i - elems.supp_rates_len];
-			own_rate = 5 * (rate & 0x7f);
-			for (j = 0; j < num_rates; j++)
-				if (rates[j].rate == own_rate)
-					supp_rates |= BIT(j);
-		}
+		u64 prev_rates;
+		u64 supp_rates = ieee80211_sta_get_rates(local, &elems,
+							rx_status->band);
 
-		prev_rates = sta->supp_rates;
-		sta->supp_rates &= supp_rates;
-		if (sta->supp_rates == 0) {
+		prev_rates = sta->supp_rates[rx_status->band];
+		sta->supp_rates[rx_status->band] &= supp_rates;
+		if (sta->supp_rates[rx_status->band] == 0) {
 			/* No matching rates - this should not really happen.
 			 * Make sure that at least one rate is marked
 			 * supported to avoid issues with TX rate ctrl. */
-			sta->supp_rates = sdata->u.sta.supp_rates_bits;
+			sta->supp_rates[rx_status->band] =
+				sdata->u.sta.supp_rates_bits[rx_status->band];
 		}
-		if (sta->supp_rates != prev_rates) {
+		if (sta->supp_rates[rx_status->band] != prev_rates) {
 			printk(KERN_DEBUG "%s: updated supp_rates set for "
-			       "%s based on beacon info (0x%x & 0x%x -> "
-			       "0x%x)\n",
-			       dev->name, print_mac(mac, sta->addr), prev_rates,
-			       supp_rates, sta->supp_rates);
+			       "%s based on beacon info (0x%llx & 0x%llx -> "
+			       "0x%llx)\n",
+			       dev->name, print_mac(mac, sta->addr),
+			       (unsigned long long) prev_rates,
+			       (unsigned long long) supp_rates,
+			       (unsigned long long) sta->supp_rates[rx_status->band]);
 		}
-		sta_info_put(sta);
 	}
 
-	if (!elems.ssid)
-		return;
+	rcu_read_unlock();
 
 	if (elems.ds_params && elems.ds_params_len == 1)
-		channel = elems.ds_params[0];
+		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
 	else
-		channel = rx_status->channel;
+		freq = rx_status->freq;
 
-	bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel,
-				   elems.ssid, elems.ssid_len);
-	if (!bss) {
-		bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel,
+	channel = ieee80211_get_channel(local->hw.wiphy, freq);
+
+	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+		return;
+
+#ifdef CONFIG_MAC80211_MESH
+	if (elems.mesh_config)
+		bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id,
+				elems.mesh_id_len, elems.mesh_config, freq);
+	else
+#endif
+		bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq,
 					   elems.ssid, elems.ssid_len);
+	if (!bss) {
+#ifdef CONFIG_MAC80211_MESH
+		if (elems.mesh_config)
+			bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id,
+				elems.mesh_id_len, elems.mesh_config,
+				elems.mesh_config_len, freq);
+		else
+#endif
+			bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq,
+						   elems.ssid, elems.ssid_len);
 		if (!bss)
 			return;
 	} else {
@@ -1951,8 +2558,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 #endif
 	}
 
-	if (bss->probe_resp && beacon) {
-		/* Do not allow beacon to override data from Probe Response. */
+	bss->band = rx_status->band;
+
+	if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	    bss->probe_resp && beacon) {
+		/* STA mode:
+		 * Do not allow beacon to override data from Probe Response. */
 		ieee80211_rx_bss_put(dev, bss);
 		return;
 	}
@@ -2049,27 +2660,69 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
 		bss->ht_ie_len = 0;
 	}
 
-	bss->hw_mode = rx_status->phymode;
-	bss->freq = rx_status->freq;
-	if (channel != rx_status->channel &&
-	    (bss->hw_mode == MODE_IEEE80211G ||
-	     bss->hw_mode == MODE_IEEE80211B) &&
-	    channel >= 1 && channel <= 14) {
-		static const int freq_list[] = {
-			2412, 2417, 2422, 2427, 2432, 2437, 2442,
-			2447, 2452, 2457, 2462, 2467, 2472, 2484
-		};
-		/* IEEE 802.11g/b mode can receive packets from neighboring
-		 * channels, so map the channel into frequency. */
-		bss->freq = freq_list[channel - 1];
-	}
-	bss->timestamp = timestamp;
+	bss->timestamp = beacon_timestamp;
 	bss->last_update = jiffies;
 	bss->rssi = rx_status->ssi;
 	bss->signal = rx_status->signal;
 	bss->noise = rx_status->noise;
 	if (!beacon)
 		bss->probe_resp++;
+
+	/* check if we need to merge IBSS */
+	if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon &&
+	    !local->sta_sw_scanning && !local->sta_hw_scanning &&
+	    bss->capability & WLAN_CAPABILITY_IBSS &&
+	    bss->freq == local->oper_channel->center_freq &&
+	    elems.ssid_len == sdata->u.sta.ssid_len &&
+	    memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) {
+		if (rx_status->flag & RX_FLAG_TSFT) {
+			/* in order for correct IBSS merging we need mactime
+			 *
+			 * since mactime is defined as the time the first data
+			 * symbol of the frame hits the PHY, and the timestamp
+			 * of the beacon is defined as "the time that the data
+			 * symbol containing the first bit of the timestamp is
+			 * transmitted to the PHY plus the transmitting STA’s
+			 * delays through its local PHY from the MAC-PHY
+			 * interface to its interface with the WM"
+			 * (802.11 11.1.2) - equals the time this bit arrives at
+			 * the receiver - we have to take into account the
+			 * offset between the two.
+			 * e.g: at 1 MBit that means mactime is 192 usec earlier
+			 * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
+			 */
+			int rate = local->hw.wiphy->bands[rx_status->band]->
+					bitrates[rx_status->rate_idx].bitrate;
+			rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+		} else if (local && local->ops && local->ops->get_tsf)
+			/* second best option: get current TSF */
+			rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+		else
+			/* can't merge without knowing the TSF */
+			rx_timestamp = -1LLU;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+		printk(KERN_DEBUG "RX beacon SA=%s BSSID="
+		       "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+		       print_mac(mac, mgmt->sa),
+		       print_mac(mac2, mgmt->bssid),
+		       (unsigned long long)rx_timestamp,
+		       (unsigned long long)beacon_timestamp,
+		       (unsigned long long)(rx_timestamp - beacon_timestamp),
+		       jiffies);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+		if (beacon_timestamp > rx_timestamp) {
+#ifndef CONFIG_MAC80211_IBSS_DEBUG
+			if (net_ratelimit())
+#endif
+				printk(KERN_DEBUG "%s: beacon TSF higher than "
+				       "local TSF - IBSS merge with BSSID %s\n",
+				       dev->name, print_mac(mac, mgmt->bssid));
+			ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss);
+			ieee80211_ibss_add_sta(dev, NULL,
+					       mgmt->bssid, mgmt->sa);
+		}
+	}
+
 	ieee80211_rx_bss_put(dev, bss);
 }
 
@@ -2220,8 +2873,11 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
 static void ieee80211_rx_mgmt_action(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta,
 				     struct ieee80211_mgmt *mgmt,
-				     size_t len)
+				     size_t len,
+				     struct ieee80211_rx_status *rx_status)
 {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
 	if (len < IEEE80211_MIN_ACTION_SIZE)
 		return;
 
@@ -2234,6 +2890,12 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
 				break;
 			ieee80211_sta_process_addba_request(dev, mgmt, len);
 			break;
+		case WLAN_ACTION_ADDBA_RESP:
+			if (len < (IEEE80211_MIN_ACTION_SIZE +
+				   sizeof(mgmt->u.action.u.addba_resp)))
+				break;
+			ieee80211_sta_process_addba_resp(dev, mgmt, len);
+			break;
 		case WLAN_ACTION_DELBA:
 			if (len < (IEEE80211_MIN_ACTION_SIZE +
 				   sizeof(mgmt->u.action.u.delba)))
@@ -2247,7 +2909,18 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev,
 			break;
 		}
 		break;
+	case PLINK_CATEGORY:
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			mesh_rx_plink_frame(dev, mgmt, len, rx_status);
+		break;
+	case MESH_PATH_SEL_CATEGORY:
+		if (ieee80211_vif_is_mesh(&sdata->vif))
+			mesh_rx_path_sel_frame(dev, mgmt, len);
+		break;
 	default:
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: Rx unknown action frame - "
+			"category=%d\n", dev->name, mgmt->u.action.category);
 		break;
 	}
 }
@@ -2274,13 +2947,13 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
 	case IEEE80211_STYPE_PROBE_REQ:
 	case IEEE80211_STYPE_PROBE_RESP:
 	case IEEE80211_STYPE_BEACON:
+	case IEEE80211_STYPE_ACTION:
 		memcpy(skb->cb, rx_status, sizeof(*rx_status));
 	case IEEE80211_STYPE_AUTH:
 	case IEEE80211_STYPE_ASSOC_RESP:
 	case IEEE80211_STYPE_REASSOC_RESP:
 	case IEEE80211_STYPE_DEAUTH:
 	case IEEE80211_STYPE_DISASSOC:
-	case IEEE80211_STYPE_ACTION:
 		skb_queue_tail(&ifsta->skb_queue, skb);
 		queue_work(local->hw.workqueue, &ifsta->work);
 		return;
@@ -2339,7 +3012,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
 		ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
 		break;
 	case IEEE80211_STYPE_ACTION:
-		ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len);
+		ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status);
 		break;
 	}
 
@@ -2347,7 +3020,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
 }
 
 
-ieee80211_txrx_result
+ieee80211_rx_result
 ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 		      struct ieee80211_rx_status *rx_status)
 {
@@ -2355,31 +3028,31 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
 	u16 fc;
 
 	if (skb->len < 2)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	mgmt = (struct ieee80211_mgmt *) skb->data;
 	fc = le16_to_cpu(mgmt->frame_control);
 
 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (skb->len < 24)
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 
 	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
 		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
 			ieee80211_rx_mgmt_probe_resp(dev, mgmt,
 						     skb->len, rx_status);
 			dev_kfree_skb(skb);
-			return TXRX_QUEUED;
+			return RX_QUEUED;
 		} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
 			ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
 						 rx_status);
 			dev_kfree_skb(skb);
-			return TXRX_QUEUED;
+			return RX_QUEUED;
 		}
 	}
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
@@ -2388,45 +3061,50 @@ static int ieee80211_sta_active_ibss(struct net_device *dev)
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	int active = 0;
 	struct sta_info *sta;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	rcu_read_lock();
 
-	read_lock_bh(&local->sta_lock);
-	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->dev == dev &&
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		if (sta->sdata == sdata &&
 		    time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
 			       jiffies)) {
 			active++;
 			break;
 		}
 	}
-	read_unlock_bh(&local->sta_lock);
+
+	rcu_read_unlock();
 
 	return active;
 }
 
 
-static void ieee80211_sta_expire(struct net_device *dev)
+static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time)
 {
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta, *tmp;
 	LIST_HEAD(tmp_list);
 	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
 
-	write_lock_bh(&local->sta_lock);
+	spin_lock_irqsave(&local->sta_lock, flags);
 	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
-		if (time_after(jiffies, sta->last_rx +
-			       IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+		if (time_after(jiffies, sta->last_rx + exp_time)) {
 			printk(KERN_DEBUG "%s: expiring inactive STA %s\n",
 			       dev->name, print_mac(mac, sta->addr));
-			__sta_info_get(sta);
-			sta_info_remove(sta);
-			list_add(&sta->list, &tmp_list);
+			__sta_info_unlink(&sta);
+			if (sta)
+				list_add(&sta->list, &tmp_list);
 		}
-	write_unlock_bh(&local->sta_lock);
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 
-	list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
-		sta_info_free(sta);
-		sta_info_put(sta);
-	}
+	synchronize_rcu();
+
+	rtnl_lock();
+	list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+		sta_info_destroy(sta);
+	rtnl_unlock();
 }
 
 
@@ -2435,7 +3113,7 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev,
 {
 	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
 
-	ieee80211_sta_expire(dev);
+	ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT);
 	if (ieee80211_sta_active_ibss(dev))
 		return;
 
@@ -2445,6 +3123,36 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev,
 }
 
 
+#ifdef CONFIG_MAC80211_MESH
+static void ieee80211_mesh_housekeeping(struct net_device *dev,
+			   struct ieee80211_if_sta *ifsta)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	bool free_plinks;
+
+	ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
+	mesh_path_expire(dev);
+
+	free_plinks = mesh_plink_availables(sdata);
+	if (free_plinks != sdata->u.sta.accepting_plinks)
+		ieee80211_if_config_beacon(dev);
+
+	mod_timer(&ifsta->timer, jiffies +
+			IEEE80211_MESH_HOUSEKEEPING_INTERVAL);
+}
+
+
+void ieee80211_start_mesh(struct net_device *dev)
+{
+	struct ieee80211_if_sta *ifsta;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	ifsta = &sdata->u.sta;
+	ifsta->state = IEEE80211_MESH_UP;
+	ieee80211_sta_timer((unsigned long)sdata);
+}
+#endif
+
+
 void ieee80211_sta_timer(unsigned long data)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -2456,7 +3164,6 @@ void ieee80211_sta_timer(unsigned long data)
 	queue_work(local->hw.workqueue, &ifsta->work);
 }
 
-
 void ieee80211_sta_work(struct work_struct *work)
 {
 	struct ieee80211_sub_if_data *sdata =
@@ -2473,7 +3180,8 @@ void ieee80211_sta_work(struct work_struct *work)
 		return;
 
 	if (sdata->vif.type != IEEE80211_IF_TYPE_STA &&
-	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS) {
+	    sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
+	    sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) {
 		printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
 		       "(type=%d)\n", dev->name, sdata->vif.type);
 		return;
@@ -2483,6 +3191,13 @@ void ieee80211_sta_work(struct work_struct *work)
 	while ((skb = skb_dequeue(&ifsta->skb_queue)))
 		ieee80211_sta_rx_queued_mgmt(dev, skb);
 
+#ifdef CONFIG_MAC80211_MESH
+	if (ifsta->preq_queue_len &&
+	    time_after(jiffies,
+		       ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval)))
+		mesh_path_start_discovery(dev);
+#endif
+
 	if (ifsta->state != IEEE80211_AUTHENTICATE &&
 	    ifsta->state != IEEE80211_ASSOCIATE &&
 	    test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
@@ -2518,6 +3233,11 @@ void ieee80211_sta_work(struct work_struct *work)
 	case IEEE80211_IBSS_JOINED:
 		ieee80211_sta_merge_ibss(dev, ifsta);
 		break;
+#ifdef CONFIG_MAC80211_MESH
+	case IEEE80211_MESH_UP:
+		ieee80211_mesh_housekeeping(dev, ifsta);
+		break;
+#endif
 	default:
 		printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
 		       ifsta->state);
@@ -2628,7 +3348,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 	}
 
 	spin_lock_bh(&local->sta_bss_lock);
-	freq = local->oper_channel->freq;
+	freq = local->oper_channel->center_freq;
 	list_for_each_entry(bss, &local->sta_bss_list, list) {
 		if (!(bss->capability & WLAN_CAPABILITY_ESS))
 			continue;
@@ -2659,11 +3379,12 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 	spin_unlock_bh(&local->sta_bss_lock);
 
 	if (selected) {
-		ieee80211_set_channel(local, -1, selected->freq);
+		ieee80211_set_freq(local, selected->freq);
 		if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
 			ieee80211_sta_set_ssid(dev, selected->ssid,
 					       selected->ssid_len);
 		ieee80211_sta_set_bssid(dev, selected->bssid);
+		ieee80211_sta_def_wmm_params(dev, selected, 0);
 		ieee80211_rx_bss_put(dev, selected);
 		ifsta->state = IEEE80211_AUTHENTICATE;
 		ieee80211_sta_reset_auth(dev, ifsta);
@@ -2683,162 +3404,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
 	return -1;
 }
 
-static int ieee80211_sta_join_ibss(struct net_device *dev,
-				   struct ieee80211_if_sta *ifsta,
-				   struct ieee80211_sta_bss *bss)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	int res, rates, i, j;
-	struct sk_buff *skb;
-	struct ieee80211_mgmt *mgmt;
-	struct ieee80211_tx_control control;
-	struct ieee80211_hw_mode *mode;
-	struct rate_selection ratesel;
-	u8 *pos;
-	struct ieee80211_sub_if_data *sdata;
-
-	/* Remove possible STA entries from other IBSS networks. */
-	sta_info_flush(local, NULL);
-
-	if (local->ops->reset_tsf) {
-		/* Reset own TSF to allow time synchronization work. */
-		local->ops->reset_tsf(local_to_hw(local));
-	}
-	memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
-	res = ieee80211_if_config(dev);
-	if (res)
-		return res;
-
-	local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	sdata->drop_unencrypted = bss->capability &
-		WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
-	res = ieee80211_set_channel(local, -1, bss->freq);
-
-	if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
-		printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
-		       "(%d MHz)\n", dev->name, local->hw.conf.channel,
-		       local->hw.conf.freq);
-		return -1;
-	}
-
-	/* Set beacon template based on scan results */
-	skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
-	do {
-		if (!skb)
-			break;
-
-		skb_reserve(skb, local->hw.extra_tx_headroom);
-
-		mgmt = (struct ieee80211_mgmt *)
-			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-						   IEEE80211_STYPE_BEACON);
-		memset(mgmt->da, 0xff, ETH_ALEN);
-		memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
-		memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-		mgmt->u.beacon.beacon_int =
-			cpu_to_le16(local->hw.conf.beacon_int);
-		mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
-
-		pos = skb_put(skb, 2 + ifsta->ssid_len);
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = ifsta->ssid_len;
-		memcpy(pos, ifsta->ssid, ifsta->ssid_len);
-
-		rates = bss->supp_rates_len;
-		if (rates > 8)
-			rates = 8;
-		pos = skb_put(skb, 2 + rates);
-		*pos++ = WLAN_EID_SUPP_RATES;
-		*pos++ = rates;
-		memcpy(pos, bss->supp_rates, rates);
-
-		pos = skb_put(skb, 2 + 1);
-		*pos++ = WLAN_EID_DS_PARAMS;
-		*pos++ = 1;
-		*pos++ = bss->channel;
-
-		pos = skb_put(skb, 2 + 2);
-		*pos++ = WLAN_EID_IBSS_PARAMS;
-		*pos++ = 2;
-		/* FIX: set ATIM window based on scan results */
-		*pos++ = 0;
-		*pos++ = 0;
-
-		if (bss->supp_rates_len > 8) {
-			rates = bss->supp_rates_len - 8;
-			pos = skb_put(skb, 2 + rates);
-			*pos++ = WLAN_EID_EXT_SUPP_RATES;
-			*pos++ = rates;
-			memcpy(pos, &bss->supp_rates[8], rates);
-		}
-
-		memset(&control, 0, sizeof(control));
-		rate_control_get_rate(dev, local->oper_hw_mode, skb, &ratesel);
-		if (!ratesel.rate) {
-			printk(KERN_DEBUG "%s: Failed to determine TX rate "
-			       "for IBSS beacon\n", dev->name);
-			break;
-		}
-		control.vif = &sdata->vif;
-		control.tx_rate =
-			(sdata->bss_conf.use_short_preamble &&
-			(ratesel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			ratesel.rate->val2 : ratesel.rate->val;
-		control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-		control.power_level = local->hw.conf.power_level;
-		control.flags |= IEEE80211_TXCTL_NO_ACK;
-		control.retry_limit = 1;
-
-		ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
-		if (ifsta->probe_resp) {
-			mgmt = (struct ieee80211_mgmt *)
-				ifsta->probe_resp->data;
-			mgmt->frame_control =
-				IEEE80211_FC(IEEE80211_FTYPE_MGMT,
-					     IEEE80211_STYPE_PROBE_RESP);
-		} else {
-			printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
-			       "template for IBSS\n", dev->name);
-		}
-
-		if (local->ops->beacon_update &&
-		    local->ops->beacon_update(local_to_hw(local),
-					     skb, &control) == 0) {
-			printk(KERN_DEBUG "%s: Configured IBSS beacon "
-			       "template based on scan results\n", dev->name);
-			skb = NULL;
-		}
-
-		rates = 0;
-		mode = local->oper_hw_mode;
-		for (i = 0; i < bss->supp_rates_len; i++) {
-			int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
-			for (j = 0; j < mode->num_rates; j++)
-				if (mode->rates[j].rate == bitrate)
-					rates |= BIT(j);
-		}
-		ifsta->supp_rates_bits = rates;
-	} while (0);
-
-	if (skb) {
-		printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
-		       "template\n", dev->name);
-		dev_kfree_skb(skb);
-	}
-
-	ifsta->state = IEEE80211_IBSS_JOINED;
-	mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
-
-	ieee80211_rx_bss_put(dev, bss);
-
-	return res;
-}
-
 
 static int ieee80211_sta_create_ibss(struct net_device *dev,
 				     struct ieee80211_if_sta *ifsta)
@@ -2846,7 +3411,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct ieee80211_sta_bss *bss;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	u8 bssid[ETH_ALEN], *pos;
 	int i;
 	DECLARE_MAC_BUF(mac);
@@ -2868,28 +3433,28 @@ static int ieee80211_sta_create_ibss(struct net_device *dev,
 	printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n",
 	       dev->name, print_mac(mac, bssid));
 
-	bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel,
+	bss = ieee80211_rx_bss_add(dev, bssid,
+				   local->hw.conf.channel->center_freq,
 				   sdata->u.sta.ssid, sdata->u.sta.ssid_len);
 	if (!bss)
 		return -ENOMEM;
 
-	mode = local->oper_hw_mode;
+	bss->band = local->hw.conf.channel->band;
+	sband = local->hw.wiphy->bands[bss->band];
 
 	if (local->hw.conf.beacon_int == 0)
-		local->hw.conf.beacon_int = 100;
+		local->hw.conf.beacon_int = 10000;
 	bss->beacon_int = local->hw.conf.beacon_int;
-	bss->hw_mode = local->hw.conf.phymode;
-	bss->freq = local->hw.conf.freq;
 	bss->last_update = jiffies;
 	bss->capability = WLAN_CAPABILITY_IBSS;
 	if (sdata->default_key) {
 		bss->capability |= WLAN_CAPABILITY_PRIVACY;
 	} else
 		sdata->drop_unencrypted = 0;
-	bss->supp_rates_len = mode->num_rates;
+	bss->supp_rates_len = sband->n_bitrates;
 	pos = bss->supp_rates;
-	for (i = 0; i < mode->num_rates; i++) {
-		int rate = mode->rates[i].rate;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		int rate = sband->bitrates[i].bitrate;
 		*pos++ = (u8) (rate / 5);
 	}
 
@@ -2938,7 +3503,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 	       "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid));
 #endif /* CONFIG_MAC80211_IBSS_DEBUG */
 	if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
-	    (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel,
+	    (bss = ieee80211_rx_bss_get(dev, bssid,
+					local->hw.conf.channel->center_freq,
 					ifsta->ssid, ifsta->ssid_len))) {
 		printk(KERN_DEBUG "%s: Selected IBSS BSSID %s"
 		       " based on configured SSID\n",
@@ -2966,13 +3532,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 		if (time_after(jiffies, ifsta->ibss_join_req +
 			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
 			if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
-			    local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+			    (!(local->oper_channel->flags &
+					IEEE80211_CHAN_NO_IBSS)))
 				return ieee80211_sta_create_ibss(dev, ifsta);
 			if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
-				printk(KERN_DEBUG "%s: IBSS not allowed on the"
-				       " configured channel %d (%d MHz)\n",
-				       dev->name, local->hw.conf.channel,
-				       local->hw.conf.freq);
+				printk(KERN_DEBUG "%s: IBSS not allowed on"
+				       " %d MHz\n", dev->name,
+				       local->hw.conf.channel->center_freq);
 			}
 
 			/* No IBSS found - decrease scan interval and continue
@@ -2991,41 +3557,12 @@ static int ieee80211_sta_find_ibss(struct net_device *dev,
 
 int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_if_sta *ifsta;
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 
 	if (len > IEEE80211_MAX_SSID_LEN)
 		return -EINVAL;
 
-	/* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
-	 * not defined. */
-	if (local->ops->conf_tx) {
-		struct ieee80211_tx_queue_params qparam;
-		int i;
-
-		memset(&qparam, 0, sizeof(qparam));
-		/* TODO: are these ok defaults for all hw_modes? */
-		qparam.aifs = 2;
-		qparam.cw_min =
-			local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
-		qparam.cw_max = 1023;
-		qparam.burst_time = 0;
-		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-		{
-			local->ops->conf_tx(local_to_hw(local),
-					   i + IEEE80211_TX_QUEUE_DATA0,
-					   &qparam);
-		}
-		/* IBSS uses different parameters for Beacon sending */
-		qparam.cw_min++;
-		qparam.cw_min *= 2;
-		qparam.cw_min--;
-		local->ops->conf_tx(local_to_hw(local),
-				   IEEE80211_TX_QUEUE_BEACON, &qparam);
-	}
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	ifsta = &sdata->u.sta;
 
 	if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
@@ -3117,6 +3654,13 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local,
 }
 
 
+static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
+{
+	if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+	    ieee80211_vif_is_mesh(&sdata->vif))
+		ieee80211_sta_timer((unsigned long)sdata);
+}
+
 void ieee80211_scan_completed(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -3130,6 +3674,15 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 
 	if (local->sta_hw_scanning) {
 		local->sta_hw_scanning = 0;
+		if (ieee80211_hw_config(local))
+			printk(KERN_DEBUG "%s: failed to restore operational "
+			       "channel after scan\n", dev->name);
+		/* Restart STA timer for HW scan case */
+		rcu_read_lock();
+		list_for_each_entry_rcu(sdata, &local->interfaces, list)
+			ieee80211_restart_sta_timer(sdata);
+		rcu_read_unlock();
+
 		goto done;
 	}
 
@@ -3156,11 +3709,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw)
 		if (sdata->dev == local->mdev)
 			continue;
 
-		if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
-			if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
-				ieee80211_send_nullfunc(local, sdata, 0);
-			ieee80211_sta_timer((unsigned long)sdata);
-		}
+		/* Tell AP we're back */
+		if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
+		    sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)
+			ieee80211_send_nullfunc(local, sdata, 0);
+
+		ieee80211_restart_sta_timer(sdata);
 
 		netif_wake_queue(sdata->dev);
 	}
@@ -3184,7 +3738,7 @@ void ieee80211_sta_scan_work(struct work_struct *work)
 		container_of(work, struct ieee80211_local, scan_work.work);
 	struct net_device *dev = local->scan_dev;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	struct ieee80211_channel *chan;
 	int skip;
 	unsigned long next_delay = 0;
@@ -3194,44 +3748,59 @@ void ieee80211_sta_scan_work(struct work_struct *work)
 
 	switch (local->scan_state) {
 	case SCAN_SET_CHANNEL:
-		mode = local->scan_hw_mode;
-		if (local->scan_hw_mode->list.next == &local->modes_list &&
-		    local->scan_channel_idx >= mode->num_channels) {
+		/*
+		 * Get current scan band. scan_band may be IEEE80211_NUM_BANDS
+		 * after we successfully scanned the last channel of the last
+		 * band (and the last band is supported by the hw)
+		 */
+		if (local->scan_band < IEEE80211_NUM_BANDS)
+			sband = local->hw.wiphy->bands[local->scan_band];
+		else
+			sband = NULL;
+
+		/*
+		 * If we are at an unsupported band and have more bands
+		 * left to scan, advance to the next supported one.
+		 */
+		while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) {
+			local->scan_band++;
+			sband = local->hw.wiphy->bands[local->scan_band];
+			local->scan_channel_idx = 0;
+		}
+
+		/* if no more bands/channels left, complete scan */
+		if (!sband || local->scan_channel_idx >= sband->n_channels) {
 			ieee80211_scan_completed(local_to_hw(local));
 			return;
 		}
-		skip = !(local->enabled_modes & (1 << mode->mode));
-		chan = &mode->channels[local->scan_channel_idx];
-		if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
+		skip = 0;
+		chan = &sband->channels[local->scan_channel_idx];
+
+		if (chan->flags & IEEE80211_CHAN_DISABLED ||
 		    (sdata->vif.type == IEEE80211_IF_TYPE_IBSS &&
-		     !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
-		    (local->hw_modes & local->enabled_modes &
-		     (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+		     chan->flags & IEEE80211_CHAN_NO_IBSS))
 			skip = 1;
 
 		if (!skip) {
-#if 0
-			printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
-			       dev->name, chan->chan, chan->freq);
-#endif
-
 			local->scan_channel = chan;
 			if (ieee80211_hw_config(local)) {
-				printk(KERN_DEBUG "%s: failed to set channel "
-				       "%d (%d MHz) for scan\n", dev->name,
-				       chan->chan, chan->freq);
+				printk(KERN_DEBUG "%s: failed to set freq to "
+				       "%d MHz for scan\n", dev->name,
+				       chan->center_freq);
 				skip = 1;
 			}
 		}
 
+		/* advance state machine to next channel/band */
 		local->scan_channel_idx++;
-		if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
-			if (local->scan_hw_mode->list.next != &local->modes_list) {
-				local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
-								 struct ieee80211_hw_mode,
-								 list);
-				local->scan_channel_idx = 0;
-			}
+		if (local->scan_channel_idx >= sband->n_channels) {
+			/*
+			 * scan_band may end up == IEEE80211_NUM_BANDS, but
+			 * we'll catch that case above and complete the scan
+			 * if that is the case.
+			 */
+			local->scan_band++;
+			local->scan_channel_idx = 0;
 		}
 
 		if (skip)
@@ -3242,13 +3811,14 @@ void ieee80211_sta_scan_work(struct work_struct *work)
 		local->scan_state = SCAN_SEND_PROBE;
 		break;
 	case SCAN_SEND_PROBE:
-		if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
-			ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
-						 local->scan_ssid_len);
-			next_delay = IEEE80211_CHANNEL_TIME;
-		} else
-			next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
 		local->scan_state = SCAN_SET_CHANNEL;
+
+		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+			break;
+		ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+					 local->scan_ssid_len);
+		next_delay = IEEE80211_CHANNEL_TIME;
 		break;
 	}
 
@@ -3323,10 +3893,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev,
 	} else
 		local->scan_ssid_len = 0;
 	local->scan_state = SCAN_SET_CHANNEL;
-	local->scan_hw_mode = list_entry(local->modes_list.next,
-					 struct ieee80211_hw_mode,
-					 list);
 	local->scan_channel_idx = 0;
+	local->scan_band = IEEE80211_BAND_2GHZ;
 	local->scan_dev = dev;
 
 	netif_tx_lock_bh(local->mdev);
@@ -3381,9 +3949,6 @@ ieee80211_sta_scan_result(struct net_device *dev,
 		       bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
 		return current_ev;
 
-	if (!(local->enabled_modes & (1 << bss->hw_mode)))
-		return current_ev;
-
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWAP;
 	iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
@@ -3393,15 +3958,25 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWESSID;
-	iwe.u.data.length = bss->ssid_len;
-	iwe.u.data.flags = 1;
-	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
-					  bss->ssid);
+	if (bss_mesh_cfg(bss)) {
+		iwe.u.data.length = bss_mesh_id_len(bss);
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  bss_mesh_id(bss));
+	} else {
+		iwe.u.data.length = bss->ssid_len;
+		iwe.u.data.flags = 1;
+		current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+						  bss->ssid);
+	}
 
-	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+	if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)
+	    || bss_mesh_cfg(bss)) {
 		memset(&iwe, 0, sizeof(iwe));
 		iwe.cmd = SIOCGIWMODE;
-		if (bss->capability & WLAN_CAPABILITY_ESS)
+		if (bss_mesh_cfg(bss))
+			iwe.u.mode = IW_MODE_MESH;
+		else if (bss->capability & WLAN_CAPABILITY_ESS)
 			iwe.u.mode = IW_MODE_MASTER;
 		else
 			iwe.u.mode = IW_MODE_ADHOC;
@@ -3411,12 +3986,15 @@ ieee80211_sta_scan_result(struct net_device *dev,
 
 	memset(&iwe, 0, sizeof(iwe));
 	iwe.cmd = SIOCGIWFREQ;
-	iwe.u.freq.m = bss->channel;
-	iwe.u.freq.e = 0;
+	iwe.u.freq.m = bss->freq;
+	iwe.u.freq.e = 6;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 					  IW_EV_FREQ_LEN);
-	iwe.u.freq.m = bss->freq * 100000;
-	iwe.u.freq.e = 1;
+
+	memset(&iwe, 0, sizeof(iwe));
+	iwe.cmd = SIOCGIWFREQ;
+	iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq);
+	iwe.u.freq.e = 0;
 	current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
 					  IW_EV_FREQ_LEN);
 
@@ -3487,6 +4065,42 @@ ieee80211_sta_scan_result(struct net_device *dev,
 		}
 	}
 
+	if (bss_mesh_cfg(bss)) {
+		char *buf;
+		struct bss_mesh_config *cfg = bss_mesh_cfg(bss);
+		buf = kmalloc(50, GFP_ATOMIC);
+		if (buf) {
+			memset(&iwe, 0, sizeof(iwe));
+			iwe.cmd = IWEVCUSTOM;
+			sprintf(buf, "Mesh network (version %d)",
+				cfg->mesh_version);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Protocol ID: "
+				"0x%08X", cfg->path_proto_id);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Path Selection Metric ID: "
+				"0x%08X", cfg->path_metric_id);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Congestion Control Mode ID: "
+				"0x%08X", cfg->cong_control_id);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			sprintf(buf, "Channel Precedence: "
+				"0x%08X", cfg->channel_precedence);
+			iwe.u.data.length = strlen(buf);
+			current_ev = iwe_stream_add_point(current_ev, end_buf,
+							  &iwe, buf);
+			kfree(buf);
+		}
+	}
+
 	return current_ev;
 }
 
@@ -3555,15 +4169,21 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
 	printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n",
 	       wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name);
 
-	sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
+	sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
 	if (!sta)
 		return NULL;
 
-	sta->supp_rates = sdata->u.sta.supp_rates_bits;
+	sta->flags |= WLAN_STA_AUTHORIZED;
+
+	sta->supp_rates[local->hw.conf.channel->band] =
+		sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band];
 
 	rate_control_rate_init(sta, local);
 
-	return sta; /* caller will call sta_info_put() */
+	if (sta_info_insert(sta))
+		return NULL;
+
+	return sta;
 }
 
 
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index ed57fb8e82fc..5df9e0cc009f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -13,14 +13,15 @@
 #include <linux/etherdevice.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
+#include <linux/rtnetlink.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "debugfs_key.h"
 #include "aes_ccm.h"
 
 
-/*
- * Key handling basics
+/**
+ * DOC: Key handling basics
  *
  * Key handling in mac80211 is done based on per-interface (sub_if_data)
  * keys and per-station keys. Since each station belongs to an interface,
@@ -34,6 +35,10 @@
  *
  * All operations here are called under RTNL so no extra locking is
  * required.
+ *
+ * NOTE: This code requires that sta info *destruction* is done under
+ *	 RTNL, otherwise it can try to access already freed STA structs
+ *	 when a STA key is being freed.
  */
 
 static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -68,6 +73,15 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 	if (!key->local->ops->set_key)
 		return;
 
+	/*
+	 * This makes sure that all pending flushes have
+	 * actually completed prior to uploading new key
+	 * material to the hardware. That is necessary to
+	 * avoid races between flushing STAs and adding
+	 * new keys for them.
+	 */
+	__ieee80211_run_pending_flush(key->local);
+
 	addr = get_mac_for_key(key);
 
 	ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY,
@@ -84,16 +98,25 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 		       key->conf.keyidx, print_mac(mac, addr), ret);
 }
 
+static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key)
+{
+	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+		key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+		key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE;
+	}
+}
+
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 {
 	const u8 *addr;
 	int ret;
 	DECLARE_MAC_BUF(mac);
 
-	if (!key->local->ops->set_key)
+	if (!key || !key->local->ops->set_key)
 		return;
 
-	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
+	    !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE))
 		return;
 
 	addr = get_mac_for_key(key);
@@ -108,12 +131,11 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 		       wiphy_name(key->local->hw.wiphy),
 		       key->conf.keyidx, print_mac(mac, addr), ret);
 
-	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+	key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE |
+			KEY_FLAG_REMOVE_FROM_HARDWARE);
 }
 
-struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
-					  struct sta_info *sta,
-					  enum ieee80211_key_alg alg,
+struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
 					  int idx,
 					  size_t key_len,
 					  const u8 *key_data)
@@ -137,10 +159,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 	key->conf.keyidx = idx;
 	key->conf.keylen = key_len;
 	memcpy(key->conf.key, key_data, key_len);
-
-	key->local = sdata->local;
-	key->sdata = sdata;
-	key->sta = sta;
+	INIT_LIST_HEAD(&key->list);
 
 	if (alg == ALG_CCMP) {
 		/*
@@ -154,13 +173,68 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
-	ieee80211_debugfs_key_add(key->local, key);
+	return key;
+}
 
-	/* remove key first */
-	if (sta)
-		ieee80211_key_free(sta->key);
-	else
-		ieee80211_key_free(sdata->keys[idx]);
+static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
+				    struct sta_info *sta,
+				    struct ieee80211_key *key,
+				    struct ieee80211_key *new)
+{
+	int idx, defkey;
+
+	if (new)
+		list_add(&new->list, &sdata->key_list);
+
+	if (sta) {
+		rcu_assign_pointer(sta->key, new);
+	} else {
+		WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx);
+
+		if (key)
+			idx = key->conf.keyidx;
+		else
+			idx = new->conf.keyidx;
+
+		defkey = key && sdata->default_key == key;
+
+		if (defkey && !new)
+			ieee80211_set_default_key(sdata, -1);
+
+		rcu_assign_pointer(sdata->keys[idx], new);
+		if (defkey && new)
+			ieee80211_set_default_key(sdata, new->conf.keyidx);
+	}
+
+	if (key) {
+		ieee80211_key_mark_hw_accel_off(key);
+		/*
+		 * We'll use an empty list to indicate that the key
+		 * has already been removed.
+		 */
+		list_del_init(&key->list);
+	}
+}
+
+void ieee80211_key_link(struct ieee80211_key *key,
+			struct ieee80211_sub_if_data *sdata,
+			struct sta_info *sta)
+{
+	struct ieee80211_key *old_key;
+	int idx;
+
+	ASSERT_RTNL();
+	might_sleep();
+
+	BUG_ON(!sdata);
+	BUG_ON(!key);
+
+	idx = key->conf.keyidx;
+	key->local = sdata->local;
+	key->sdata = sdata;
+	key->sta = sta;
+
+	ieee80211_debugfs_key_add(key->local, key);
 
 	if (sta) {
 		ieee80211_debugfs_key_sta_link(key, sta);
@@ -175,61 +249,76 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
 		if (sdata->vif.type == IEEE80211_IF_TYPE_STA) {
 			struct sta_info *ap;
 
+			rcu_read_lock();
+
 			/* same here, the AP could be using QoS */
 			ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
 			if (ap) {
 				if (ap->flags & WLAN_STA_WME)
 					key->conf.flags |=
 						IEEE80211_KEY_FLAG_WMM_STA;
-				sta_info_put(ap);
 			}
+
+			rcu_read_unlock();
 		}
 	}
 
-	/* enable hwaccel if appropriate */
-	if (netif_running(key->sdata->dev))
-		ieee80211_key_enable_hw_accel(key);
-
 	if (sta)
-		rcu_assign_pointer(sta->key, key);
+		old_key = sta->key;
 	else
-		rcu_assign_pointer(sdata->keys[idx], key);
+		old_key = sdata->keys[idx];
 
-	list_add(&key->list, &sdata->key_list);
+	__ieee80211_key_replace(sdata, sta, old_key, key);
 
-	return key;
+	if (old_key) {
+		synchronize_rcu();
+		ieee80211_key_free(old_key);
+	}
+
+	if (netif_running(sdata->dev))
+		ieee80211_key_enable_hw_accel(key);
 }
 
 void ieee80211_key_free(struct ieee80211_key *key)
 {
+	ASSERT_RTNL();
+	might_sleep();
+
 	if (!key)
 		return;
 
-	if (key->sta) {
-		rcu_assign_pointer(key->sta->key, NULL);
-	} else {
-		if (key->sdata->default_key == key)
-			ieee80211_set_default_key(key->sdata, -1);
-		if (key->conf.keyidx >= 0 &&
-		    key->conf.keyidx < NUM_DEFAULT_KEYS)
-			rcu_assign_pointer(key->sdata->keys[key->conf.keyidx],
-					   NULL);
-		else
-			WARN_ON(1);
-	}
+	if (key->sdata) {
+		/*
+		 * Replace key with nothingness.
+		 *
+		 * Because other code may have key reference (RCU protected)
+		 * right now, we then wait for a grace period before freeing
+		 * it.
+		 * An empty list indicates it was never added to the key list
+		 * or has been removed already. It may, however, still be in
+		 * hardware for acceleration.
+		 */
+		if (!list_empty(&key->list))
+			__ieee80211_key_replace(key->sdata, key->sta,
+						key, NULL);
 
-	/* wait for all key users to complete */
-	synchronize_rcu();
+		/*
+		 * Do NOT remove this without looking at sta_info_destroy()
+		 */
+		synchronize_rcu();
 
-	/* remove from hwaccel if appropriate */
-	ieee80211_key_disable_hw_accel(key);
+		/*
+		 * Remove from hwaccel if appropriate, this will
+		 * only happen when the key is actually unlinked,
+		 * it will already be done when the key was replaced.
+		 */
+		ieee80211_key_disable_hw_accel(key);
+	}
 
 	if (key->conf.alg == ALG_CCMP)
 		ieee80211_aes_key_free(key->u.ccmp.tfm);
 	ieee80211_debugfs_key_remove(key);
 
-	list_del(&key->list);
-
 	kfree(key);
 }
 
@@ -253,6 +342,10 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
 void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_key *key, *tmp;
+	LIST_HEAD(tmp_list);
+
+	ASSERT_RTNL();
+	might_sleep();
 
 	list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
 		ieee80211_key_free(key);
@@ -262,8 +355,10 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_key *key;
 
-	WARN_ON(!netif_running(sdata->dev));
-	if (!netif_running(sdata->dev))
+	ASSERT_RTNL();
+	might_sleep();
+
+	if (WARN_ON(!netif_running(sdata->dev)))
 		return;
 
 	list_for_each_entry(key, &sdata->key_list, list)
@@ -274,6 +369,9 @@ void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
 {
 	struct ieee80211_key *key;
 
+	ASSERT_RTNL();
+	might_sleep();
+
 	list_for_each_entry(key, &sdata->key_list, list)
 		ieee80211_key_disable_hw_accel(key);
 }
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
new file mode 100644
index 000000000000..b10f1e543a94
--- /dev/null
+++ b/net/mac80211/mesh.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors:    Luis Carlos Cobo <luisca@cozybit.com>
+ * 	       Javier Cardona <javier@cozybit.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+#define ACCEPT_PLINKS 0x80
+
+int mesh_allocated;
+static struct kmem_cache *rm_cache;
+
+void ieee80211s_init(void)
+{
+	mesh_pathtbl_init();
+	mesh_allocated = 1;
+	rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry),
+				     0, 0, NULL);
+}
+
+void ieee80211s_stop(void)
+{
+	mesh_pathtbl_unregister();
+	kmem_cache_destroy(rm_cache);
+}
+
+/**
+ * mesh_matches_local - check if the config of a mesh point matches ours
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ *
+ * This function checks if the mesh configuration of a mesh point matches the
+ * local mesh configuration, i.e. if both nodes belong to the same mesh network.
+ */
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *sta = &sdata->u.sta;
+
+	/*
+	 * As support for each feature is added, check for matching
+	 * - On mesh config capabilities
+	 *   - Power Save Support En
+	 *   - Sync support enabled
+	 *   - Sync support active
+	 *   - Sync support required from peer
+	 *   - MDA enabled
+	 * - Power management control on fc
+	 */
+	if (sta->mesh_id_len == ie->mesh_id_len &&
+		memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+		memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 &&
+		memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 &&
+		memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0)
+		return true;
+
+	return false;
+}
+
+/**
+ * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links
+ *
+ * @ie: information elements of a management frame from the mesh peer
+ * @dev: local mesh interface
+ */
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+			      struct net_device *dev)
+{
+	return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0;
+}
+
+/**
+ * mesh_accept_plinks_update: update accepting_plink in local mesh beacons
+ *
+ * @sdata: mesh interface in which mesh beacons are going to be updated
+ */
+void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
+{
+	bool free_plinks;
+
+	/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
+	 * the mesh interface might be able to establish plinks with peers that
+	 * are already on the table but are not on PLINK_ESTAB state. However,
+	 * in general the mesh interface is not accepting peer link requests
+	 * from new peers, and that must be reflected in the beacon
+	 */
+	free_plinks = mesh_plink_availables(sdata);
+
+	if (free_plinks != sdata->u.sta.accepting_plinks)
+		ieee80211_sta_timer((unsigned long) sdata);
+}
+
+void mesh_ids_set_default(struct ieee80211_if_sta *sta)
+{
+	u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff};
+
+	memcpy(sta->mesh_pp_id, def_id, 4);
+	memcpy(sta->mesh_pm_id, def_id, 4);
+	memcpy(sta->mesh_cc_id, def_id, 4);
+}
+
+int mesh_rmc_init(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int i;
+
+	sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL);
+	if (!sdata->u.sta.rmc)
+		return -ENOMEM;
+	sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1;
+	for (i = 0; i < RMC_BUCKETS; i++)
+		INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list);
+	return 0;
+}
+
+void mesh_rmc_free(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_rmc *rmc = sdata->u.sta.rmc;
+	struct rmc_entry *p, *n;
+	int i;
+
+	if (!sdata->u.sta.rmc)
+		return;
+
+	for (i = 0; i < RMC_BUCKETS; i++)
+		list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) {
+			list_del(&p->list);
+			kmem_cache_free(rm_cache, p);
+		}
+
+	kfree(rmc);
+	sdata->u.sta.rmc = NULL;
+}
+
+/**
+ * mesh_rmc_check - Check frame in recent multicast cache and add if absent.
+ *
+ * @sa:		source address
+ * @mesh_hdr:	mesh_header
+ *
+ * Returns: 0 if the frame is not in the cache, nonzero otherwise.
+ *
+ * Checks using the source address and the mesh sequence number if we have
+ * received this frame lately. If the frame is not in the cache, it is added to
+ * it.
+ */
+int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
+		   struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_rmc *rmc = sdata->u.sta.rmc;
+	u32 seqnum = 0;
+	int entries = 0;
+	u8 idx;
+	struct rmc_entry *p, *n;
+
+	/* Don't care about endianness since only match matters */
+	memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum));
+	idx = mesh_hdr->seqnum[0] & rmc->idx_mask;
+	list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) {
+		++entries;
+		if (time_after(jiffies, p->exp_time) ||
+				(entries == RMC_QUEUE_MAX_LEN)) {
+			list_del(&p->list);
+			kmem_cache_free(rm_cache, p);
+			--entries;
+		} else if ((seqnum == p->seqnum)
+				&& (memcmp(sa, p->sa, ETH_ALEN) == 0))
+			return -1;
+	}
+
+	p = kmem_cache_alloc(rm_cache, GFP_ATOMIC);
+	if (!p) {
+		printk(KERN_DEBUG "o11s: could not allocate RMC entry\n");
+		return 0;
+	}
+	p->seqnum = seqnum;
+	p->exp_time = jiffies + RMC_TIMEOUT;
+	memcpy(p->sa, sa, ETH_ALEN);
+	list_add(&p->list, &rmc->bucket[idx].list);
+	return 0;
+}
+
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_supported_band *sband;
+	u8 *pos;
+	int len, i, rate;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	len = sband->n_bitrates;
+	if (len > 8)
+		len = 8;
+	pos = skb_put(skb, len + 2);
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos++ = len;
+	for (i = 0; i < len; i++) {
+		rate = sband->bitrates[i].bitrate;
+		*pos++ = (u8) (rate / 5);
+	}
+
+	if (sband->n_bitrates > len) {
+		pos = skb_put(skb, sband->n_bitrates - len + 2);
+		*pos++ = WLAN_EID_EXT_SUPP_RATES;
+		*pos++ = sband->n_bitrates - len;
+		for (i = len; i < sband->n_bitrates; i++) {
+			rate = sband->bitrates[i].bitrate;
+			*pos++ = (u8) (rate / 5);
+		}
+	}
+
+	pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len);
+	*pos++ = WLAN_EID_MESH_ID;
+	*pos++ = sdata->u.sta.mesh_id_len;
+	if (sdata->u.sta.mesh_id_len)
+		memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len);
+
+	pos = skb_put(skb, 21);
+	*pos++ = WLAN_EID_MESH_CONFIG;
+	*pos++ = MESH_CFG_LEN;
+	/* Version */
+	*pos++ = 1;
+
+	/* Active path selection protocol ID */
+	memcpy(pos, sdata->u.sta.mesh_pp_id, 4);
+	pos += 4;
+
+	/* Active path selection metric ID   */
+	memcpy(pos, sdata->u.sta.mesh_pm_id, 4);
+	pos += 4;
+
+	/* Congestion control mode identifier */
+	memcpy(pos, sdata->u.sta.mesh_cc_id, 4);
+	pos += 4;
+
+	/* Channel precedence:
+	 * Not running simple channel unification protocol
+	 */
+	memset(pos, 0x00, 4);
+	pos += 4;
+
+	/* Mesh capability */
+	sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata);
+	*pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00;
+	*pos++ = 0x00;
+
+	return;
+}
+
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl)
+{
+	/* Use last four bytes of hw addr and interface index as hash index */
+	return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd)
+		& tbl->hash_mask;
+}
+
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len)
+{
+	if (!mesh_id_len)
+		return 1;
+	else if (mesh_id_len == 1)
+		return (u8) mesh_id[0];
+	else
+		return (u8) (mesh_id[0] + 2 * mesh_id[1]);
+}
+
+struct mesh_table *mesh_table_alloc(int size_order)
+{
+	int i;
+	struct mesh_table *newtbl;
+
+	newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+	if (!newtbl)
+		return NULL;
+
+	newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
+			(1 << size_order), GFP_KERNEL);
+
+	if (!newtbl->hash_buckets) {
+		kfree(newtbl);
+		return NULL;
+	}
+
+	newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
+			(1 << size_order), GFP_KERNEL);
+	if (!newtbl->hashwlock) {
+		kfree(newtbl->hash_buckets);
+		kfree(newtbl);
+		return NULL;
+	}
+
+	newtbl->size_order = size_order;
+	newtbl->hash_mask = (1 << size_order) - 1;
+	atomic_set(&newtbl->entries,  0);
+	get_random_bytes(&newtbl->hash_rnd,
+			sizeof(newtbl->hash_rnd));
+	for (i = 0; i <= newtbl->hash_mask; i++)
+		spin_lock_init(&newtbl->hashwlock[i]);
+
+	return newtbl;
+}
+
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+{
+	struct hlist_head *mesh_hash;
+	struct hlist_node *p, *q;
+	int i;
+
+	mesh_hash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++) {
+		spin_lock(&tbl->hashwlock[i]);
+		hlist_for_each_safe(p, q, &mesh_hash[i]) {
+			tbl->free_node(p, free_leafs);
+			atomic_dec(&tbl->entries);
+		}
+		spin_unlock(&tbl->hashwlock[i]);
+	}
+	kfree(tbl->hash_buckets);
+	kfree(tbl->hashwlock);
+	kfree(tbl);
+}
+
+static void ieee80211_mesh_path_timer(unsigned long data)
+{
+	struct ieee80211_sub_if_data *sdata =
+		(struct ieee80211_sub_if_data *) data;
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+
+	queue_work(local->hw.workqueue, &ifsta->work);
+}
+
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+{
+	struct mesh_table *newtbl;
+	struct hlist_head *oldhash;
+	struct hlist_node *p;
+	int err = 0;
+	int i;
+
+	if (atomic_read(&tbl->entries)
+			< tbl->mean_chain_len * (tbl->hash_mask + 1)) {
+		err = -EPERM;
+		goto endgrow;
+	}
+
+	newtbl = mesh_table_alloc(tbl->size_order + 1);
+	if (!newtbl) {
+		err = -ENOMEM;
+		goto endgrow;
+	}
+
+	newtbl->free_node = tbl->free_node;
+	newtbl->mean_chain_len = tbl->mean_chain_len;
+	newtbl->copy_node = tbl->copy_node;
+	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+
+	oldhash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++)
+		hlist_for_each(p, &oldhash[i])
+			tbl->copy_node(p, newtbl);
+
+endgrow:
+	if (err)
+		return NULL;
+	else
+		return newtbl;
+}
+
+/**
+ * ieee80211_new_mesh_header - create a new mesh header
+ * @meshhdr:    uninitialized mesh header
+ * @sdata:	mesh interface to be used
+ *
+ * Return the header length.
+ */
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+		struct ieee80211_sub_if_data *sdata)
+{
+	meshhdr->flags = 0;
+	meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+
+	meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++;
+	meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1];
+	meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2];
+
+	if (sdata->u.sta.mesh_seqnum[0] == 0) {
+		sdata->u.sta.mesh_seqnum[1]++;
+		if (sdata->u.sta.mesh_seqnum[1] == 0)
+			sdata->u.sta.mesh_seqnum[2]++;
+	}
+
+	return 5;
+}
+
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
+{
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+	ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
+	ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
+	ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
+	ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
+	ifsta->mshcfg.dot11MeshTTL = MESH_TTL;
+	ifsta->mshcfg.auto_open_plinks = true;
+	ifsta->mshcfg.dot11MeshMaxPeerLinks =
+		MESH_MAX_ESTAB_PLINKS;
+	ifsta->mshcfg.dot11MeshHWMPactivePathTimeout =
+		MESH_PATH_TIMEOUT;
+	ifsta->mshcfg.dot11MeshHWMPpreqMinInterval =
+		MESH_PREQ_MIN_INT;
+	ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
+		MESH_DIAM_TRAVERSAL_TIME;
+	ifsta->mshcfg.dot11MeshHWMPmaxPREQretries =
+		MESH_MAX_PREQ_RETRIES;
+	ifsta->mshcfg.path_refresh_time =
+		MESH_PATH_REFRESH_TIME;
+	ifsta->mshcfg.min_discovery_timeout =
+		MESH_MIN_DISCOVERY_TIMEOUT;
+	ifsta->accepting_plinks = true;
+	ifsta->preq_id = 0;
+	ifsta->dsn = 0;
+	atomic_set(&ifsta->mpaths, 0);
+	mesh_rmc_init(sdata->dev);
+	ifsta->last_preq = jiffies;
+	/* Allocate all mesh structures when creating the first mesh interface. */
+	if (!mesh_allocated)
+		ieee80211s_init();
+	mesh_ids_set_default(ifsta);
+	setup_timer(&ifsta->mesh_path_timer,
+		    ieee80211_mesh_path_timer,
+		    (unsigned long) sdata);
+	INIT_LIST_HEAD(&ifsta->preq_queue.list);
+	spin_lock_init(&ifsta->mesh_preq_queue_lock);
+}
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
new file mode 100644
index 000000000000..8ff46ea0f1d7
--- /dev/null
+++ b/net/mac80211/mesh.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Authors:    Luis Carlos Cobo <luisca@cozybit.com>
+ *             Javier Cardona <javier@cozybit.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#ifndef IEEE80211S_H
+#define IEEE80211S_H
+
+#include <linux/types.h>
+#include <linux/jhash.h>
+#include "ieee80211_i.h"
+
+
+/* Data structures */
+
+/**
+ * enum mesh_path_flags - mac80211 mesh path flags
+ *
+ *
+ *
+ * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding
+ * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path
+ * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence
+ * 	number
+ * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
+ * 	modified
+ * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ *
+ * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to
+ * decide when to stop or cancel the mesh path discovery.
+ */
+enum mesh_path_flags {
+	MESH_PATH_ACTIVE =	BIT(0),
+	MESH_PATH_RESOLVING =	BIT(1),
+	MESH_PATH_DSN_VALID =	BIT(2),
+	MESH_PATH_FIXED	=	BIT(3),
+	MESH_PATH_RESOLVED =	BIT(4),
+};
+
+/**
+ * struct mesh_path - mac80211 mesh path structure
+ *
+ * @dst: mesh path destination mac address
+ * @dev: mesh path device
+ * @next_hop: mesh neighbor to which frames for this destination will be
+ * 	forwarded
+ * @timer: mesh path discovery timer
+ * @frame_queue: pending queue for frames sent to this destination while the
+ * 	path is unresolved
+ * @dsn: destination sequence number of the destination
+ * @metric: current metric to this destination
+ * @hop_count: hops to destination
+ * @exp_time: in jiffies, when the path will expire or when it expired
+ * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery
+ * 	retry
+ * @discovery_retries: number of discovery retries
+ * @flags: mesh path flags, as specified on &enum mesh_path_flags
+ * @state_lock: mesh pat state lock
+ *
+ *
+ * The combination of dst and dev is unique in the mesh path table. Since the
+ * next_hop STA is only protected by RCU as well, deleting the STA must also
+ * remove/substitute the mesh_path structure and wait until that is no longer
+ * reachable before destroying the STA completely.
+ */
+struct mesh_path {
+	u8 dst[ETH_ALEN];
+	struct net_device *dev;
+	struct sta_info *next_hop;
+	struct timer_list timer;
+	struct sk_buff_head frame_queue;
+	struct rcu_head rcu;
+	u32 dsn;
+	u32 metric;
+	u8 hop_count;
+	unsigned long exp_time;
+	u32 discovery_timeout;
+	u8 discovery_retries;
+	enum mesh_path_flags flags;
+	spinlock_t state_lock;
+};
+
+/**
+ * struct mesh_table
+ *
+ * @hash_buckets: array of hash buckets of the table
+ * @hashwlock: array of locks to protect write operations, one per bucket
+ * @hash_mask: 2^size_order - 1, used to compute hash idx
+ * @hash_rnd: random value used for hash computations
+ * @entries: number of entries in the table
+ * @free_node: function to free nodes of the table
+ * @copy_node: fuction to copy nodes of the table
+ * @size_order: determines size of the table, there will be 2^size_order hash
+ *	buckets
+ * @mean_chain_len: maximum average length for the hash buckets' list, if it is
+ *	reached, the table will grow
+ */
+struct mesh_table {
+	/* Number of buckets will be 2^N */
+	struct hlist_head *hash_buckets;
+	spinlock_t *hashwlock;		/* One per bucket, for add/del */
+	unsigned int hash_mask;		/* (2^size_order) - 1 */
+	__u32 hash_rnd;			/* Used for hash generation */
+	atomic_t entries;		/* Up to MAX_MESH_NEIGHBOURS */
+	void (*free_node) (struct hlist_node *p, bool free_leafs);
+	void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
+	int size_order;
+	int mean_chain_len;
+};
+
+/* Recent multicast cache */
+/* RMC_BUCKETS must be a power of 2, maximum 256 */
+#define RMC_BUCKETS		256
+#define RMC_QUEUE_MAX_LEN	4
+#define RMC_TIMEOUT		(3 * HZ)
+
+/**
+ * struct rmc_entry - entry in the Recent Multicast Cache
+ *
+ * @seqnum: mesh sequence number of the frame
+ * @exp_time: expiration time of the entry, in jiffies
+ * @sa: source address of the frame
+ *
+ * The Recent Multicast Cache keeps track of the latest multicast frames that
+ * have been received by a mesh interface and discards received multicast frames
+ * that are found in the cache.
+ */
+struct rmc_entry {
+	struct list_head list;
+	u32 seqnum;
+	unsigned long exp_time;
+	u8 sa[ETH_ALEN];
+};
+
+struct mesh_rmc {
+	struct rmc_entry bucket[RMC_BUCKETS];
+	u8 idx_mask;
+};
+
+
+/* Mesh IEs constants */
+#define MESH_CFG_LEN		19
+
+/*
+ * MESH_CFG_COMP_LEN Includes:
+ * 	- Active path selection protocol ID.
+ * 	- Active path selection metric ID.
+ * 	- Congestion control mode identifier.
+ * 	- Channel precedence.
+ * Does not include mesh capabilities, which may vary across nodes in the same
+ * mesh
+ */
+#define MESH_CFG_CMP_LEN 	17
+
+/*
+ * Components offset within the mesh configuration IE
+ */
+#define PP_OFFSET	1		/* Path Selection Protocol */
+#define PM_OFFSET	5		/* Path Selection Metric   */
+#define CC_OFFSET	9		/* Congestion Control Mode */
+#define CP_OFFSET	13		/* Channel Precedence */
+#define CAPAB_OFFSET	17		/* Mesh Capabilities */
+
+
+/* Default values, timeouts in ms */
+#define MESH_TTL 		5
+#define MESH_MAX_RETR	 	3
+#define MESH_RET_T 		100
+#define MESH_CONF_T 		100
+#define MESH_HOLD_T 		100
+
+#define MESH_PATH_TIMEOUT	5000
+/* Minimum interval between two consecutive PREQs originated by the same
+ * interface
+ */
+#define MESH_PREQ_MIN_INT	10
+#define MESH_DIAM_TRAVERSAL_TIME 50
+/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their
+ * expiration
+ */
+#define MESH_PATH_REFRESH_TIME			1000
+#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+
+#define MESH_MAX_PREQ_RETRIES 4
+#define MESH_PATH_EXPIRE (600 * HZ)
+
+/* Default maximum number of established plinks per interface */
+#define MESH_MAX_ESTAB_PLINKS	32
+
+/* Default maximum number of plinks per interface */
+#define MESH_MAX_PLINKS		256
+
+/* Maximum number of paths per interface */
+#define MESH_MAX_MPATHS		1024
+
+/* Pending ANA approval */
+#define PLINK_CATEGORY		30
+#define MESH_PATH_SEL_CATEGORY	32
+
+/* Mesh Header Flags */
+#define IEEE80211S_FLAGS_AE	0x3
+
+/* Public interfaces */
+/* Various */
+u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len);
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
+int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
+		struct ieee80211_sub_if_data *sdata);
+int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
+		struct net_device *dev);
+bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev);
+void mesh_ids_set_default(struct ieee80211_if_sta *sta);
+void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev);
+void mesh_rmc_free(struct net_device *dev);
+int mesh_rmc_init(struct net_device *dev);
+void ieee80211s_init(void);
+void ieee80211s_stop(void);
+void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata);
+
+/* Mesh paths */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+		struct net_device *dev);
+void mesh_path_start_discovery(struct net_device *dev);
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev);
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev);
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
+void mesh_path_expire(struct net_device *dev);
+void mesh_path_flush(struct net_device *dev);
+void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+		size_t len);
+int mesh_path_add(u8 *dst, struct net_device *dev);
+/* Mesh plinks */
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+		bool add);
+bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie,
+			      struct net_device *dev);
+void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
+void mesh_plink_broken(struct sta_info *sta);
+void mesh_plink_deactivate(struct sta_info *sta);
+int mesh_plink_open(struct sta_info *sta);
+int mesh_plink_close(struct sta_info *sta);
+void mesh_plink_block(struct sta_info *sta);
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+			 size_t len, struct ieee80211_rx_status *rx_status);
+
+/* Private interfaces */
+/* Mesh tables */
+struct mesh_table *mesh_table_alloc(int size_order);
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
+struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
+u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl);
+/* Mesh paths */
+int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra,
+		struct net_device *dev);
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta);
+void mesh_path_flush_pending(struct mesh_path *mpath);
+void mesh_path_tx_pending(struct mesh_path *mpath);
+int mesh_pathtbl_init(void);
+void mesh_pathtbl_unregister(void);
+int mesh_path_del(u8 *addr, struct net_device *dev);
+void mesh_path_timer(unsigned long data);
+void mesh_path_flush_by_nexthop(struct sta_info *sta);
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev);
+
+#ifdef CONFIG_MAC80211_MESH
+extern int mesh_allocated;
+
+static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata)
+{
+	return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks -
+	       atomic_read(&sdata->u.sta.mshstats.estab_plinks);
+}
+
+static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata)
+{
+	return (min_t(long, mesh_plink_free_count(sdata),
+		   MESH_MAX_PLINKS - sdata->local->num_sta)) > 0;
+}
+
+static inline void mesh_path_activate(struct mesh_path *mpath)
+{
+	mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED;
+}
+
+#define for_each_mesh_entry(x, p, node, i) \
+	for (i = 0; i <= x->hash_mask; i++) \
+		hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list)
+
+#else
+#define mesh_allocated	0
+#endif
+
+#define MESH_PREQ(skb)	(skb->cb + 30)
+
+#endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
new file mode 100644
index 000000000000..576a6e55323e
--- /dev/null
+++ b/net/mac80211/mesh_hwmp.c
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author:     Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/unaligned.h>
+#include "mesh.h"
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+
+#define TEST_FRAME_LEN	8192
+#define MAX_METRIC	0xffffffff
+#define ARITH_SHIFT	8
+
+/* Number of frames buffered per destination for unresolved destinations */
+#define MESH_FRAME_QUEUE_LEN	10
+#define MAX_PREQ_QUEUE_LEN	64
+
+/* Destination only */
+#define MP_F_DO	0x1
+/* Reply and forward */
+#define MP_F_RF	0x2
+
+static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae)
+{
+	if (ae)
+		offset += 6;
+	return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset)));
+}
+
+/* HWMP IE processing macros */
+#define AE_F			(1<<6)
+#define AE_F_SET(x)		(*x & AE_F)
+#define PREQ_IE_FLAGS(x)	(*(x))
+#define PREQ_IE_HOPCOUNT(x)	(*(x + 1))
+#define PREQ_IE_TTL(x)		(*(x + 2))
+#define PREQ_IE_PREQ_ID(x)	u32_field_get(x, 3, 0)
+#define PREQ_IE_ORIG_ADDR(x)	(x + 7)
+#define PREQ_IE_ORIG_DSN(x)	u32_field_get(x, 13, 0);
+#define PREQ_IE_LIFETIME(x)	u32_field_get(x, 17, AE_F_SET(x));
+#define PREQ_IE_METRIC(x) 	u32_field_get(x, 21, AE_F_SET(x));
+#define PREQ_IE_DST_F(x)	(*(AE_F_SET(x) ? x + 32 : x + 26))
+#define PREQ_IE_DST_ADDR(x) 	(AE_F_SET(x) ? x + 33 : x + 27)
+#define PREQ_IE_DST_DSN(x) 	u32_field_get(x, 33, AE_F_SET(x));
+
+
+#define PREP_IE_FLAGS(x)	PREQ_IE_FLAGS(x)
+#define PREP_IE_HOPCOUNT(x)	PREQ_IE_HOPCOUNT(x)
+#define PREP_IE_TTL(x)		PREQ_IE_TTL(x)
+#define PREP_IE_ORIG_ADDR(x)	(x + 3)
+#define PREP_IE_ORIG_DSN(x)	u32_field_get(x, 9, 0);
+#define PREP_IE_LIFETIME(x)	u32_field_get(x, 13, AE_F_SET(x));
+#define PREP_IE_METRIC(x)	u32_field_get(x, 17, AE_F_SET(x));
+#define PREP_IE_DST_ADDR(x)	(AE_F_SET(x) ? x + 27 : x + 21)
+#define PREP_IE_DST_DSN(x)	u32_field_get(x, 27, AE_F_SET(x));
+
+#define PERR_IE_DST_ADDR(x)	(x + 2)
+#define PERR_IE_DST_DSN(x)	u32_field_get(x, 8, 0);
+
+#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000))
+#define MSEC_TO_TU(x) (x*1000/1024)
+#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0)
+#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0)
+
+#define net_traversal_jiffies(s) \
+	msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime)
+#define default_lifetime(s) \
+	MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout)
+#define min_preq_int_jiff(s) \
+	(msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval))
+#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries)
+#define disc_timeout_jiff(s) \
+	msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout)
+
+enum mpath_frame_type {
+	MPATH_PREQ = 0,
+	MPATH_PREP,
+	MPATH_PERR
+};
+
+static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
+		u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst,
+		__le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime,
+		__le32 metric, __le32 preq_id, struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos;
+	int ie_len;
+
+	if (!skb)
+		return -1;
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	/* 25 is the size of the common mgmt part (24) plus the size of the
+	 * common action part (1)
+	 */
+	mgmt = (struct ieee80211_mgmt *)
+		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_ACTION);
+
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	/* BSSID is left zeroed, wildcard value */
+	mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+	mgmt->u.action.u.mesh_action.action_code = action;
+
+	switch (action) {
+	case MPATH_PREQ:
+		ie_len = 37;
+		pos = skb_put(skb, 2 + ie_len);
+		*pos++ = WLAN_EID_PREQ;
+		break;
+	case MPATH_PREP:
+		ie_len = 31;
+		pos = skb_put(skb, 2 + ie_len);
+		*pos++ = WLAN_EID_PREP;
+		break;
+	default:
+		kfree(skb);
+		return -ENOTSUPP;
+		break;
+	}
+	*pos++ = ie_len;
+	*pos++ = flags;
+	*pos++ = hop_count;
+	*pos++ = ttl;
+	if (action == MPATH_PREQ) {
+		memcpy(pos, &preq_id, 4);
+		pos += 4;
+	}
+	memcpy(pos, orig_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	memcpy(pos, &orig_dsn, 4);
+	pos += 4;
+	memcpy(pos, &lifetime, 4);
+	pos += 4;
+	memcpy(pos, &metric, 4);
+	pos += 4;
+	if (action == MPATH_PREQ) {
+		/* destination count */
+		*pos++ = 1;
+		*pos++ = dst_flags;
+	}
+	memcpy(pos, dst, ETH_ALEN);
+	pos += ETH_ALEN;
+	memcpy(pos, &dst_dsn, 4);
+
+	ieee80211_sta_tx(dev, skb, 0);
+	return 0;
+}
+
+/**
+ * mesh_send_path error - Sends a PERR mesh management frame
+ *
+ * @dst: broken destination
+ * @dst_dsn: dsn of the broken destination
+ * @ra: node this frame is addressed to
+ */
+int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra,
+		struct net_device *dev)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	struct ieee80211_mgmt *mgmt;
+	u8 *pos;
+	int ie_len;
+
+	if (!skb)
+		return -1;
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	/* 25 is the size of the common mgmt part (24) plus the size of the
+	 * common action part (1)
+	 */
+	mgmt = (struct ieee80211_mgmt *)
+		skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
+	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_ACTION);
+
+	memcpy(mgmt->da, ra, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	/* BSSID is left zeroed, wildcard value */
+	mgmt->u.action.category = MESH_PATH_SEL_CATEGORY;
+	mgmt->u.action.u.mesh_action.action_code = MPATH_PERR;
+	ie_len = 12;
+	pos = skb_put(skb, 2 + ie_len);
+	*pos++ = WLAN_EID_PERR;
+	*pos++ = ie_len;
+	/* mode flags, reserved */
+	*pos++ = 0;
+	/* number of destinations */
+	*pos++ = 1;
+	memcpy(pos, dst, ETH_ALEN);
+	pos += ETH_ALEN;
+	memcpy(pos, &dst_dsn, 4);
+
+	ieee80211_sta_tx(dev, skb, 0);
+	return 0;
+}
+
+static u32 airtime_link_metric_get(struct ieee80211_local *local,
+				   struct sta_info *sta)
+{
+	struct ieee80211_supported_band *sband;
+	/* This should be adjusted for each device */
+	int device_constant = 1 << ARITH_SHIFT;
+	int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT;
+	int s_unit = 1 << ARITH_SHIFT;
+	int rate, err;
+	u32 tx_time, estimated_retx;
+	u64 result;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	if (sta->fail_avg >= 100)
+		return MAX_METRIC;
+	err = (sta->fail_avg << ARITH_SHIFT) / 100;
+
+	/* bitrate is in units of 100 Kbps, while we need rate in units of
+	 * 1Mbps. This will be corrected on tx_time computation.
+	 */
+	rate = sband->bitrates[sta->txrate_idx].bitrate;
+	tx_time = (device_constant + 10 * test_frame_len / rate);
+	estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
+	result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
+	return (u32)result;
+}
+
+/**
+ * hwmp_route_info_get - Update routing info to originator and transmitter
+ *
+ * @dev: local mesh interface
+ * @mgmt: mesh management frame
+ * @hwmp_ie: hwmp information element (PREP or PREQ)
+ *
+ * This function updates the path routing information to the originator and the
+ * transmitter of a HWMP PREQ or PREP fram.
+ *
+ * Returns: metric to frame originator or 0 if the frame should not be further
+ * processed
+ *
+ * Notes: this function is the only place (besides user-provided info) where
+ * path routing information is updated.
+ */
+static u32 hwmp_route_info_get(struct net_device *dev,
+			    struct ieee80211_mgmt *mgmt,
+			    u8 *hwmp_ie)
+{
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct mesh_path *mpath;
+	struct sta_info *sta;
+	bool fresh_info;
+	u8 *orig_addr, *ta;
+	u32 orig_dsn, orig_metric;
+	unsigned long orig_lifetime, exp_time;
+	u32 last_hop_metric, new_metric;
+	bool process = true;
+	u8 action = mgmt->u.action.u.mesh_action.action_code;
+
+	rcu_read_lock();
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta) {
+		rcu_read_unlock();
+		return 0;
+	}
+
+	last_hop_metric = airtime_link_metric_get(local, sta);
+	/* Update and check originator routing info */
+	fresh_info = true;
+
+	switch (action) {
+	case MPATH_PREQ:
+		orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie);
+		orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie);
+		orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie);
+		orig_metric = PREQ_IE_METRIC(hwmp_ie);
+		break;
+	case MPATH_PREP:
+		/* Originator here refers to the MP that was the destination in
+		 * the Path Request. The draft refers to that MP as the
+		 * destination address, even though usually it is the origin of
+		 * the PREP frame. We divert from the nomenclature in the draft
+		 * so that we can easily use a single function to gather path
+		 * information from both PREQ and PREP frames.
+		 */
+		orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie);
+		orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie);
+		orig_lifetime = PREP_IE_LIFETIME(hwmp_ie);
+		orig_metric = PREP_IE_METRIC(hwmp_ie);
+		break;
+	default:
+		rcu_read_unlock();
+		return 0;
+	}
+	new_metric = orig_metric + last_hop_metric;
+	if (new_metric < orig_metric)
+		new_metric = MAX_METRIC;
+	exp_time = TU_TO_EXP_TIME(orig_lifetime);
+
+	if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) {
+		/* This MP is the originator, we are not interested in this
+		 * frame, except for updating transmitter's path info.
+		 */
+		process = false;
+		fresh_info = false;
+	} else {
+		mpath = mesh_path_lookup(orig_addr, dev);
+		if (mpath) {
+			spin_lock_bh(&mpath->state_lock);
+			if (mpath->flags & MESH_PATH_FIXED)
+				fresh_info = false;
+			else if ((mpath->flags & MESH_PATH_ACTIVE) &&
+			    (mpath->flags & MESH_PATH_DSN_VALID)) {
+				if (DSN_GT(mpath->dsn, orig_dsn) ||
+				    (mpath->dsn == orig_dsn &&
+				     action == MPATH_PREQ &&
+				     new_metric > mpath->metric)) {
+					process = false;
+					fresh_info = false;
+				}
+			}
+		} else {
+			mesh_path_add(orig_addr, dev);
+			mpath = mesh_path_lookup(orig_addr, dev);
+			if (!mpath) {
+				rcu_read_unlock();
+				return 0;
+			}
+			spin_lock_bh(&mpath->state_lock);
+		}
+
+		if (fresh_info) {
+			mesh_path_assign_nexthop(mpath, sta);
+			mpath->flags |= MESH_PATH_DSN_VALID;
+			mpath->metric = new_metric;
+			mpath->dsn = orig_dsn;
+			mpath->exp_time = time_after(mpath->exp_time, exp_time)
+					  ?  mpath->exp_time : exp_time;
+			mesh_path_activate(mpath);
+			spin_unlock_bh(&mpath->state_lock);
+			mesh_path_tx_pending(mpath);
+			/* draft says preq_id should be saved to, but there does
+			 * not seem to be any use for it, skipping by now
+			 */
+		} else
+			spin_unlock_bh(&mpath->state_lock);
+	}
+
+	/* Update and check transmitter routing info */
+	ta = mgmt->sa;
+	if (memcmp(orig_addr, ta, ETH_ALEN) == 0)
+		fresh_info = false;
+	else {
+		fresh_info = true;
+
+		mpath = mesh_path_lookup(ta, dev);
+		if (mpath) {
+			spin_lock_bh(&mpath->state_lock);
+			if ((mpath->flags & MESH_PATH_FIXED) ||
+				((mpath->flags & MESH_PATH_ACTIVE) &&
+					(last_hop_metric > mpath->metric)))
+				fresh_info = false;
+		} else {
+			mesh_path_add(ta, dev);
+			mpath = mesh_path_lookup(ta, dev);
+			if (!mpath) {
+				rcu_read_unlock();
+				return 0;
+			}
+			spin_lock_bh(&mpath->state_lock);
+		}
+
+		if (fresh_info) {
+			mesh_path_assign_nexthop(mpath, sta);
+			mpath->flags &= ~MESH_PATH_DSN_VALID;
+			mpath->metric = last_hop_metric;
+			mpath->exp_time = time_after(mpath->exp_time, exp_time)
+					  ?  mpath->exp_time : exp_time;
+			mesh_path_activate(mpath);
+			spin_unlock_bh(&mpath->state_lock);
+			mesh_path_tx_pending(mpath);
+		} else
+			spin_unlock_bh(&mpath->state_lock);
+	}
+
+	rcu_read_unlock();
+
+	return process ? new_metric : 0;
+}
+
+static void hwmp_preq_frame_process(struct net_device *dev,
+				    struct ieee80211_mgmt *mgmt,
+				    u8 *preq_elem, u32 metric) {
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct mesh_path *mpath;
+	u8 *dst_addr, *orig_addr;
+	u8 dst_flags, ttl;
+	u32 orig_dsn, dst_dsn, lifetime;
+	bool reply = false;
+	bool forward = true;
+
+	/* Update destination DSN, if present */
+	dst_addr = PREQ_IE_DST_ADDR(preq_elem);
+	orig_addr = PREQ_IE_ORIG_ADDR(preq_elem);
+	dst_dsn = PREQ_IE_DST_DSN(preq_elem);
+	orig_dsn = PREQ_IE_ORIG_DSN(preq_elem);
+	dst_flags = PREQ_IE_DST_F(preq_elem);
+
+	if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) {
+		forward = false;
+		reply = true;
+		metric = 0;
+		if (time_after(jiffies, ifsta->last_dsn_update +
+					net_traversal_jiffies(sdata)) ||
+		    time_before(jiffies, ifsta->last_dsn_update)) {
+			dst_dsn = ++ifsta->dsn;
+			ifsta->last_dsn_update = jiffies;
+		}
+	} else {
+		rcu_read_lock();
+		mpath = mesh_path_lookup(dst_addr, dev);
+		if (mpath) {
+			if ((!(mpath->flags & MESH_PATH_DSN_VALID)) ||
+					DSN_LT(mpath->dsn, dst_dsn)) {
+				mpath->dsn = dst_dsn;
+				mpath->flags &= MESH_PATH_DSN_VALID;
+			} else if ((!(dst_flags & MP_F_DO)) &&
+					(mpath->flags & MESH_PATH_ACTIVE)) {
+				reply = true;
+				metric = mpath->metric;
+				dst_dsn = mpath->dsn;
+				if (dst_flags & MP_F_RF)
+					dst_flags |= MP_F_DO;
+				else
+					forward = false;
+			}
+		}
+		rcu_read_unlock();
+	}
+
+	if (reply) {
+		lifetime = PREQ_IE_LIFETIME(preq_elem);
+		ttl = ifsta->mshcfg.dot11MeshTTL;
+		if (ttl != 0)
+			mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr,
+				cpu_to_le32(dst_dsn), 0, orig_addr,
+				cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl,
+				cpu_to_le32(lifetime), cpu_to_le32(metric),
+				0, dev);
+		else
+			ifsta->mshstats.dropped_frames_ttl++;
+	}
+
+	if (forward) {
+		u32 preq_id;
+		u8 hopcount, flags;
+
+		ttl = PREQ_IE_TTL(preq_elem);
+		lifetime = PREQ_IE_LIFETIME(preq_elem);
+		if (ttl <= 1) {
+			ifsta->mshstats.dropped_frames_ttl++;
+			return;
+		}
+		--ttl;
+		flags = PREQ_IE_FLAGS(preq_elem);
+		preq_id = PREQ_IE_PREQ_ID(preq_elem);
+		hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1;
+		mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr,
+				cpu_to_le32(orig_dsn), dst_flags, dst_addr,
+				cpu_to_le32(dst_dsn), dev->broadcast,
+				hopcount, ttl, cpu_to_le32(lifetime),
+				cpu_to_le32(metric), cpu_to_le32(preq_id),
+				dev);
+		ifsta->mshstats.fwded_frames++;
+	}
+}
+
+
+static void hwmp_prep_frame_process(struct net_device *dev,
+				    struct ieee80211_mgmt *mgmt,
+				    u8 *prep_elem, u32 metric)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+	u8 *dst_addr, *orig_addr;
+	u8 ttl, hopcount, flags;
+	u8 next_hop[ETH_ALEN];
+	u32 dst_dsn, orig_dsn, lifetime;
+
+	/* Note that we divert from the draft nomenclature and denominate
+	 * destination to what the draft refers to as origininator. So in this
+	 * function destnation refers to the final destination of the PREP,
+	 * which corresponds with the originator of the PREQ which this PREP
+	 * replies
+	 */
+	dst_addr = PREP_IE_DST_ADDR(prep_elem);
+	if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0)
+		/* destination, no forwarding required */
+		return;
+
+	ttl = PREP_IE_TTL(prep_elem);
+	if (ttl <= 1) {
+		sdata->u.sta.mshstats.dropped_frames_ttl++;
+		return;
+	}
+
+	rcu_read_lock();
+	mpath = mesh_path_lookup(dst_addr, dev);
+	if (mpath)
+		spin_lock_bh(&mpath->state_lock);
+	else
+		goto fail;
+	if (!(mpath->flags & MESH_PATH_ACTIVE)) {
+		spin_unlock_bh(&mpath->state_lock);
+		goto fail;
+	}
+	memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN);
+	spin_unlock_bh(&mpath->state_lock);
+	--ttl;
+	flags = PREP_IE_FLAGS(prep_elem);
+	lifetime = PREP_IE_LIFETIME(prep_elem);
+	hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1;
+	orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
+	dst_dsn = PREP_IE_DST_DSN(prep_elem);
+	orig_dsn = PREP_IE_ORIG_DSN(prep_elem);
+
+	mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr,
+		cpu_to_le32(orig_dsn), 0, dst_addr,
+		cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl,
+		cpu_to_le32(lifetime), cpu_to_le32(metric),
+		0, dev);
+	rcu_read_unlock();
+	sdata->u.sta.mshstats.fwded_frames++;
+	return;
+
+fail:
+	rcu_read_unlock();
+	sdata->u.sta.mshstats.dropped_frames_no_route++;
+	return;
+}
+
+static void hwmp_perr_frame_process(struct net_device *dev,
+			     struct ieee80211_mgmt *mgmt, u8 *perr_elem)
+{
+	struct mesh_path *mpath;
+	u8 *ta, *dst_addr;
+	u32 dst_dsn;
+
+	ta = mgmt->sa;
+	dst_addr = PERR_IE_DST_ADDR(perr_elem);
+	dst_dsn = PERR_IE_DST_DSN(perr_elem);
+	rcu_read_lock();
+	mpath = mesh_path_lookup(dst_addr, dev);
+	if (mpath) {
+		spin_lock_bh(&mpath->state_lock);
+		if (mpath->flags & MESH_PATH_ACTIVE &&
+		    memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 &&
+		    (!(mpath->flags & MESH_PATH_DSN_VALID) ||
+		    DSN_GT(dst_dsn, mpath->dsn))) {
+			mpath->flags &= ~MESH_PATH_ACTIVE;
+			mpath->dsn = dst_dsn;
+			spin_unlock_bh(&mpath->state_lock);
+			mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn),
+					   dev->broadcast, dev);
+		} else
+			spin_unlock_bh(&mpath->state_lock);
+	}
+	rcu_read_unlock();
+}
+
+
+
+void mesh_rx_path_sel_frame(struct net_device *dev,
+			    struct ieee80211_mgmt *mgmt,
+			    size_t len)
+{
+	struct ieee802_11_elems elems;
+	size_t baselen;
+	u32 last_hop_metric;
+
+	baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt;
+	ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable,
+			len - baselen, &elems);
+
+	switch (mgmt->u.action.u.mesh_action.action_code) {
+	case MPATH_PREQ:
+		if (!elems.preq || elems.preq_len != 37)
+			/* Right now we support just 1 destination and no AE */
+			return;
+		last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq);
+		if (!last_hop_metric)
+			return;
+		hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric);
+		break;
+	case MPATH_PREP:
+		if (!elems.prep || elems.prep_len != 31)
+			/* Right now we support no AE */
+			return;
+		last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep);
+		if (!last_hop_metric)
+			return;
+		hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric);
+		break;
+	case MPATH_PERR:
+		if (!elems.perr || elems.perr_len != 12)
+			/* Right now we support only one destination per PERR */
+			return;
+		hwmp_perr_frame_process(dev, mgmt, elems.perr);
+	default:
+		return;
+	}
+
+}
+
+/**
+ * mesh_queue_preq - queue a PREQ to a given destination
+ *
+ * @mpath: mesh path to discover
+ * @flags: special attributes of the PREQ to be sent
+ *
+ * Locking: the function must be called from within a rcu read lock block.
+ *
+ */
+static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
+{
+	struct ieee80211_sub_if_data *sdata =
+		IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct mesh_preq_queue *preq_node;
+
+	preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL);
+	if (!preq_node) {
+		printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n");
+		return;
+	}
+
+	spin_lock(&ifsta->mesh_preq_queue_lock);
+	if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) {
+		spin_unlock(&ifsta->mesh_preq_queue_lock);
+		kfree(preq_node);
+		if (printk_ratelimit())
+			printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n");
+		return;
+	}
+
+	memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
+	preq_node->flags = flags;
+
+	list_add_tail(&preq_node->list, &ifsta->preq_queue.list);
+	++ifsta->preq_queue_len;
+	spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+	if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata)))
+		queue_work(sdata->local->hw.workqueue, &ifsta->work);
+
+	else if (time_before(jiffies, ifsta->last_preq)) {
+		/* avoid long wait if did not send preqs for a long time
+		 * and jiffies wrapped around
+		 */
+		ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
+		queue_work(sdata->local->hw.workqueue, &ifsta->work);
+	} else
+		mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq +
+						min_preq_int_jiff(sdata));
+}
+
+/**
+ * mesh_path_start_discovery - launch a path discovery from the PREQ queue
+ *
+ * @dev: local mesh interface
+ */
+void mesh_path_start_discovery(struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata =
+		IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+	struct mesh_preq_queue *preq_node;
+	struct mesh_path *mpath;
+	u8 ttl, dst_flags;
+	u32 lifetime;
+
+	spin_lock(&ifsta->mesh_preq_queue_lock);
+	if (!ifsta->preq_queue_len ||
+		time_before(jiffies, ifsta->last_preq +
+				min_preq_int_jiff(sdata))) {
+		spin_unlock(&ifsta->mesh_preq_queue_lock);
+		return;
+	}
+
+	preq_node = list_first_entry(&ifsta->preq_queue.list,
+			struct mesh_preq_queue, list);
+	list_del(&preq_node->list);
+	--ifsta->preq_queue_len;
+	spin_unlock(&ifsta->mesh_preq_queue_lock);
+
+	rcu_read_lock();
+	mpath = mesh_path_lookup(preq_node->dst, dev);
+	if (!mpath)
+		goto enddiscovery;
+
+	spin_lock_bh(&mpath->state_lock);
+	if (preq_node->flags & PREQ_Q_F_START) {
+		if (mpath->flags & MESH_PATH_RESOLVING) {
+			spin_unlock_bh(&mpath->state_lock);
+			goto enddiscovery;
+		} else {
+			mpath->flags &= ~MESH_PATH_RESOLVED;
+			mpath->flags |= MESH_PATH_RESOLVING;
+			mpath->discovery_retries = 0;
+			mpath->discovery_timeout = disc_timeout_jiff(sdata);
+		}
+	} else if (!(mpath->flags & MESH_PATH_RESOLVING) ||
+			mpath->flags & MESH_PATH_RESOLVED) {
+		mpath->flags &= ~MESH_PATH_RESOLVING;
+		spin_unlock_bh(&mpath->state_lock);
+		goto enddiscovery;
+	}
+
+	ifsta->last_preq = jiffies;
+
+	if (time_after(jiffies, ifsta->last_dsn_update +
+				net_traversal_jiffies(sdata)) ||
+	    time_before(jiffies, ifsta->last_dsn_update)) {
+		++ifsta->dsn;
+		sdata->u.sta.last_dsn_update = jiffies;
+	}
+	lifetime = default_lifetime(sdata);
+	ttl = sdata->u.sta.mshcfg.dot11MeshTTL;
+	if (ttl == 0) {
+		sdata->u.sta.mshstats.dropped_frames_ttl++;
+		spin_unlock_bh(&mpath->state_lock);
+		goto enddiscovery;
+	}
+
+	if (preq_node->flags & PREQ_Q_F_REFRESH)
+		dst_flags = MP_F_DO;
+	else
+		dst_flags = MP_F_RF;
+
+	spin_unlock_bh(&mpath->state_lock);
+	mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr,
+			cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst,
+			cpu_to_le32(mpath->dsn), dev->broadcast, 0,
+			ttl, cpu_to_le32(lifetime), 0,
+			cpu_to_le32(ifsta->preq_id++), dev);
+	mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout);
+
+enddiscovery:
+	rcu_read_unlock();
+	kfree(preq_node);
+}
+
+/**
+ * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame
+ *
+ * @next_hop: output argument for next hop address
+ * @skb: frame to be sent
+ * @dev: network device the frame will be sent through
+ *
+ * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is
+ * found, the function will start a path discovery and queue the frame so it is
+ * sent when the path is resolved. This means the caller must not free the skb
+ * in this case.
+ */
+int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb,
+		struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sk_buff *skb_to_free = NULL;
+	struct mesh_path *mpath;
+	int err = 0;
+
+	rcu_read_lock();
+	mpath = mesh_path_lookup(skb->data, dev);
+
+	if (!mpath) {
+		mesh_path_add(skb->data, dev);
+		mpath = mesh_path_lookup(skb->data, dev);
+		if (!mpath) {
+			dev_kfree_skb(skb);
+			sdata->u.sta.mshstats.dropped_frames_no_route++;
+			err = -ENOSPC;
+			goto endlookup;
+		}
+	}
+
+	if (mpath->flags & MESH_PATH_ACTIVE) {
+		if (time_after(jiffies, mpath->exp_time -
+			msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time))
+				&& skb->pkt_type != PACKET_OTHERHOST
+				&& !(mpath->flags & MESH_PATH_RESOLVING)
+				&& !(mpath->flags & MESH_PATH_FIXED)) {
+			mesh_queue_preq(mpath,
+					PREQ_Q_F_START | PREQ_Q_F_REFRESH);
+		}
+		memcpy(next_hop, mpath->next_hop->addr,
+				ETH_ALEN);
+	} else {
+		if (!(mpath->flags & MESH_PATH_RESOLVING)) {
+			/* Start discovery only if it is not running yet */
+			mesh_queue_preq(mpath, PREQ_Q_F_START);
+		}
+
+		if (skb_queue_len(&mpath->frame_queue) >=
+				MESH_FRAME_QUEUE_LEN) {
+			skb_to_free = mpath->frame_queue.next;
+			skb_unlink(skb_to_free, &mpath->frame_queue);
+		}
+
+		skb_queue_tail(&mpath->frame_queue, skb);
+		if (skb_to_free)
+			mesh_path_discard_frame(skb_to_free, dev);
+		err = -ENOENT;
+	}
+
+endlookup:
+	rcu_read_unlock();
+	return err;
+}
+
+void mesh_path_timer(unsigned long data)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct mesh_path *mpath;
+
+	rcu_read_lock();
+	mpath = (struct mesh_path *) data;
+	mpath = rcu_dereference(mpath);
+	if (!mpath)
+		goto endmpathtimer;
+	spin_lock_bh(&mpath->state_lock);
+	sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+	if (mpath->flags & MESH_PATH_RESOLVED ||
+			(!(mpath->flags & MESH_PATH_RESOLVING)))
+		mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
+	else if (mpath->discovery_retries < max_preq_retries(sdata)) {
+		++mpath->discovery_retries;
+		mpath->discovery_timeout *= 2;
+		mesh_queue_preq(mpath, 0);
+	} else {
+		mpath->flags = 0;
+		mpath->exp_time = jiffies;
+		mesh_path_flush_pending(mpath);
+	}
+
+	spin_unlock_bh(&mpath->state_lock);
+endmpathtimer:
+	rcu_read_unlock();
+}
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
new file mode 100644
index 000000000000..5845dc21ce85
--- /dev/null
+++ b/net/mac80211/mesh_pathtbl.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author:     Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "mesh.h"
+
+/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */
+#define INIT_PATHS_SIZE_ORDER	2
+
+/* Keep the mean chain length below this constant */
+#define MEAN_CHAIN_LEN		2
+
+#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \
+				time_after(jiffies, mpath->exp_time) && \
+				!(mpath->flags & MESH_PATH_FIXED))
+
+struct mpath_node {
+	struct hlist_node list;
+	struct rcu_head rcu;
+	/* This indirection allows two different tables to point to the same
+	 * mesh_path structure, useful when resizing
+	 */
+	struct mesh_path *mpath;
+};
+
+static struct mesh_table *mesh_paths;
+
+/* This lock will have the grow table function as writer and add / delete nodes
+ * as readers. When reading the table (i.e. doing lookups) we are well protected
+ * by RCU
+ */
+static DEFINE_RWLOCK(pathtbl_resize_lock);
+
+/**
+ *
+ * mesh_path_assign_nexthop - update mesh path next hop
+ *
+ * @mpath: mesh path to update
+ * @sta: next hop to assign
+ *
+ * Locking: mpath->state_lock must be held when calling this function
+ */
+void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
+{
+	rcu_assign_pointer(mpath->next_hop, sta);
+}
+
+
+/**
+ * mesh_path_lookup - look up a path in the mesh path table
+ * @dst: hardware address (ETH_ALEN length) of destination
+ * @dev: local interface
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev)
+{
+	struct mesh_path *mpath;
+	struct hlist_node *n;
+	struct hlist_head *bucket;
+	struct mesh_table *tbl;
+	struct mpath_node *node;
+
+	tbl = rcu_dereference(mesh_paths);
+
+	bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)];
+	hlist_for_each_entry_rcu(node, n, bucket, list) {
+		mpath = node->mpath;
+		if (mpath->dev == dev &&
+				memcmp(dst, mpath->dst, ETH_ALEN) == 0) {
+			if (MPATH_EXPIRED(mpath)) {
+				spin_lock_bh(&mpath->state_lock);
+				if (MPATH_EXPIRED(mpath))
+					mpath->flags &= ~MESH_PATH_ACTIVE;
+				spin_unlock_bh(&mpath->state_lock);
+			}
+			return mpath;
+		}
+	}
+	return NULL;
+}
+
+/**
+ * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index
+ * @idx: index
+ * @dev: local interface, or NULL for all entries
+ *
+ * Returns: pointer to the mesh path structure, or NULL if not found.
+ *
+ * Locking: must be called within a read rcu section.
+ */
+struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev)
+{
+	struct mpath_node *node;
+	struct hlist_node *p;
+	int i;
+	int j = 0;
+
+	for_each_mesh_entry(mesh_paths, p, node, i) {
+		if (dev && node->mpath->dev != dev)
+			continue;
+		if (j++ == idx) {
+			if (MPATH_EXPIRED(node->mpath)) {
+				spin_lock_bh(&node->mpath->state_lock);
+				if (MPATH_EXPIRED(node->mpath))
+					node->mpath->flags &= ~MESH_PATH_ACTIVE;
+				spin_unlock_bh(&node->mpath->state_lock);
+			}
+			return node->mpath;
+		}
+	}
+
+	return NULL;
+}
+
+/**
+ * mesh_path_add - allocate and add a new path to the mesh path table
+ * @addr: destination address of the path (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 on sucess
+ *
+ * State: the initial state of the new path is set to 0
+ */
+int mesh_path_add(u8 *dst, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath, *new_mpath;
+	struct mpath_node *node, *new_node;
+	struct hlist_head *bucket;
+	struct hlist_node *n;
+	int grow = 0;
+	int err = 0;
+	u32 hash_idx;
+
+	if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0)
+		/* never add ourselves as neighbours */
+		return -ENOTSUPP;
+
+	if (is_multicast_ether_addr(dst))
+		return -ENOTSUPP;
+
+	if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0)
+		return -ENOSPC;
+
+	read_lock(&pathtbl_resize_lock);
+
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	if (!new_mpath) {
+		atomic_dec(&sdata->u.sta.mpaths);
+		err = -ENOMEM;
+		goto endadd2;
+	}
+	memcpy(new_mpath->dst, dst, ETH_ALEN);
+	new_mpath->dev = dev;
+	new_mpath->flags = 0;
+	skb_queue_head_init(&new_mpath->frame_queue);
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node->mpath = new_mpath;
+	new_mpath->timer.data = (unsigned long) new_mpath;
+	new_mpath->timer.function = mesh_path_timer;
+	new_mpath->exp_time = jiffies;
+	spin_lock_init(&new_mpath->state_lock);
+	init_timer(&new_mpath->timer);
+
+	hash_idx = mesh_table_hash(dst, dev, mesh_paths);
+	bucket = &mesh_paths->hash_buckets[hash_idx];
+
+	spin_lock(&mesh_paths->hashwlock[hash_idx]);
+
+	hlist_for_each_entry(node, n, bucket, list) {
+		mpath = node->mpath;
+		if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN)
+				== 0) {
+			err = -EEXIST;
+			atomic_dec(&sdata->u.sta.mpaths);
+			kfree(new_node);
+			kfree(new_mpath);
+			goto endadd;
+		}
+	}
+
+	hlist_add_head_rcu(&new_node->list, bucket);
+	if (atomic_inc_return(&mesh_paths->entries) >=
+		mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1))
+		grow = 1;
+
+endadd:
+	spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+endadd2:
+	read_unlock(&pathtbl_resize_lock);
+	if (!err && grow) {
+		struct mesh_table *oldtbl, *newtbl;
+
+		write_lock(&pathtbl_resize_lock);
+		oldtbl = mesh_paths;
+		newtbl = mesh_table_grow(mesh_paths);
+		if (!newtbl) {
+			write_unlock(&pathtbl_resize_lock);
+			return -ENOMEM;
+		}
+		rcu_assign_pointer(mesh_paths, newtbl);
+		synchronize_rcu();
+		mesh_table_free(oldtbl, false);
+		write_unlock(&pathtbl_resize_lock);
+	}
+	return err;
+}
+
+
+/**
+ * mesh_plink_broken - deactivates paths and sends perr when a link breaks
+ *
+ * @sta: broken peer link
+ *
+ * This function must be called from the rate control algorithm if enough
+ * delivery errors suggest that a peer link is no longer usable.
+ */
+void mesh_plink_broken(struct sta_info *sta)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node;
+	struct hlist_node *p;
+	struct net_device *dev = sta->sdata->dev;
+	int i;
+
+	rcu_read_lock();
+	for_each_mesh_entry(mesh_paths, p, node, i) {
+		mpath = node->mpath;
+		spin_lock_bh(&mpath->state_lock);
+		if (mpath->next_hop == sta &&
+		    mpath->flags & MESH_PATH_ACTIVE &&
+		    !(mpath->flags & MESH_PATH_FIXED)) {
+			mpath->flags &= ~MESH_PATH_ACTIVE;
+			++mpath->dsn;
+			spin_unlock_bh(&mpath->state_lock);
+			mesh_path_error_tx(mpath->dst,
+					cpu_to_le32(mpath->dsn),
+					dev->broadcast, dev);
+		} else
+		spin_unlock_bh(&mpath->state_lock);
+	}
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL(mesh_plink_broken);
+
+/**
+ * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches
+ *
+ * @sta - mesh peer to match
+ *
+ * RCU notes: this function is called when a mesh plink transitions from
+ * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that
+ * allows path creation. This will happen before the sta can be freed (because
+ * sta_info_destroy() calls this) so any reader in a rcu read block will be
+ * protected against the plink disappearing.
+ */
+void mesh_path_flush_by_nexthop(struct sta_info *sta)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node;
+	struct hlist_node *p;
+	int i;
+
+	for_each_mesh_entry(mesh_paths, p, node, i) {
+		mpath = node->mpath;
+		if (mpath->next_hop == sta)
+			mesh_path_del(mpath->dst, mpath->dev);
+	}
+}
+
+void mesh_path_flush(struct net_device *dev)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node;
+	struct hlist_node *p;
+	int i;
+
+	for_each_mesh_entry(mesh_paths, p, node, i) {
+		mpath = node->mpath;
+		if (mpath->dev == dev)
+			mesh_path_del(mpath->dst, mpath->dev);
+	}
+}
+
+static void mesh_path_node_reclaim(struct rcu_head *rp)
+{
+	struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
+	struct ieee80211_sub_if_data *sdata =
+		IEEE80211_DEV_TO_SUB_IF(node->mpath->dev);
+
+	del_timer_sync(&node->mpath->timer);
+	atomic_dec(&sdata->u.sta.mpaths);
+	kfree(node->mpath);
+	kfree(node);
+}
+
+/**
+ * mesh_path_del - delete a mesh path from the table
+ *
+ * @addr: dst address (ETH_ALEN length)
+ * @dev: local interface
+ *
+ * Returns: 0 if succesful
+ */
+int mesh_path_del(u8 *addr, struct net_device *dev)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node;
+	struct hlist_head *bucket;
+	struct hlist_node *n;
+	int hash_idx;
+	int err = 0;
+
+	read_lock(&pathtbl_resize_lock);
+	hash_idx = mesh_table_hash(addr, dev, mesh_paths);
+	bucket = &mesh_paths->hash_buckets[hash_idx];
+
+	spin_lock(&mesh_paths->hashwlock[hash_idx]);
+	hlist_for_each_entry(node, n, bucket, list) {
+		mpath = node->mpath;
+		if (mpath->dev == dev &&
+				memcmp(addr, mpath->dst, ETH_ALEN) == 0) {
+			spin_lock_bh(&mpath->state_lock);
+			mpath->flags |= MESH_PATH_RESOLVING;
+			hlist_del_rcu(&node->list);
+			call_rcu(&node->rcu, mesh_path_node_reclaim);
+			atomic_dec(&mesh_paths->entries);
+			spin_unlock_bh(&mpath->state_lock);
+			goto enddel;
+		}
+	}
+
+	err = -ENXIO;
+enddel:
+	spin_unlock(&mesh_paths->hashwlock[hash_idx]);
+	read_unlock(&pathtbl_resize_lock);
+	return err;
+}
+
+/**
+ * mesh_path_tx_pending - sends pending frames in a mesh path queue
+ *
+ * @mpath: mesh path to activate
+ *
+ * Locking: the state_lock of the mpath structure must NOT be held when calling
+ * this function.
+ */
+void mesh_path_tx_pending(struct mesh_path *mpath)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+			(mpath->flags & MESH_PATH_ACTIVE))
+		dev_queue_xmit(skb);
+}
+
+/**
+ * mesh_path_discard_frame - discard a frame whose path could not be resolved
+ *
+ * @skb: frame to discard
+ * @dev: network device the frame was to be sent through
+ *
+ * If the frame was beign forwarded from another MP, a PERR frame will be sent
+ * to the precursor.
+ *
+ * Locking: the function must me called within a rcu_read_lock region
+ */
+void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct mesh_path *mpath;
+	u32 dsn = 0;
+
+	if (skb->pkt_type == PACKET_OTHERHOST) {
+		struct ieee80211s_hdr *prev_meshhdr;
+		int mshhdrlen;
+		u8 *ra, *da;
+
+		prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+		mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+		da = skb->data;
+		ra = MESH_PREQ(skb);
+		mpath = mesh_path_lookup(da, dev);
+		if (mpath)
+			dsn = ++mpath->dsn;
+		mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev);
+	}
+
+	kfree_skb(skb);
+	sdata->u.sta.mshstats.dropped_frames_no_route++;
+}
+
+/**
+ * mesh_path_flush_pending - free the pending queue of a mesh path
+ *
+ * @mpath: mesh path whose queue has to be freed
+ *
+ * Locking: the function must me called withing a rcu_read_lock region
+ */
+void mesh_path_flush_pending(struct mesh_path *mpath)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct sk_buff *skb;
+
+	sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev);
+
+	while ((skb = skb_dequeue(&mpath->frame_queue)) &&
+			(mpath->flags & MESH_PATH_ACTIVE))
+		mesh_path_discard_frame(skb, mpath->dev);
+}
+
+/**
+ * mesh_path_fix_nexthop - force a specific next hop for a mesh path
+ *
+ * @mpath: the mesh path to modify
+ * @next_hop: the next hop to force
+ *
+ * Locking: this function must be called holding mpath->state_lock
+ */
+void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop)
+{
+	spin_lock_bh(&mpath->state_lock);
+	mesh_path_assign_nexthop(mpath, next_hop);
+	mpath->dsn = 0xffff;
+	mpath->metric = 0;
+	mpath->hop_count = 0;
+	mpath->exp_time = 0;
+	mpath->flags |= MESH_PATH_FIXED;
+	mesh_path_activate(mpath);
+	spin_unlock_bh(&mpath->state_lock);
+	mesh_path_tx_pending(mpath);
+}
+
+static void mesh_path_node_free(struct hlist_node *p, bool free_leafs)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node = hlist_entry(p, struct mpath_node, list);
+	mpath = node->mpath;
+	hlist_del_rcu(p);
+	synchronize_rcu();
+	if (free_leafs)
+		kfree(mpath);
+	kfree(node);
+}
+
+static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node, *new_node;
+	u32 hash_idx;
+
+	node = hlist_entry(p, struct mpath_node, list);
+	mpath = node->mpath;
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node->mpath = mpath;
+	hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl);
+	hlist_add_head(&new_node->list,
+			&newtbl->hash_buckets[hash_idx]);
+}
+
+int mesh_pathtbl_init(void)
+{
+	mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER);
+	mesh_paths->free_node = &mesh_path_node_free;
+	mesh_paths->copy_node = &mesh_path_node_copy;
+	mesh_paths->mean_chain_len = MEAN_CHAIN_LEN;
+	if (!mesh_paths)
+		return -ENOMEM;
+	return 0;
+}
+
+void mesh_path_expire(struct net_device *dev)
+{
+	struct mesh_path *mpath;
+	struct mpath_node *node;
+	struct hlist_node *p;
+	int i;
+
+	read_lock(&pathtbl_resize_lock);
+	for_each_mesh_entry(mesh_paths, p, node, i) {
+		if (node->mpath->dev != dev)
+			continue;
+		mpath = node->mpath;
+		spin_lock_bh(&mpath->state_lock);
+		if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
+		    (!(mpath->flags & MESH_PATH_FIXED)) &&
+			time_after(jiffies,
+			 mpath->exp_time + MESH_PATH_EXPIRE)) {
+			spin_unlock_bh(&mpath->state_lock);
+			mesh_path_del(mpath->dst, mpath->dev);
+		} else
+			spin_unlock_bh(&mpath->state_lock);
+	}
+	read_unlock(&pathtbl_resize_lock);
+}
+
+void mesh_pathtbl_unregister(void)
+{
+	mesh_table_free(mesh_paths, true);
+}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
new file mode 100644
index 000000000000..56c54e321b38
--- /dev/null
+++ b/net/mac80211/mesh_plink.c
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author:     Luis Carlos Cobo <luisca@cozybit.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/random.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "mesh.h"
+
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+#define mpl_dbg(fmt, args...)	printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpl_dbg(fmt, args...)	do { (void)(0); } while (0)
+#endif
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+#define PLINK_GET_FRAME_SUBTYPE(p) (p)
+#define PLINK_GET_LLID(p) (p + 1)
+#define PLINK_GET_PLID(p) (p + 3)
+
+#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
+				jiffies + HZ * t / 1000))
+
+/* Peer link cancel reasons, all subject to ANA approval */
+#define MESH_LINK_CANCELLED			2
+#define MESH_MAX_NEIGHBORS			3
+#define MESH_CAPABILITY_POLICY_VIOLATION	4
+#define MESH_CLOSE_RCVD				5
+#define MESH_MAX_RETRIES			6
+#define MESH_CONFIRM_TIMEOUT			7
+#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS	8
+#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE	9
+#define MESH_SECURITY_FAILED_VERIFICATION	10
+
+#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+
+enum plink_frame_type {
+	PLINK_OPEN = 0,
+	PLINK_CONFIRM,
+	PLINK_CLOSE
+};
+
+enum plink_event {
+	PLINK_UNDEFINED,
+	OPN_ACPT,
+	OPN_RJCT,
+	OPN_IGNR,
+	CNF_ACPT,
+	CNF_RJCT,
+	CNF_IGNR,
+	CLS_ACPT,
+	CLS_IGNR
+};
+
+static inline
+void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+	atomic_inc(&sdata->u.sta.mshstats.estab_plinks);
+	mesh_accept_plinks_update(sdata);
+}
+
+static inline
+void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+{
+	atomic_dec(&sdata->u.sta.mshstats.estab_plinks);
+	mesh_accept_plinks_update(sdata);
+}
+
+/**
+ * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
+ *
+ * @sta: mes peer link to restart
+ *
+ * Locking: this function must be called holding sta->plink_lock
+ */
+static inline void mesh_plink_fsm_restart(struct sta_info *sta)
+{
+	sta->plink_state = PLINK_LISTEN;
+	sta->llid = sta->plid = sta->reason = 0;
+	sta->plink_retries = 0;
+}
+
+/*
+ * NOTE: This is just an alias for sta_info_alloc(), see notes
+ *       on it in the lifecycle management section!
+ */
+static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
+					 u8 *hw_addr, u64 rates)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct sta_info *sta;
+
+	if (local->num_sta >= MESH_MAX_PLINKS)
+		return NULL;
+
+	sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC);
+	if (!sta)
+		return NULL;
+
+	sta->flags |= WLAN_STA_AUTHORIZED;
+	sta->supp_rates[local->hw.conf.channel->band] = rates;
+
+	return sta;
+}
+
+/**
+ * mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ *
+ * Locking: the caller must hold sta->plink_lock
+ */
+static void __mesh_plink_deactivate(struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+	if (sta->plink_state == PLINK_ESTAB)
+		mesh_plink_dec_estab_count(sdata);
+	sta->plink_state = PLINK_BLOCKED;
+	mesh_path_flush_by_nexthop(sta);
+}
+
+/**
+ * __mesh_plink_deactivate - deactivate mesh peer link
+ *
+ * @sta: mesh peer link to deactivate
+ *
+ * All mesh paths with this peer as next hop will be flushed
+ */
+void mesh_plink_deactivate(struct sta_info *sta)
+{
+	spin_lock_bh(&sta->plink_lock);
+	__mesh_plink_deactivate(sta);
+	spin_unlock_bh(&sta->plink_lock);
+}
+
+static int mesh_plink_frame_tx(struct net_device *dev,
+		enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
+		__le16 reason) {
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+	struct ieee80211_mgmt *mgmt;
+	bool include_plid = false;
+	u8 *pos;
+	int ie_len;
+
+	if (!skb)
+		return -1;
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+	/* 25 is the size of the common mgmt part (24) plus the size of the
+	 * common action part (1)
+	 */
+	mgmt = (struct ieee80211_mgmt *)
+		skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
+	memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+	mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+					   IEEE80211_STYPE_ACTION);
+	memcpy(mgmt->da, da, ETH_ALEN);
+	memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+	/* BSSID is left zeroed, wildcard value */
+	mgmt->u.action.category = PLINK_CATEGORY;
+	mgmt->u.action.u.plink_action.action_code = action;
+
+	if (action == PLINK_CLOSE)
+		mgmt->u.action.u.plink_action.aux = reason;
+	else {
+		mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
+		if (action == PLINK_CONFIRM) {
+			pos = skb_put(skb, 4);
+			/* two-byte status code followed by two-byte AID */
+			memset(pos, 0, 4);
+		}
+		mesh_mgmt_ies_add(skb, dev);
+	}
+
+	/* Add Peer Link Management element */
+	switch (action) {
+	case PLINK_OPEN:
+		ie_len = 3;
+		break;
+	case PLINK_CONFIRM:
+		ie_len = 5;
+		include_plid = true;
+		break;
+	case PLINK_CLOSE:
+	default:
+		if (!plid)
+			ie_len = 5;
+		else {
+			ie_len = 7;
+			include_plid = true;
+		}
+		break;
+	}
+
+	pos = skb_put(skb, 2 + ie_len);
+	*pos++ = WLAN_EID_PEER_LINK;
+	*pos++ = ie_len;
+	*pos++ = action;
+	memcpy(pos, &llid, 2);
+	if (include_plid) {
+		pos += 2;
+		memcpy(pos, &plid, 2);
+	}
+	if (action == PLINK_CLOSE) {
+		pos += 2;
+		memcpy(pos, &reason, 2);
+	}
+
+	ieee80211_sta_tx(dev, skb, 0);
+	return 0;
+}
+
+void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev,
+			   bool peer_accepting_plinks)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct sta_info *sta;
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, hw_addr);
+	if (!sta) {
+		sta = mesh_plink_alloc(sdata, hw_addr, rates);
+		if (!sta) {
+			rcu_read_unlock();
+			return;
+		}
+		if (sta_info_insert(sta)) {
+			rcu_read_unlock();
+			return;
+		}
+	}
+
+	sta->last_rx = jiffies;
+	sta->supp_rates[local->hw.conf.channel->band] = rates;
+	if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
+			sdata->u.sta.accepting_plinks &&
+			sdata->u.sta.mshcfg.auto_open_plinks)
+		mesh_plink_open(sta);
+
+	rcu_read_unlock();
+}
+
+static void mesh_plink_timer(unsigned long data)
+{
+	struct sta_info *sta;
+	__le16 llid, plid, reason;
+	struct net_device *dev = NULL;
+	struct ieee80211_sub_if_data *sdata;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
+
+	/*
+	 * This STA is valid because sta_info_destroy() will
+	 * del_timer_sync() this timer after having made sure
+	 * it cannot be readded (by deleting the plink.)
+	 */
+	sta = (struct sta_info *) data;
+
+	spin_lock_bh(&sta->plink_lock);
+	if (sta->ignore_plink_timer) {
+		sta->ignore_plink_timer = false;
+		spin_unlock_bh(&sta->plink_lock);
+		return;
+	}
+	mpl_dbg("Mesh plink timer for %s fired on state %d\n",
+			print_mac(mac, sta->addr), sta->plink_state);
+	reason = 0;
+	llid = sta->llid;
+	plid = sta->plid;
+	sdata = sta->sdata;
+	dev = sdata->dev;
+
+	switch (sta->plink_state) {
+	case PLINK_OPN_RCVD:
+	case PLINK_OPN_SNT:
+		/* retry timer */
+		if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
+			u32 rand;
+			mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
+					print_mac(mac, sta->addr),
+					sta->plink_retries, sta->plink_timeout);
+			get_random_bytes(&rand, sizeof(u32));
+			sta->plink_timeout = sta->plink_timeout +
+					     rand % sta->plink_timeout;
+			++sta->plink_retries;
+			mod_plink_timer(sta, sta->plink_timeout);
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+					    0, 0);
+			break;
+		}
+		reason = cpu_to_le16(MESH_MAX_RETRIES);
+		/* fall through on else */
+	case PLINK_CNF_RCVD:
+		/* confirm timer */
+		if (!reason)
+			reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+		sta->plink_state = PLINK_HOLDING;
+		mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+		spin_unlock_bh(&sta->plink_lock);
+		mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid,
+				    reason);
+		break;
+	case PLINK_HOLDING:
+		/* holding timer */
+		del_timer(&sta->plink_timer);
+		mesh_plink_fsm_restart(sta);
+		spin_unlock_bh(&sta->plink_lock);
+		break;
+	default:
+		spin_unlock_bh(&sta->plink_lock);
+		break;
+	}
+}
+
+static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
+{
+	sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
+	sta->plink_timer.data = (unsigned long) sta;
+	sta->plink_timer.function = mesh_plink_timer;
+	sta->plink_timeout = timeout;
+	add_timer(&sta->plink_timer);
+}
+
+int mesh_plink_open(struct sta_info *sta)
+{
+	__le16 llid;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
+
+	spin_lock_bh(&sta->plink_lock);
+	get_random_bytes(&llid, 2);
+	sta->llid = llid;
+	if (sta->plink_state != PLINK_LISTEN) {
+		spin_unlock_bh(&sta->plink_lock);
+		return -EBUSY;
+	}
+	sta->plink_state = PLINK_OPN_SNT;
+	mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+	spin_unlock_bh(&sta->plink_lock);
+	mpl_dbg("Mesh plink: starting establishment with %s\n",
+		print_mac(mac, sta->addr));
+
+	return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN,
+				   sta->addr, llid, 0, 0);
+}
+
+void mesh_plink_block(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
+
+	spin_lock_bh(&sta->plink_lock);
+	__mesh_plink_deactivate(sta);
+	sta->plink_state = PLINK_BLOCKED;
+	spin_unlock_bh(&sta->plink_lock);
+}
+
+int mesh_plink_close(struct sta_info *sta)
+{
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	__le16 llid, plid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
+
+	mpl_dbg("Mesh plink: closing link with %s\n",
+			print_mac(mac, sta->addr));
+	spin_lock_bh(&sta->plink_lock);
+	sta->reason = cpu_to_le16(MESH_LINK_CANCELLED);
+	reason = sta->reason;
+
+	if (sta->plink_state == PLINK_LISTEN ||
+	    sta->plink_state == PLINK_BLOCKED) {
+		mesh_plink_fsm_restart(sta);
+		spin_unlock_bh(&sta->plink_lock);
+		return 0;
+	} else if (sta->plink_state == PLINK_ESTAB) {
+		__mesh_plink_deactivate(sta);
+		/* The timer should not be running */
+		mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+	} else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)))
+		sta->ignore_plink_timer = true;
+
+	sta->plink_state = PLINK_HOLDING;
+	llid = sta->llid;
+	plid = sta->plid;
+	spin_unlock_bh(&sta->plink_lock);
+	mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid,
+			    plid, reason);
+	return 0;
+}
+
+void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt,
+			 size_t len, struct ieee80211_rx_status *rx_status)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee802_11_elems elems;
+	struct sta_info *sta;
+	enum plink_event event;
+	enum plink_frame_type ftype;
+	size_t baselen;
+	u8 ie_len;
+	u8 *baseaddr;
+	__le16 plid, llid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
+
+	if (is_multicast_ether_addr(mgmt->da)) {
+		mpl_dbg("Mesh plink: ignore frame from multicast address");
+		return;
+	}
+
+	baseaddr = mgmt->u.action.u.plink_action.variable;
+	baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
+	if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+		baseaddr += 4;
+		baselen -= 4;
+	}
+	ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
+	if (!elems.peer_link) {
+		mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+		return;
+	}
+
+	ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
+	ie_len = elems.peer_link_len;
+	if ((ftype == PLINK_OPEN && ie_len != 3) ||
+	    (ftype == PLINK_CONFIRM && ie_len != 5) ||
+	    (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) {
+		mpl_dbg("Mesh plink: incorrect plink ie length\n");
+		return;
+	}
+
+	if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+		mpl_dbg("Mesh plink: missing necessary ie\n");
+		return;
+	}
+	/* Note the lines below are correct, the llid in the frame is the plid
+	 * from the point of view of this host.
+	 */
+	memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
+	if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
+		memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+
+	rcu_read_lock();
+
+	sta = sta_info_get(local, mgmt->sa);
+	if (!sta && ftype != PLINK_OPEN) {
+		mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+		rcu_read_unlock();
+		return;
+	}
+
+	if (sta && sta->plink_state == PLINK_BLOCKED) {
+		rcu_read_unlock();
+		return;
+	}
+
+	/* Now we will figure out the appropriate event... */
+	event = PLINK_UNDEFINED;
+	if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) {
+		switch (ftype) {
+		case PLINK_OPEN:
+			event = OPN_RJCT;
+			break;
+		case PLINK_CONFIRM:
+			event = CNF_RJCT;
+			break;
+		case PLINK_CLOSE:
+			/* avoid warning */
+			break;
+		}
+		spin_lock_bh(&sta->plink_lock);
+	} else if (!sta) {
+		/* ftype == PLINK_OPEN */
+		u64 rates;
+		if (!mesh_plink_free_count(sdata)) {
+			mpl_dbg("Mesh plink error: no more free plinks\n");
+			rcu_read_unlock();
+			return;
+		}
+
+		rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
+		sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
+		if (!sta) {
+			mpl_dbg("Mesh plink error: plink table full\n");
+			rcu_read_unlock();
+			return;
+		}
+		if (sta_info_insert(sta)) {
+			rcu_read_unlock();
+			return;
+		}
+		event = OPN_ACPT;
+		spin_lock_bh(&sta->plink_lock);
+	} else {
+		spin_lock_bh(&sta->plink_lock);
+		switch (ftype) {
+		case PLINK_OPEN:
+			if (!mesh_plink_free_count(sdata) ||
+			    (sta->plid && sta->plid != plid))
+				event = OPN_IGNR;
+			else
+				event = OPN_ACPT;
+			break;
+		case PLINK_CONFIRM:
+			if (!mesh_plink_free_count(sdata) ||
+			    (sta->llid != llid || sta->plid != plid))
+				event = CNF_IGNR;
+			else
+				event = CNF_ACPT;
+			break;
+		case PLINK_CLOSE:
+			if (sta->plink_state == PLINK_ESTAB)
+				/* Do not check for llid or plid. This does not
+				 * follow the standard but since multiple plinks
+				 * per sta are not supported, it is necessary in
+				 * order to avoid a livelock when MP A sees an
+				 * establish peer link to MP B but MP B does not
+				 * see it. This can be caused by a timeout in
+				 * B's peer link establishment or B beign
+				 * restarted.
+				 */
+				event = CLS_ACPT;
+			else if (sta->plid != plid)
+				event = CLS_IGNR;
+			else if (ie_len == 7 && sta->llid != llid)
+				event = CLS_IGNR;
+			else
+				event = CLS_ACPT;
+			break;
+		default:
+			mpl_dbg("Mesh plink: unknown frame subtype\n");
+			spin_unlock_bh(&sta->plink_lock);
+			rcu_read_unlock();
+			return;
+		}
+	}
+
+	mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n",
+			print_mac(mac, mgmt->sa), sta->plink_state,
+			le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
+			event);
+	reason = 0;
+	switch (sta->plink_state) {
+		/* spin_unlock as soon as state is updated at each case */
+	case PLINK_LISTEN:
+		switch (event) {
+		case CLS_ACPT:
+			mesh_plink_fsm_restart(sta);
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		case OPN_ACPT:
+			sta->plink_state = PLINK_OPN_RCVD;
+			sta->plid = plid;
+			get_random_bytes(&llid, 2);
+			sta->llid = llid;
+			mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid,
+					    0, 0);
+			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr,
+					    llid, plid, 0);
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		}
+		break;
+
+	case PLINK_OPN_SNT:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+		case CLS_ACPT:
+			if (!reason)
+				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+			sta->reason = reason;
+			sta->plink_state = PLINK_HOLDING;
+			if (!mod_plink_timer(sta,
+					     dot11MeshHoldingTimeout(sdata)))
+				sta->ignore_plink_timer = true;
+
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+					    plid, reason);
+			break;
+		case OPN_ACPT:
+			/* retry timer is left untouched */
+			sta->plink_state = PLINK_OPN_RCVD;
+			sta->plid = plid;
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+					    plid, 0);
+			break;
+		case CNF_ACPT:
+			sta->plink_state = PLINK_CNF_RCVD;
+			if (!mod_plink_timer(sta,
+					     dot11MeshConfirmTimeout(sdata)))
+				sta->ignore_plink_timer = true;
+
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		}
+		break;
+
+	case PLINK_OPN_RCVD:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+		case CLS_ACPT:
+			if (!reason)
+				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+			sta->reason = reason;
+			sta->plink_state = PLINK_HOLDING;
+			if (!mod_plink_timer(sta,
+					     dot11MeshHoldingTimeout(sdata)))
+				sta->ignore_plink_timer = true;
+
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+					    plid, reason);
+			break;
+		case OPN_ACPT:
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+					    plid, 0);
+			break;
+		case CNF_ACPT:
+			del_timer(&sta->plink_timer);
+			sta->plink_state = PLINK_ESTAB;
+			mesh_plink_inc_estab_count(sdata);
+			spin_unlock_bh(&sta->plink_lock);
+			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+					print_mac(mac, sta->addr));
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		}
+		break;
+
+	case PLINK_CNF_RCVD:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+		case CLS_ACPT:
+			if (!reason)
+				reason = cpu_to_le16(MESH_CLOSE_RCVD);
+			sta->reason = reason;
+			sta->plink_state = PLINK_HOLDING;
+			if (!mod_plink_timer(sta,
+					     dot11MeshHoldingTimeout(sdata)))
+				sta->ignore_plink_timer = true;
+
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+					    plid, reason);
+			break;
+		case OPN_ACPT:
+			del_timer(&sta->plink_timer);
+			sta->plink_state = PLINK_ESTAB;
+			mesh_plink_inc_estab_count(sdata);
+			spin_unlock_bh(&sta->plink_lock);
+			mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+					print_mac(mac, sta->addr));
+			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+					    plid, 0);
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		}
+		break;
+
+	case PLINK_ESTAB:
+		switch (event) {
+		case CLS_ACPT:
+			reason = cpu_to_le16(MESH_CLOSE_RCVD);
+			sta->reason = reason;
+			__mesh_plink_deactivate(sta);
+			sta->plink_state = PLINK_HOLDING;
+			llid = sta->llid;
+			mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+					    plid, reason);
+			break;
+		case OPN_ACPT:
+			llid = sta->llid;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid,
+					    plid, 0);
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		}
+		break;
+	case PLINK_HOLDING:
+		switch (event) {
+		case CLS_ACPT:
+			if (del_timer(&sta->plink_timer))
+				sta->ignore_plink_timer = 1;
+			mesh_plink_fsm_restart(sta);
+			spin_unlock_bh(&sta->plink_lock);
+			break;
+		case OPN_ACPT:
+		case CNF_ACPT:
+		case OPN_RJCT:
+		case CNF_RJCT:
+			llid = sta->llid;
+			reason = sta->reason;
+			spin_unlock_bh(&sta->plink_lock);
+			mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid,
+					    plid, reason);
+			break;
+		default:
+			spin_unlock_bh(&sta->plink_lock);
+		}
+		break;
+	default:
+		/* should not get here, PLINK_BLOCKED is dealt with at the
+		 * beggining of the function
+		 */
+		spin_unlock_bh(&sta->plink_lock);
+		break;
+	}
+
+	rcu_read_unlock();
+}
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c
index 3b77410588e7..a1993161de99 100644
--- a/net/mac80211/rc80211_pid_algo.c
+++ b/net/mac80211/rc80211_pid_algo.c
@@ -15,7 +15,7 @@
 #include <linux/debugfs.h>
 #include <net/mac80211.h>
 #include "ieee80211_rate.h"
-
+#include "mesh.h"
 #include "rc80211_pid.h"
 
 
@@ -63,6 +63,7 @@
  * RC_PID_ARITH_SHIFT.
  */
 
+
 /* 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
@@ -72,14 +73,14 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
 					 struct rc_pid_rateinfo *rinfo)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
-	int cur_sorted, new_sorted, probe, tmp, n_bitrates;
-	int cur = sta->txrate;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	struct ieee80211_supported_band *sband;
+	int cur_sorted, new_sorted, probe, tmp, n_bitrates, band;
+	int cur = sta->txrate_idx;
 
-	mode = local->oper_hw_mode;
-	n_bitrates = mode->num_rates;
+	sdata = sta->sdata;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	band = sband->band;
+	n_bitrates = sband->n_bitrates;
 
 	/* Map passed arguments to sorted values. */
 	cur_sorted = rinfo[cur].rev_index;
@@ -97,20 +98,20 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
 		/* 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))
+			    rate_supported(sta, band, 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))
+			    rate_supported(sta, band, 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;
+		if (rate_supported(sta, band, rinfo[tmp].index)) {
+			sta->txrate_idx = rinfo[tmp].index;
 			break;
 		}
 		if (adj < 0)
@@ -122,7 +123,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local,
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_rate_change(
 		&((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events,
-		cur, mode->rates[cur].rate);
+		sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate);
 #endif
 }
 
@@ -147,9 +148,12 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 				    struct ieee80211_local *local,
 				    struct sta_info *sta)
 {
+#ifdef CONFIG_MAC80211_MESH
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+#endif
 	struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv;
 	struct rc_pid_rateinfo *rinfo = pinfo->rinfo;
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	u32 pf;
 	s32 err_avg;
 	u32 err_prop;
@@ -158,7 +162,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 	int adj, i, j, tmp;
 	unsigned long period;
 
-	mode = local->oper_hw_mode;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 	spinfo = sta->rate_ctrl_priv;
 
 	/* In case nothing happened during the previous control interval, turn
@@ -177,25 +181,32 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo,
 		pf = spinfo->last_pf;
 	else {
 		pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit;
+#ifdef CONFIG_MAC80211_MESH
+		if (pf == 100 &&
+		    sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+			mesh_plink_broken(sta);
+#endif
 		pf <<= RC_PID_ARITH_SHIFT;
+		sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9)
+					>> RC_PID_ARITH_SHIFT;
 	}
 
 	spinfo->tx_num_xmit = 0;
 	spinfo->tx_num_failed = 0;
 
 	/* If we just switched rate, update the rate behaviour info. */
-	if (pinfo->oldrate != sta->txrate) {
+	if (pinfo->oldrate != sta->txrate_idx) {
 
 		i = rinfo[pinfo->oldrate].rev_index;
-		j = rinfo[sta->txrate].rev_index;
+		j = rinfo[sta->txrate_idx].rev_index;
 
 		tmp = (pf - spinfo->last_pf);
 		tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT);
 
 		rinfo[j].diff = rinfo[i].diff + tmp;
-		pinfo->oldrate = sta->txrate;
+		pinfo->oldrate = sta->txrate_idx;
 	}
-	rate_control_pid_normalize(pinfo, mode->num_rates);
+	rate_control_pid_normalize(pinfo, sband->n_bitrates);
 
 	/* Compute the proportional, integral and derivative errors. */
 	err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf;
@@ -236,23 +247,27 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 	struct sta_info *sta;
 	struct rc_pid_sta_info *spinfo;
 	unsigned long period;
+	struct ieee80211_supported_band *sband;
+
+	rcu_read_lock();
 
 	sta = sta_info_get(local, hdr->addr1);
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	if (!sta)
-		return;
+		goto unlock;
 
 	/* Don't update the state if we're not controlling the rate. */
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	sdata = sta->sdata;
 	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
-		sta->txrate = sdata->bss->max_ratectrl_rateidx;
-		return;
+		sta->txrate_idx = sdata->bss->max_ratectrl_rateidx;
+		goto unlock;
 	}
 
 	/* Ignore all frames that were sent with a different rate than the rate
 	 * we currently advise mac80211 to use. */
-	if (status->control.rate != &local->oper_hw_mode->rates[sta->txrate])
-		goto ignore;
+	if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx])
+		goto unlock;
 
 	spinfo = sta->rate_ctrl_priv;
 	spinfo->tx_num_xmit++;
@@ -277,9 +292,6 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 		sta->tx_num_consecutive_failures++;
 		sta->tx_num_mpdu_fail++;
 	} else {
-		sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
-		sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
-		sta->last_ack_rssi[2] = status->ack_signal;
 		sta->tx_num_consecutive_failures = 0;
 		sta->tx_num_mpdu_ok++;
 	}
@@ -293,12 +305,12 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev,
 	if (time_after(jiffies, spinfo->last_sample + period))
 		rate_control_pid_sample(pinfo, local, sta);
 
-ignore:
-	sta_info_put(sta);
+ unlock:
+	rcu_read_unlock();
 }
 
 static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
-				      struct ieee80211_hw_mode *mode,
+				      struct ieee80211_supported_band *sband,
 				      struct sk_buff *skb,
 				      struct rate_selection *sel)
 {
@@ -309,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 	int rateidx;
 	u16 fc;
 
+	rcu_read_lock();
+
 	sta = sta_info_get(local, hdr->addr1);
 
 	/* Send management frames and broadcast/multicast data using lowest
@@ -316,32 +330,31 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev,
 	fc = le16_to_cpu(hdr->frame_control);
 	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
 	    is_multicast_ether_addr(hdr->addr1) || !sta) {
-		sel->rate = rate_lowest(local, mode, sta);
-		if (sta)
-			sta_info_put(sta);
+		sel->rate = rate_lowest(local, sband, sta);
+		rcu_read_unlock();
 		return;
 	}
 
 	/* If a forced rate is in effect, select it. */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
-		sta->txrate = sdata->bss->force_unicast_rateidx;
+		sta->txrate_idx = sdata->bss->force_unicast_rateidx;
 
-	rateidx = sta->txrate;
+	rateidx = sta->txrate_idx;
 
-	if (rateidx >= mode->num_rates)
-		rateidx = mode->num_rates - 1;
+	if (rateidx >= sband->n_bitrates)
+		rateidx = sband->n_bitrates - 1;
 
-	sta->last_txrate = rateidx;
+	sta->last_txrate_idx = rateidx;
 
-	sta_info_put(sta);
+	rcu_read_unlock();
 
-	sel->rate = &mode->rates[rateidx];
+	sel->rate = &sband->bitrates[rateidx];
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	rate_control_pid_event_tx_rate(
 		&((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events,
-		rateidx, mode->rates[rateidx].rate);
+		rateidx, sband->bitrates[rateidx].bitrate);
 #endif
 }
 
@@ -353,28 +366,33 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta,
 	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
 	 * Until that method is implemented, we will use the lowest supported
 	 * rate as a workaround. */
-	sta->txrate = rate_lowest_index(local, local->oper_hw_mode, sta);
+	struct ieee80211_supported_band *sband;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+	sta->txrate_idx = rate_lowest_index(local, sband, sta);
+	sta->fail_avg = 0;
 }
 
 static void *rate_control_pid_alloc(struct ieee80211_local *local)
 {
 	struct rc_pid_info *pinfo;
 	struct rc_pid_rateinfo *rinfo;
-	struct ieee80211_hw_mode *mode;
+	struct ieee80211_supported_band *sband;
 	int i, j, tmp;
 	bool s;
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct rc_pid_debugfs_entries *de;
 #endif
 
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
 	pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC);
 	if (!pinfo)
 		return NULL;
 
-	/* We can safely assume that oper_hw_mode won't change unless we get
+	/* We can safely assume that sband won't change unless we get
 	 * reinitialized. */
-	mode = local->oper_hw_mode;
-	rinfo = kmalloc(sizeof(*rinfo) * mode->num_rates, GFP_ATOMIC);
+	rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC);
 	if (!rinfo) {
 		kfree(pinfo);
 		return NULL;
@@ -383,7 +401,7 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
 	/* Sort the rates. This is optimized for the most common case (i.e.
 	 * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed
 	 * mapping too. */
-	for (i = 0; i < mode->num_rates; i++) {
+	for (i = 0; i < sband->n_bitrates; i++) {
 		rinfo[i].index = i;
 		rinfo[i].rev_index = i;
 		if (pinfo->fast_start)
@@ -391,11 +409,11 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local)
 		else
 			rinfo[i].diff = i * pinfo->norm_offset;
 	}
-	for (i = 1; i < mode->num_rates; i++) {
+	for (i = 1; i < sband->n_bitrates; i++) {
 		s = 0;
-		for (j = 0; j < mode->num_rates - i; j++)
-			if (unlikely(mode->rates[rinfo[j].index].rate >
-				     mode->rates[rinfo[j + 1].index].rate)) {
+		for (j = 0; j < sband->n_bitrates - i; j++)
+			if (unlikely(sband->bitrates[rinfo[j].index].bitrate >
+				     sband->bitrates[rinfo[j + 1].index].bitrate)) {
 				tmp = rinfo[j].index;
 				rinfo[j].index = rinfo[j + 1].index;
 				rinfo[j + 1].index = tmp;
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
deleted file mode 100644
index 9a78b116acff..000000000000
--- a/net/mac80211/rc80211_simple.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005, Devicescape Software, Inc.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/compiler.h>
-#include <linux/module.h>
-
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-#include "ieee80211_rate.h"
-#include "debugfs.h"
-
-
-/* This is a minimal implementation of TX rate controlling that can be used
- * as the default when no improved mechanisms are available. */
-
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP   15
-
-#define RATE_CONTROL_EMERG_DEC 2
-#define RATE_CONTROL_INTERVAL (HZ / 20)
-#define RATE_CONTROL_MIN_TX 10
-
-static void rate_control_rate_inc(struct ieee80211_local *local,
-				  struct sta_info *sta)
-{
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
-	int i = sta->txrate;
-	int maxrate;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
-		/* forced unicast rate - do not change STA rate */
-		return;
-	}
-
-	mode = local->oper_hw_mode;
-	maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
-
-	if (i > mode->num_rates)
-		i = mode->num_rates - 2;
-
-	while (i + 1 < mode->num_rates) {
-		i++;
-		if (sta->supp_rates & BIT(i) &&
-		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
-		    (maxrate < 0 || i <= maxrate)) {
-			sta->txrate = i;
-			break;
-		}
-	}
-}
-
-
-static void rate_control_rate_dec(struct ieee80211_local *local,
-				  struct sta_info *sta)
-{
-	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_hw_mode *mode;
-	int i = sta->txrate;
-
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
-		/* forced unicast rate - do not change STA rate */
-		return;
-	}
-
-	mode = local->oper_hw_mode;
-	if (i > mode->num_rates)
-		i = mode->num_rates;
-
-	while (i > 0) {
-		i--;
-		if (sta->supp_rates & BIT(i) &&
-		    mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
-			sta->txrate = i;
-			break;
-		}
-	}
-}
-
-struct global_rate_control {
-	int dummy;
-};
-
-struct sta_rate_control {
-	unsigned long last_rate_change;
-	u32 tx_num_failures;
-	u32 tx_num_xmit;
-
-	unsigned long avg_rate_update;
-	u32 tx_avg_rate_sum;
-	u32 tx_avg_rate_num;
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-	struct dentry *tx_avg_rate_sum_dentry;
-	struct dentry *tx_avg_rate_num_dentry;
-#endif
-};
-
-
-static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
-					  struct sk_buff *skb,
-					  struct ieee80211_tx_status *status)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct sta_info *sta;
-	struct sta_rate_control *srctrl;
-
-	sta = sta_info_get(local, hdr->addr1);
-
-	if (!sta)
-	    return;
-
-	srctrl = sta->rate_ctrl_priv;
-	srctrl->tx_num_xmit++;
-	if (status->excessive_retries) {
-		srctrl->tx_num_failures++;
-		sta->tx_retry_failed++;
-		sta->tx_num_consecutive_failures++;
-		sta->tx_num_mpdu_fail++;
-	} else {
-		sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
-		sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
-		sta->last_ack_rssi[2] = status->ack_signal;
-		sta->tx_num_consecutive_failures = 0;
-		sta->tx_num_mpdu_ok++;
-	}
-	sta->tx_retry_count += status->retry_count;
-	sta->tx_num_mpdu_fail += status->retry_count;
-
-	if (time_after(jiffies,
-		       srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
-		srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
-		u32 per_failed;
-		srctrl->last_rate_change = jiffies;
-
-		per_failed = (100 * sta->tx_num_mpdu_fail) /
-			(sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
-		/* TODO: calculate average per_failed to make adjusting
-		 * parameters easier */
-#if 0
-		if (net_ratelimit()) {
-			printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
-			       sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
-			       per_failed);
-		}
-#endif
-
-		/*
-		 * XXX: Make these configurable once we have an
-		 * interface to the rate control algorithms
-		 */
-		if (per_failed > RATE_CONTROL_NUM_DOWN) {
-			rate_control_rate_dec(local, sta);
-		} else if (per_failed < RATE_CONTROL_NUM_UP) {
-			rate_control_rate_inc(local, sta);
-		}
-		srctrl->tx_avg_rate_sum += status->control.rate->rate;
-		srctrl->tx_avg_rate_num++;
-		srctrl->tx_num_failures = 0;
-		srctrl->tx_num_xmit = 0;
-	} else if (sta->tx_num_consecutive_failures >=
-		   RATE_CONTROL_EMERG_DEC) {
-		rate_control_rate_dec(local, sta);
-	}
-
-	if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
-		srctrl->avg_rate_update = jiffies;
-		if (srctrl->tx_avg_rate_num > 0) {
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-			DECLARE_MAC_BUF(mac);
-			printk(KERN_DEBUG "%s: STA %s Average rate: "
-			       "%d (%d/%d)\n",
-			       dev->name, print_mac(mac, sta->addr),
-			       srctrl->tx_avg_rate_sum /
-			       srctrl->tx_avg_rate_num,
-			       srctrl->tx_avg_rate_sum,
-			       srctrl->tx_avg_rate_num);
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
-			srctrl->tx_avg_rate_sum = 0;
-			srctrl->tx_avg_rate_num = 0;
-		}
-	}
-
-	sta_info_put(sta);
-}
-
-
-static void
-rate_control_simple_get_rate(void *priv, struct net_device *dev,
-			     struct ieee80211_hw_mode *mode,
-			     struct sk_buff *skb,
-			     struct rate_selection *sel)
-{
-	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	struct ieee80211_sub_if_data *sdata;
-	struct sta_info *sta;
-	int rateidx;
-	u16 fc;
-
-	sta = sta_info_get(local, hdr->addr1);
-
-	/* Send management frames and broadcast/multicast data using lowest
-	 * rate. */
-	fc = le16_to_cpu(hdr->frame_control);
-	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-	    is_multicast_ether_addr(hdr->addr1) || !sta) {
-		sel->rate = rate_lowest(local, mode, sta);
-		if (sta)
-			sta_info_put(sta);
-		return;
-	}
-
-	/* If a forced rate is in effect, select it. */
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
-		sta->txrate = sdata->bss->force_unicast_rateidx;
-
-	rateidx = sta->txrate;
-
-	if (rateidx >= mode->num_rates)
-		rateidx = mode->num_rates - 1;
-
-	sta->last_txrate = rateidx;
-
-	sta_info_put(sta);
-
-	sel->rate = &mode->rates[rateidx];
-}
-
-
-static void rate_control_simple_rate_init(void *priv, void *priv_sta,
-					  struct ieee80211_local *local,
-					  struct sta_info *sta)
-{
-	struct ieee80211_hw_mode *mode;
-	int i;
-	sta->txrate = 0;
-	mode = local->oper_hw_mode;
-	/* TODO: This routine should consider using RSSI from previous packets
-	 * as we need to have IEEE 802.1X auth succeed immediately after assoc..
-	 * Until that method is implemented, we will use the lowest supported rate
-	 * as a workaround, */
-	for (i = 0; i < mode->num_rates; i++) {
-		if ((sta->supp_rates & BIT(i)) &&
-		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) {
-			sta->txrate = i;
-			break;
-		}
-	}
-}
-
-
-static void * rate_control_simple_alloc(struct ieee80211_local *local)
-{
-	struct global_rate_control *rctrl;
-
-	rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
-
-	return rctrl;
-}
-
-
-static void rate_control_simple_free(void *priv)
-{
-	struct global_rate_control *rctrl = priv;
-	kfree(rctrl);
-}
-
-
-static void rate_control_simple_clear(void *priv)
-{
-}
-
-
-static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp)
-{
-	struct sta_rate_control *rctrl;
-
-	rctrl = kzalloc(sizeof(*rctrl), gfp);
-
-	return rctrl;
-}
-
-
-static void rate_control_simple_free_sta(void *priv, void *priv_sta)
-{
-	struct sta_rate_control *rctrl = priv_sta;
-	kfree(rctrl);
-}
-
-#ifdef CONFIG_MAC80211_DEBUGFS
-
-static int open_file_generic(struct inode *inode, struct file *file)
-{
-	file->private_data = inode->i_private;
-	return 0;
-}
-
-static ssize_t sta_tx_avg_rate_sum_read(struct file *file,
-					char __user *userbuf,
-					size_t count, loff_t *ppos)
-{
-	struct sta_rate_control *srctrl = file->private_data;
-	char buf[20];
-
-	sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
-	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-static const struct file_operations sta_tx_avg_rate_sum_ops = {
-	.read = sta_tx_avg_rate_sum_read,
-	.open = open_file_generic,
-};
-
-static ssize_t sta_tx_avg_rate_num_read(struct file *file,
-					char __user *userbuf,
-					size_t count, loff_t *ppos)
-{
-	struct sta_rate_control *srctrl = file->private_data;
-	char buf[20];
-
-	sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
-	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
-}
-
-static const struct file_operations sta_tx_avg_rate_num_ops = {
-	.read = sta_tx_avg_rate_num_read,
-	.open = open_file_generic,
-};
-
-static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta,
-						struct dentry *dir)
-{
-	struct sta_rate_control *srctrl = priv_sta;
-
-	srctrl->tx_avg_rate_num_dentry =
-		debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400,
-				    dir, srctrl, &sta_tx_avg_rate_num_ops);
-	srctrl->tx_avg_rate_sum_dentry =
-		debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400,
-				    dir, srctrl, &sta_tx_avg_rate_sum_ops);
-}
-
-static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
-{
-	struct sta_rate_control *srctrl = priv_sta;
-
-	debugfs_remove(srctrl->tx_avg_rate_sum_dentry);
-	debugfs_remove(srctrl->tx_avg_rate_num_dentry);
-}
-#endif
-
-static struct rate_control_ops mac80211_rcsimple = {
-	.name = "simple",
-	.tx_status = rate_control_simple_tx_status,
-	.get_rate = rate_control_simple_get_rate,
-	.rate_init = rate_control_simple_rate_init,
-	.clear = rate_control_simple_clear,
-	.alloc = rate_control_simple_alloc,
-	.free = rate_control_simple_free,
-	.alloc_sta = rate_control_simple_alloc_sta,
-	.free_sta = rate_control_simple_free_sta,
-#ifdef CONFIG_MAC80211_DEBUGFS
-	.add_sta_debugfs = rate_control_simple_add_sta_debugfs,
-	.remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
-#endif
-};
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Simple rate control algorithm");
-
-int __init rc80211_simple_init(void)
-{
-	return ieee80211_rate_control_register(&mac80211_rcsimple);
-}
-
-void rc80211_simple_exit(void)
-{
-	ieee80211_rate_control_unregister(&mac80211_rcsimple);
-}
-
-#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE
-module_init(rc80211_simple_init);
-module_exit(rc80211_simple_exit);
-#endif
diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c
deleted file mode 100644
index f42678fa62d1..000000000000
--- a/net/mac80211/regdomain.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2002-2005, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- *
- * 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
- * published by the Free Software Foundation.
- */
-
-/*
- * This regulatory domain control implementation is known to be incomplete
- * and confusing. mac80211 regulatory domain control will be significantly
- * reworked in the not-too-distant future.
- *
- * For now, drivers wishing to control which channels are and aren't available
- * are advised as follows:
- *  - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
- *  - continue to include *ALL* possible channels in the modes registered
- *    through ieee80211_register_hwmode()
- *  - for each allowable ieee80211_channel structure registered in the above
- *    call, set the flag member to some meaningful value such as
- *    IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
- *    IEEE80211_CHAN_W_IBSS.
- *  - leave flag as 0 for non-allowable channels
- *
- * The usual implementation is for a driver to read a device EEPROM to
- * determine which regulatory domain it should be operating under, then
- * looking up the allowable channels in a driver-local table, then performing
- * the above.
- */
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <net/mac80211.h>
-#include "ieee80211_i.h"
-
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
-
-struct ieee80211_channel_range {
-	short start_freq;
-	short end_freq;
-	unsigned char power_level;
-	unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
-	{ 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
-	{ 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
-	{ 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
-	{ 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
-	{ 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
-	{ 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
-	{ 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
-	{ 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
-	{ 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
-	ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
-{
-	int i;
-
-	chan->flag = 0;
-
-	for (i = 0; channel_range[i].start_freq; i++) {
-		const struct ieee80211_channel_range *r = &channel_range[i];
-		if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
-			if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
-			    chan->freq >= 5260 && chan->freq <= 5320) {
-				/*
-				 * Skip new channels in Japan since the
-				 * firmware was not marked having been upgraded
-				 * by the vendor.
-				 */
-				continue;
-			}
-
-			if (ieee80211_regdom == 0x10 &&
-			    (chan->freq == 5190 || chan->freq == 5210 ||
-			     chan->freq == 5230)) {
-				    /* Skip MKK channels when in FCC domain. */
-				    continue;
-			}
-
-			chan->flag |= IEEE80211_CHAN_W_SCAN |
-				IEEE80211_CHAN_W_ACTIVE_SCAN |
-				IEEE80211_CHAN_W_IBSS;
-			chan->power_level = r->power_level;
-			chan->antenna_max = r->antenna_max;
-
-			if (ieee80211_regdom == 64 &&
-			    (chan->freq == 5170 || chan->freq == 5190 ||
-			     chan->freq == 5210 || chan->freq == 5230)) {
-				/*
-				 * New regulatory rules in Japan have backwards
-				 * compatibility with old channels in 5.15-5.25
-				 * GHz band, but the station is not allowed to
-				 * use active scan on these old channels.
-				 */
-				chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
-			}
-
-			if (ieee80211_regdom == 64 &&
-			    (chan->freq == 5260 || chan->freq == 5280 ||
-			     chan->freq == 5300 || chan->freq == 5320)) {
-				/*
-				 * IBSS is not allowed on 5.25-5.35 GHz band
-				 * due to radar detection requirements.
-				 */
-				chan->flag &= ~IEEE80211_CHAN_W_IBSS;
-			}
-
-			break;
-		}
-	}
-}
-
-
-void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
-{
-	int c;
-	for (c = 0; c < mode->num_channels; c++)
-		ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
-}
-
-
-void ieee80211_regdomain_init(void)
-{
-	if (ieee80211_regdom == 0x40)
-		channel_range = ieee80211_mkk_channels;
-}
-
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 535407d07fa4..0ac6db5c09ea 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
@@ -19,6 +20,7 @@
 
 #include "ieee80211_i.h"
 #include "ieee80211_led.h"
+#include "mesh.h"
 #include "wep.h"
 #include "wpa.h"
 #include "tkip.h"
@@ -82,10 +84,10 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status,
  */
 static struct sk_buff *
 ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
-		     struct ieee80211_rx_status *status)
+		     struct ieee80211_rx_status *status,
+		     struct ieee80211_rate *rate)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_rate *rate;
 	int needed_headroom = 0;
 	struct ieee80211_radiotap_header *rthdr;
 	__le64 *rttsft = NULL;
@@ -194,14 +196,11 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 			rtfixed->rx_flags |=
 				cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS);
 
-		rate = ieee80211_get_rate(local, status->phymode,
-					  status->rate);
-		if (rate)
-			rtfixed->rate = rate->rate / 5;
+		rtfixed->rate = rate->bitrate / 5;
 
 		rtfixed->chan_freq = cpu_to_le16(status->freq);
 
-		if (status->phymode == MODE_IEEE80211A)
+		if (status->band == IEEE80211_BAND_5GHZ)
 			rtfixed->chan_flags =
 				cpu_to_le16(IEEE80211_CHAN_OFDM |
 					    IEEE80211_CHAN_5GHZ);
@@ -226,6 +225,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR)
 			continue;
 
+		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)
+			continue;
+
 		if (prev_dev) {
 			skb2 = skb_clone(skb, GFP_ATOMIC);
 			if (skb2) {
@@ -249,15 +251,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
 }
 
 
-/* pre-rx handlers
- *
- * these don't have dev/sdata fields in the rx data
- * The sta value should also not be used because it may
- * be NULL even though a STA (in IBSS mode) will be added.
- */
-
-static ieee80211_txrx_result
-ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 {
 	u8 *data = rx->skb->data;
 	int tid;
@@ -268,9 +262,9 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
 		/* frame has qos control */
 		tid = qc[0] & QOS_CONTROL_TID_MASK;
 		if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
-			rx->flags |= IEEE80211_TXRXD_RX_AMSDU;
+			rx->flags |= IEEE80211_RX_AMSDU;
 		else
-			rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU;
+			rx->flags &= ~IEEE80211_RX_AMSDU;
 	} else {
 		if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
 			/* Separate TID for management frames */
@@ -286,68 +280,19 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
 	if (rx->sta)
 		I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
 
-	rx->u.rx.queue = tid;
+	rx->queue = tid;
 	/* Set skb->priority to 1d tag if highest order bit of TID is not set.
 	 * For now, set skb->priority to 0 for other cases. */
 	rx->skb->priority = (tid > 7) ? 0 : tid;
-
-	return TXRX_CONTINUE;
 }
 
-
-static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
-			      struct sk_buff *skb,
-			      struct ieee80211_rx_status *status)
+static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx)
 {
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	u32 load = 0, hdrtime;
-	struct ieee80211_rate *rate;
-	struct ieee80211_hw_mode *mode = local->hw.conf.mode;
-	int i;
-
-	/* Estimate total channel use caused by this frame */
-
-	if (unlikely(mode->num_rates < 0))
-		return TXRX_CONTINUE;
-
-	rate = &mode->rates[0];
-	for (i = 0; i < mode->num_rates; i++) {
-		if (mode->rates[i].val == status->rate) {
-			rate = &mode->rates[i];
-			break;
-		}
-	}
-
-	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
-	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
-
-	if (mode->mode == MODE_IEEE80211A ||
-	    (mode->mode == MODE_IEEE80211G &&
-	     rate->flags & IEEE80211_RATE_ERP))
-		hdrtime = CHAN_UTIL_HDR_SHORT;
-	else
-		hdrtime = CHAN_UTIL_HDR_LONG;
-
-	load = hdrtime;
-	if (!is_multicast_ether_addr(hdr->addr1))
-		load += hdrtime;
-
-	load += skb->len * rate->rate_inv;
-
-	/* Divide channel_use by 8 to avoid wrapping around the counter */
-	load >>= CHAN_UTIL_SHIFT;
-
-	return load;
-}
-
 #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
-static ieee80211_txrx_result
-ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
-{
 	int hdrlen;
 
 	if (!WLAN_FC_DATA_PRESENT(rx->fc))
-		return TXRX_CONTINUE;
+		return;
 
 	/*
 	 * Drivers are required to align the payload data in a way that
@@ -369,83 +314,158 @@ ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx)
 	 * to move the 802.11 header further back in that case.
 	 */
 	hdrlen = ieee80211_get_hdrlen(rx->fc);
-	if (rx->flags & IEEE80211_TXRXD_RX_AMSDU)
+	if (rx->flags & IEEE80211_RX_AMSDU)
 		hdrlen += ETH_HLEN;
 	WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3);
-
-	return TXRX_CONTINUE;
-}
 #endif
+}
 
-ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
+
+static u32 ieee80211_rx_load_stats(struct ieee80211_local *local,
+				   struct sk_buff *skb,
+				   struct ieee80211_rx_status *status,
+				   struct ieee80211_rate *rate)
 {
-	ieee80211_rx_h_parse_qos,
-#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT
-	ieee80211_rx_h_verify_ip_alignment,
-#endif
-	NULL
-};
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u32 load = 0, hdrtime;
+
+	/* Estimate total channel use caused by this frame */
+
+	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+	if (status->band == IEEE80211_BAND_5GHZ ||
+	    (status->band == IEEE80211_BAND_5GHZ &&
+	     rate->flags & IEEE80211_RATE_ERP_G))
+		hdrtime = CHAN_UTIL_HDR_SHORT;
+	else
+		hdrtime = CHAN_UTIL_HDR_LONG;
+
+	load = hdrtime;
+	if (!is_multicast_ether_addr(hdr->addr1))
+		load += hdrtime;
+
+	/* TODO: optimise again */
+	load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
+
+	/* Divide channel_use by 8 to avoid wrapping around the counter */
+	load >>= CHAN_UTIL_SHIFT;
+
+	return load;
+}
 
 /* rx handlers */
 
-static ieee80211_txrx_result
-ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx)
 {
 	if (rx->sta)
-		rx->sta->channel_use_raw += rx->u.rx.load;
-	rx->sdata->channel_use_raw += rx->u.rx.load;
-	return TXRX_CONTINUE;
+		rx->sta->channel_use_raw += rx->load;
+	rx->sdata->channel_use_raw += rx->load;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_local *local = rx->local;
 	struct sk_buff *skb = rx->skb;
 
 	if (unlikely(local->sta_hw_scanning))
-		return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+		return ieee80211_sta_rx_scan(rx->dev, skb, rx->status);
 
 	if (unlikely(local->sta_sw_scanning)) {
 		/* drop all the other packets during a software scan anyway */
-		if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
-		    != TXRX_QUEUED)
+		if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status)
+		    != RX_QUEUED)
 			dev_kfree_skb(skb);
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
-	if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) {
+	if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) {
 		/* scanning finished during invoking of handlers */
 		I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
+}
+
+static ieee80211_rx_result
+ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+{
+	int hdrlen = ieee80211_get_hdrlen(rx->fc);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l))
+
+	if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
+		if (!((rx->fc & IEEE80211_FCTL_FROMDS) &&
+		      (rx->fc & IEEE80211_FCTL_TODS)))
+			return RX_DROP_MONITOR;
+		if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
+			return RX_DROP_MONITOR;
+	}
+
+	/* If there is not an established peer link and this is not a peer link
+	 * establisment frame, beacon or probe, drop the frame.
+	 */
+
+	if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
+		struct ieee80211_mgmt *mgmt;
+
+		if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT)
+			return RX_DROP_MONITOR;
+
+		switch (rx->fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_ACTION:
+			mgmt = (struct ieee80211_mgmt *)hdr;
+			if (mgmt->u.action.category != PLINK_CATEGORY)
+				return RX_DROP_MONITOR;
+			/* fall through on else */
+		case IEEE80211_STYPE_PROBE_REQ:
+		case IEEE80211_STYPE_PROBE_RESP:
+		case IEEE80211_STYPE_BEACON:
+			return RX_CONTINUE;
+			break;
+		default:
+			return RX_DROP_MONITOR;
+		}
+
+	 } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+		    is_multicast_ether_addr(hdr->addr1) &&
+		    mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev))
+		return RX_DROP_MONITOR;
+#undef msh_h_get
+
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+
+static ieee80211_rx_result
+ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
+
 	hdr = (struct ieee80211_hdr *) rx->skb->data;
 
 	/* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
 	if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
 		if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
-			     rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+			     rx->sta->last_seq_ctrl[rx->queue] ==
 			     hdr->seq_ctrl)) {
-			if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) {
+			if (rx->flags & IEEE80211_RX_RA_MATCH) {
 				rx->local->dot11FrameDuplicateCount++;
 				rx->sta->num_duplicates++;
 			}
-			return TXRX_DROP;
+			return RX_DROP_MONITOR;
 		} else
-			rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+			rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl;
 	}
 
 	if (unlikely(rx->skb->len < 16)) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
 	/* Drop disallowed frame classes based on STA auth/assoc state;
@@ -456,6 +476,10 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 	 * deauth/disassoc frames when needed. In addition, hostapd is
 	 * responsible for filtering on both auth and assoc states.
 	 */
+
+	if (ieee80211_vif_is_mesh(&rx->sdata->vif))
+		return ieee80211_rx_mesh_check(rx);
+
 	if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
 		      ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
 		       (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
@@ -464,26 +488,26 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
 		if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
 		     !(rx->fc & IEEE80211_FCTL_TODS) &&
 		     (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-		    || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+		    || !(rx->flags & IEEE80211_RX_RA_MATCH)) {
 			/* Drop IBSS frames and frames for other hosts
 			 * silently. */
-			return TXRX_DROP;
+			return RX_DROP_MONITOR;
 		}
 
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
-static ieee80211_txrx_result
-ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 	int keyidx;
 	int hdrlen;
-	ieee80211_txrx_result result = TXRX_DROP;
+	ieee80211_rx_result result = RX_DROP_UNUSABLE;
 	struct ieee80211_key *stakey = NULL;
 
 	/*
@@ -513,14 +537,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 	 */
 
 	if (!(rx->fc & IEEE80211_FCTL_PROTECTED))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/*
 	 * No point in finding a key and decrypting if the frame is neither
 	 * addressed to us nor a multicast frame.
 	 */
-	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_CONTINUE;
+	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+		return RX_CONTINUE;
 
 	if (rx->sta)
 		stakey = rcu_dereference(rx->sta->key);
@@ -537,14 +561,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 		 * we somehow allow the driver to tell us which key
 		 * the hardware used if this flag is set?
 		 */
-		if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-		    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-			return TXRX_CONTINUE;
+		if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+		    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+			return RX_CONTINUE;
 
 		hdrlen = ieee80211_get_hdrlen(rx->fc);
 
 		if (rx->skb->len < 8 + hdrlen)
-			return TXRX_DROP; /* TODO: count this? */
+			return RX_DROP_UNUSABLE; /* TODO: count this? */
 
 		/*
 		 * no need to call ieee80211_wep_get_keyidx,
@@ -573,14 +597,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 			printk(KERN_DEBUG "%s: RX protected frame,"
 			       " but have no key\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
 	/* Check for weak IVs if possible */
 	if (rx->sta && rx->key->conf.alg == ALG_WEP &&
 	    ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-	    (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) ||
-	     !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) &&
+	    (!(rx->status->flag & RX_FLAG_IV_STRIPPED) ||
+	     !(rx->status->flag & RX_FLAG_DECRYPTED)) &&
 	    ieee80211_wep_is_weak_iv(rx->skb, rx->key))
 		rx->sta->wep_weak_iv_count++;
 
@@ -597,7 +621,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx)
 	}
 
 	/* either the frame has been decrypted or will be dropped */
-	rx->u.rx.status->flag |= RX_FLAG_DECRYPTED;
+	rx->status->flag |= RX_FLAG_DECRYPTED;
 
 	return result;
 }
@@ -607,12 +631,12 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
 	struct ieee80211_sub_if_data *sdata;
 	DECLARE_MAC_BUF(mac);
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	sdata = sta->sdata;
 
 	if (sdata->bss)
 		atomic_inc(&sdata->bss->num_sta_ps);
 	sta->flags |= WLAN_STA_PS;
-	sta->pspoll = 0;
+	sta->flags &= ~WLAN_STA_PSPOLL;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n",
 	       dev->name, print_mac(mac, sta->addr), sta->aid);
@@ -628,21 +652,21 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 	struct ieee80211_tx_packet_data *pkt_data;
 	DECLARE_MAC_BUF(mac);
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	sdata = sta->sdata;
+
 	if (sdata->bss)
 		atomic_dec(&sdata->bss->num_sta_ps);
-	sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
-	sta->pspoll = 0;
-	if (!skb_queue_empty(&sta->ps_tx_buf)) {
-		if (local->ops->set_tim)
-			local->ops->set_tim(local_to_hw(local), sta->aid, 0);
-		if (sdata->bss)
-			bss_tim_clear(local, sdata->bss, sta->aid);
-	}
+
+	sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL);
+
+	if (!skb_queue_empty(&sta->ps_tx_buf))
+		sta_info_clear_tim_bit(sta);
+
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n",
 	       dev->name, print_mac(mac, sta->addr), sta->aid);
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
 	/* Send all buffered frames to the station */
 	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
 		pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
@@ -666,15 +690,15 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
 	return sent;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
 	struct sta_info *sta = rx->sta;
 	struct net_device *dev = rx->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 
 	if (!sta)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/* Update last_rx only for IBSS packets which are for the current
 	 * BSSID to avoid keeping the current IBSS network alive in cases where
@@ -690,24 +714,26 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 		/* Update last_rx only for unicast frames in order to prevent
 		 * the Probe Request frames (the only broadcast frames from a
 		 * STA in infrastructure mode) from keeping a connection alive.
+		 * Mesh beacons will update last_rx when if they are found to
+		 * match the current local configuration when processed.
 		 */
 		sta->last_rx = jiffies;
 	}
 
-	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_CONTINUE;
+	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+		return RX_CONTINUE;
 
 	sta->rx_fragments++;
 	sta->rx_bytes += rx->skb->len;
-	sta->last_rssi = rx->u.rx.status->ssi;
-	sta->last_signal = rx->u.rx.status->signal;
-	sta->last_noise = rx->u.rx.status->noise;
+	sta->last_rssi = rx->status->ssi;
+	sta->last_signal = rx->status->signal;
+	sta->last_noise = rx->status->noise;
 
 	if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
 		/* Change STA power saving mode only in the end of a frame
 		 * exchange sequence */
 		if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
-			rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+			rx->sent_ps_buffered += ap_sta_ps_end(dev, sta);
 		else if (!(sta->flags & WLAN_STA_PS) &&
 			 (rx->fc & IEEE80211_FCTL_PM))
 			ap_sta_ps_start(dev, sta);
@@ -722,10 +748,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
 		 * as a dropped packed. */
 		sta->rx_packets++;
 		dev_kfree_skb(rx->skb);
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 } /* ieee80211_rx_h_sta_process */
 
 static inline struct ieee80211_fragment_entry *
@@ -801,7 +827,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
 		    compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
 			continue;
 
-		if (entry->first_frag_time + 2 * HZ < jiffies) {
+		if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
 			__skb_queue_purge(&entry->skb_list);
 			continue;
 		}
@@ -811,8 +837,8 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
 	return NULL;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr;
 	u16 sc;
@@ -838,27 +864,27 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 	if (frag == 0) {
 		/* This is the first fragment of a new frame. */
 		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
-						 rx->u.rx.queue, &(rx->skb));
+						 rx->queue, &(rx->skb));
 		if (rx->key && rx->key->conf.alg == ALG_CCMP &&
 		    (rx->fc & IEEE80211_FCTL_PROTECTED)) {
 			/* Store CCMP PN so that we can verify that the next
 			 * fragment has a sequential PN value. */
 			entry->ccmp = 1;
 			memcpy(entry->last_pn,
-			       rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+			       rx->key->u.ccmp.rx_pn[rx->queue],
 			       CCMP_PN_LEN);
 		}
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
 	/* This is a fragment for a frame that should already be pending in
 	 * fragment cache. Add this fragment to the end of the pending entry.
 	 */
 	entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
-					  rx->u.rx.queue, hdr);
+					  rx->queue, hdr);
 	if (!entry) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 	}
 
 	/* Verify that MPDUs within one MSDU have sequential PN values.
@@ -867,14 +893,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 		int i;
 		u8 pn[CCMP_PN_LEN], *rpn;
 		if (!rx->key || rx->key->conf.alg != ALG_CCMP)
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		memcpy(pn, entry->last_pn, CCMP_PN_LEN);
 		for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
 			pn[i]++;
 			if (pn[i])
 				break;
 		}
-		rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+		rpn = rx->key->u.ccmp.rx_pn[rx->queue];
 		if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: defrag: CCMP PN not "
@@ -885,7 +911,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 				       rpn[0], rpn[1], rpn[2], rpn[3], rpn[4],
 				       rpn[5], pn[0], pn[1], pn[2], pn[3],
 				       pn[4], pn[5]);
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
 	}
@@ -896,7 +922,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 	entry->extra_len += rx->skb->len;
 	if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
 		rx->skb = NULL;
-		return TXRX_QUEUED;
+		return RX_QUEUED;
 	}
 
 	rx->skb = __skb_dequeue(&entry->skb_list);
@@ -906,7 +932,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 					      GFP_ATOMIC))) {
 			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
 			__skb_queue_purge(&entry->skb_list);
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 	}
 	while ((skb = __skb_dequeue(&entry->skb_list))) {
@@ -915,7 +941,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 	}
 
 	/* Complete frame has been reassembled - process it now */
-	rx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+	rx->flags |= IEEE80211_RX_FRAGMENTED;
 
  out:
 	if (rx->sta)
@@ -924,11 +950,11 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
 		rx->local->dot11MulticastReceivedFrameCount++;
 	else
 		ieee80211_led_rx(rx->local);
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	struct sk_buff *skb;
@@ -938,12 +964,12 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 	if (likely(!rx->sta ||
 		   (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
 		   (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
-		   !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)))
-		return TXRX_CONTINUE;
+		   !(rx->flags & IEEE80211_RX_RA_MATCH)))
+		return RX_CONTINUE;
 
 	if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) &&
 	    (sdata->vif.type != IEEE80211_IF_TYPE_VLAN))
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	skb = skb_dequeue(&rx->sta->tx_filtered);
 	if (!skb) {
@@ -958,9 +984,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 		struct ieee80211_hdr *hdr =
 			(struct ieee80211_hdr *) skb->data;
 
-		/* tell TX path to send one frame even though the STA may
-		 * still remain is PS mode after this frame exchange */
-		rx->sta->pspoll = 1;
+		/*
+		 * Tell TX path to send one frame even though the STA may
+		 * still remain is PS mode after this frame exchange.
+		 */
+		rx->sta->flags |= WLAN_STA_PSPOLL;
 
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n",
@@ -970,46 +998,45 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 
 		/* Use MoreData flag to indicate whether there are more
 		 * buffered frames for this STA */
-		if (no_pending_pkts) {
+		if (no_pending_pkts)
 			hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-			rx->sta->flags &= ~WLAN_STA_TIM;
-		} else
+		else
 			hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
 
 		dev_queue_xmit(skb);
 
-		if (no_pending_pkts) {
-			if (rx->local->ops->set_tim)
-				rx->local->ops->set_tim(local_to_hw(rx->local),
-						       rx->sta->aid, 0);
-			if (rx->sdata->bss)
-				bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
-		}
+		if (no_pending_pkts)
+			sta_info_clear_tim_bit(rx->sta);
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
-	} else if (!rx->u.rx.sent_ps_buffered) {
+	} else if (!rx->sent_ps_buffered) {
+		/*
+		 * FIXME: This can be the result of a race condition between
+		 *	  us expiring a frame and the station polling for it.
+		 *	  Should we send it a null-func frame indicating we
+		 *	  have nothing buffered for it?
+		 */
 		printk(KERN_DEBUG "%s: STA %s sent PS Poll even "
 		       "though there is no buffered frames for it\n",
 		       rx->dev->name, print_mac(mac, rx->sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-
 	}
 
-	/* Free PS Poll skb here instead of returning TXRX_DROP that would
+	/* Free PS Poll skb here instead of returning RX_DROP that would
 	 * count as an dropped frame. */
 	dev_kfree_skb(rx->skb);
 
-	return TXRX_QUEUED;
+	return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx)
 {
 	u16 fc = rx->fc;
 	u8 *data = rx->skb->data;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
 
 	if (!WLAN_FC_IS_QOS_DATA(fc))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	/* remove the qos control field, update frame type and meta-data */
 	memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
@@ -1018,17 +1045,17 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
 	rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
 	hdr->frame_control = cpu_to_le16(fc);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 static int
-ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
+ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
-	if (unlikely(rx->sdata->ieee802_1x_pac &&
-		     (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) {
+	if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) {
 #ifdef CONFIG_MAC80211_DEBUG
-		printk(KERN_DEBUG "%s: dropped frame "
-		       "(unauthorized port)\n", rx->dev->name);
+		if (net_ratelimit())
+			printk(KERN_DEBUG "%s: dropped frame "
+			       "(unauthorized port)\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
 		return -EACCES;
 	}
@@ -1037,13 +1064,13 @@ ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx)
 }
 
 static int
-ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
+ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx)
 {
 	/*
 	 * Pass through unencrypted frames if the hardware has
 	 * decrypted them already.
 	 */
-	if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED)
+	if (rx->status->flag & RX_FLAG_DECRYPTED)
 		return 0;
 
 	/* Drop unencrypted frames if key is set. */
@@ -1060,7 +1087,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx)
 }
 
 static int
-ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
+ieee80211_data_to_8023(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
@@ -1082,6 +1109,21 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
 
 	hdrlen = ieee80211_get_hdrlen(fc);
 
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		int meshhdrlen = ieee80211_get_mesh_hdrlen(
+				(struct ieee80211s_hdr *) (skb->data + hdrlen));
+		/* Copy on cb:
+		 *  - mesh header: to be used for mesh forwarding
+		 * decision. It will also be used as mesh header template at
+		 * tx.c:ieee80211_subif_start_xmit() if interface
+		 * type is mesh and skb->pkt_type == PACKET_OTHERHOST
+		 *  - ta: to be used if a RERR needs to be sent.
+		 */
+		memcpy(skb->cb, skb->data + hdrlen, meshhdrlen);
+		memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN);
+		hdrlen += meshhdrlen;
+	}
+
 	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
 	 * header
 	 * IEEE 802.11 address fields:
@@ -1115,9 +1157,10 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
 		memcpy(dst, hdr->addr3, ETH_ALEN);
 		memcpy(src, hdr->addr4, ETH_ALEN);
 
-		if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) {
-			if (net_ratelimit())
-				printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
+		 if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS &&
+			     sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) {
+			 if (net_ratelimit())
+				 printk(KERN_DEBUG "%s: dropped FromDS&ToDS "
 				       "frame (RA=%s TA=%s DA=%s SA=%s)\n",
 				       rx->dev->name,
 				       print_mac(mac, hdr->addr1),
@@ -1192,7 +1235,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx)
 /*
  * requires that rx->skb is a frame with ethernet header
  */
-static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
+static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx)
 {
 	static const u8 pae_group_addr[ETH_ALEN]
 		= { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 };
@@ -1218,7 +1261,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx)
  * requires that rx->skb is a frame with ethernet header
  */
 static void
-ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
+ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
 	struct ieee80211_local *local = rx->local;
@@ -1232,7 +1275,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
 
 	if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP ||
 				      sdata->vif.type == IEEE80211_IF_TYPE_VLAN) &&
-	    (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+	    (rx->flags & IEEE80211_RX_RA_MATCH)) {
 		if (is_multicast_ether_addr(ehdr->h_dest)) {
 			/*
 			 * send multicast frames both to higher layers in
@@ -1244,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
 				       "multicast frame\n", dev->name);
 		} else {
 			dsta = sta_info_get(local, skb->data);
-			if (dsta && dsta->dev == dev) {
+			if (dsta && dsta->sdata->dev == dev) {
 				/*
 				 * The destination station is associated to
 				 * this AP (in this VLAN), so send the frame
@@ -1254,8 +1297,38 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
 				xmit_skb = skb;
 				skb = NULL;
 			}
-			if (dsta)
-				sta_info_put(dsta);
+		}
+	}
+
+	/* Mesh forwarding */
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl;
+		(*mesh_ttl)--;
+
+		if (is_multicast_ether_addr(skb->data)) {
+			if (*mesh_ttl > 0) {
+				xmit_skb = skb_copy(skb, GFP_ATOMIC);
+				if (!xmit_skb && net_ratelimit())
+					printk(KERN_DEBUG "%s: failed to clone "
+					       "multicast frame\n", dev->name);
+				else
+					xmit_skb->pkt_type = PACKET_OTHERHOST;
+			} else
+				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+							     dropped_frames_ttl);
+		} else if (skb->pkt_type != PACKET_OTHERHOST &&
+			compare_ether_addr(dev->dev_addr, skb->data) != 0) {
+			if (*mesh_ttl == 0) {
+				IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta,
+							     dropped_frames_ttl);
+				dev_kfree_skb(skb);
+				skb = NULL;
+			} else {
+				xmit_skb = skb;
+				xmit_skb->pkt_type = PACKET_OTHERHOST;
+				if (!(dev->flags & IFF_PROMISC))
+					skb  = NULL;
+			}
 		}
 	}
 
@@ -1275,8 +1348,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx)
 	}
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
 	struct ieee80211_local *local = rx->local;
@@ -1291,17 +1364,17 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 
 	fc = rx->fc;
 	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 
-	if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU))
-		return TXRX_CONTINUE;
+	if (!(rx->flags & IEEE80211_RX_AMSDU))
+		return RX_CONTINUE;
 
 	err = ieee80211_data_to_8023(rx);
 	if (unlikely(err))
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	skb->dev = dev;
 
@@ -1311,7 +1384,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 	/* skip the wrapping header */
 	eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
 	if (!eth)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	while (skb != frame) {
 		u8 padding;
@@ -1326,7 +1399,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 		/* the last MSDU has no padding */
 		if (subframe_len > remaining) {
 			printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 
 		skb_pull(skb, sizeof(struct ethhdr));
@@ -1338,7 +1411,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 					      subframe_len);
 
 			if (frame == NULL)
-				return TXRX_DROP;
+				return RX_DROP_UNUSABLE;
 
 			skb_reserve(frame, local->hw.extra_tx_headroom +
 				    sizeof(struct ethhdr));
@@ -1351,7 +1424,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 				printk(KERN_DEBUG "%s: wrong buffer size ",
 				       dev->name);
 				dev_kfree_skb(frame);
-				return TXRX_DROP;
+				return RX_DROP_UNUSABLE;
 			}
 		}
 
@@ -1381,7 +1454,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 
 		if (!ieee80211_frame_allowed(rx)) {
 			if (skb == frame) /* last frame */
-				return TXRX_DROP;
+				return RX_DROP_UNUSABLE;
 			dev_kfree_skb(frame);
 			continue;
 		}
@@ -1389,11 +1462,11 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
 		ieee80211_deliver_skb(rx);
 	}
 
-	return TXRX_QUEUED;
+	return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->dev;
 	u16 fc;
@@ -1401,17 +1474,17 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 
 	fc = rx->fc;
 	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 
 	err = ieee80211_data_to_8023(rx);
 	if (unlikely(err))
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	if (!ieee80211_frame_allowed(rx))
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 
 	rx->skb->dev = dev;
 
@@ -1420,11 +1493,11 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
 
 	ieee80211_deliver_skb(rx);
 
-	return TXRX_QUEUED;
+	return RX_QUEUED;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_local *local = rx->local;
 	struct ieee80211_hw *hw = &local->hw;
@@ -1435,15 +1508,16 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
 	u16 tid;
 
 	if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) {
 		if (!rx->sta)
-			return TXRX_CONTINUE;
+			return RX_CONTINUE;
 		tid = le16_to_cpu(bar->control) >> 12;
-		tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]);
-		if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
-			return TXRX_CONTINUE;
+		if (rx->sta->ampdu_mlme.tid_state_rx[tid]
+					!= HT_AGG_STATE_OPERATIONAL)
+			return RX_CONTINUE;
+		tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
 
 		start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
 
@@ -1460,77 +1534,35 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx)
 		ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL,
 						 start_seq_num, 1);
 		rcu_read_unlock();
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+static ieee80211_rx_result
+ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_sub_if_data *sdata;
 
-	if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-		return TXRX_DROP;
+	if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+		return RX_DROP_MONITOR;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
-	     sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
+	     sdata->vif.type == IEEE80211_IF_TYPE_IBSS ||
+	     sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) &&
 	    !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME))
-		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+		ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status);
 	else
-		return TXRX_DROP;
+		return RX_DROP_MONITOR;
 
-	return TXRX_QUEUED;
-}
-
-static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
-				struct ieee80211_local *local,
-				ieee80211_rx_handler *handlers,
-				struct ieee80211_txrx_data *rx,
-				struct sta_info *sta)
-{
-	ieee80211_rx_handler *handler;
-	ieee80211_txrx_result res = TXRX_DROP;
-
-	for (handler = handlers; *handler != NULL; handler++) {
-		res = (*handler)(rx);
-
-		switch (res) {
-		case TXRX_CONTINUE:
-			continue;
-		case TXRX_DROP:
-			I802_DEBUG_INC(local->rx_handlers_drop);
-			if (sta)
-				sta->rx_dropped++;
-			break;
-		case TXRX_QUEUED:
-			I802_DEBUG_INC(local->rx_handlers_queued);
-			break;
-		}
-		break;
-	}
-
-	if (res == TXRX_DROP)
-		dev_kfree_skb(rx->skb);
-	return res;
-}
-
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-						ieee80211_rx_handler *handlers,
-						struct ieee80211_txrx_data *rx,
-						struct sta_info *sta)
-{
-	if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
-	    TXRX_CONTINUE)
-		dev_kfree_skb(rx->skb);
+	return RX_QUEUED;
 }
 
 static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 					    struct ieee80211_hdr *hdr,
-					    struct sta_info *sta,
-					    struct ieee80211_txrx_data *rx)
+					    struct ieee80211_rx_data *rx)
 {
 	int keyidx, hdrlen;
 	DECLARE_MAC_BUF(mac);
@@ -1548,7 +1580,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 		       dev->name, print_mac(mac, hdr->addr2),
 		       print_mac(mac2, hdr->addr1), keyidx);
 
-	if (!sta) {
+	if (!rx->sta) {
 		/*
 		 * Some hardware seem to generate incorrect Michael MIC
 		 * reports; ignore them to avoid triggering countermeasures.
@@ -1600,7 +1632,89 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev,
 	rx->skb = NULL;
 }
 
-ieee80211_rx_handler ieee80211_rx_handlers[] =
+/* TODO: use IEEE80211_RX_FRAGMENTED */
+static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx)
+{
+	struct ieee80211_sub_if_data *sdata;
+	struct ieee80211_local *local = rx->local;
+	struct ieee80211_rtap_hdr {
+		struct ieee80211_radiotap_header hdr;
+		u8 flags;
+		u8 rate;
+		__le16 chan_freq;
+		__le16 chan_flags;
+	} __attribute__ ((packed)) *rthdr;
+	struct sk_buff *skb = rx->skb, *skb2;
+	struct net_device *prev_dev = NULL;
+	struct ieee80211_rx_status *status = rx->status;
+
+	if (rx->flags & IEEE80211_RX_CMNTR_REPORTED)
+		goto out_free_skb;
+
+	if (skb_headroom(skb) < sizeof(*rthdr) &&
+	    pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
+		goto out_free_skb;
+
+	rthdr = (void *)skb_push(skb, sizeof(*rthdr));
+	memset(rthdr, 0, sizeof(*rthdr));
+	rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+	rthdr->hdr.it_present =
+		cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+			    (1 << IEEE80211_RADIOTAP_RATE) |
+			    (1 << IEEE80211_RADIOTAP_CHANNEL));
+
+	rthdr->rate = rx->rate->bitrate / 5;
+	rthdr->chan_freq = cpu_to_le16(status->freq);
+
+	if (status->band == IEEE80211_BAND_5GHZ)
+		rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM |
+						IEEE80211_CHAN_5GHZ);
+	else
+		rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN |
+						IEEE80211_CHAN_2GHZ);
+
+	skb_set_mac_header(skb, 0);
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->pkt_type = PACKET_OTHERHOST;
+	skb->protocol = htons(ETH_P_802_2);
+
+	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+		if (!netif_running(sdata->dev))
+			continue;
+
+		if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR ||
+		    !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+			continue;
+
+		if (prev_dev) {
+			skb2 = skb_clone(skb, GFP_ATOMIC);
+			if (skb2) {
+				skb2->dev = prev_dev;
+				netif_rx(skb2);
+			}
+		}
+
+		prev_dev = sdata->dev;
+		sdata->dev->stats.rx_packets++;
+		sdata->dev->stats.rx_bytes += skb->len;
+	}
+
+	if (prev_dev) {
+		skb->dev = prev_dev;
+		netif_rx(skb);
+		skb = NULL;
+	} else
+		goto out_free_skb;
+
+	rx->flags |= IEEE80211_RX_CMNTR_REPORTED;
+	return;
+
+ out_free_skb:
+	dev_kfree_skb(skb);
+}
+
+typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *);
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
 {
 	ieee80211_rx_h_if_stats,
 	ieee80211_rx_h_passive_scan,
@@ -1622,10 +1736,51 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
 	NULL
 };
 
+static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
+					 struct ieee80211_rx_data *rx,
+					 struct sk_buff *skb)
+{
+	ieee80211_rx_handler *handler;
+	ieee80211_rx_result res = RX_DROP_MONITOR;
+
+	rx->skb = skb;
+	rx->sdata = sdata;
+	rx->dev = sdata->dev;
+
+	for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) {
+		res = (*handler)(rx);
+
+		switch (res) {
+		case RX_CONTINUE:
+			continue;
+		case RX_DROP_UNUSABLE:
+		case RX_DROP_MONITOR:
+			I802_DEBUG_INC(sdata->local->rx_handlers_drop);
+			if (rx->sta)
+				rx->sta->rx_dropped++;
+			break;
+		case RX_QUEUED:
+			I802_DEBUG_INC(sdata->local->rx_handlers_queued);
+			break;
+		}
+		break;
+	}
+
+	switch (res) {
+	case RX_CONTINUE:
+	case RX_DROP_MONITOR:
+		ieee80211_rx_cooked_monitor(rx);
+		break;
+	case RX_DROP_UNUSABLE:
+		dev_kfree_skb(rx->skb);
+		break;
+	}
+}
+
 /* main receive path */
 
 static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
-				u8 *bssid, struct ieee80211_txrx_data *rx,
+				u8 *bssid, struct ieee80211_rx_data *rx,
 				struct ieee80211_hdr *hdr)
 {
 	int multicast = is_multicast_ether_addr(hdr->addr1);
@@ -1635,34 +1790,47 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 		if (!bssid)
 			return 0;
 		if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
-			if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+			if (!(rx->flags & IEEE80211_RX_IN_SCAN))
 				return 0;
-			rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
 			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
-			rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
 		break;
 	case IEEE80211_IF_TYPE_IBSS:
 		if (!bssid)
 			return 0;
-		if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
-			if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+		if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+		    (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)
+			return 1;
+		else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+			if (!(rx->flags & IEEE80211_RX_IN_SCAN))
 				return 0;
-			rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		} else if (!multicast &&
 			   compare_ether_addr(sdata->dev->dev_addr,
 					      hdr->addr1) != 0) {
 			if (!(sdata->dev->flags & IFF_PROMISC))
 				return 0;
-			rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		} else if (!rx->sta)
 			rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb,
 							 bssid, hdr->addr2);
 		break;
+	case IEEE80211_IF_TYPE_MESH_POINT:
+		if (!multicast &&
+		    compare_ether_addr(sdata->dev->dev_addr,
+				       hdr->addr1) != 0) {
+			if (!(sdata->dev->flags & IFF_PROMISC))
+				return 0;
+
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
+		}
+		break;
 	case IEEE80211_IF_TYPE_VLAN:
 	case IEEE80211_IF_TYPE_AP:
 		if (!bssid) {
@@ -1671,12 +1839,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 				return 0;
 		} else if (!ieee80211_bssid_match(bssid,
 					sdata->dev->dev_addr)) {
-			if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+			if (!(rx->flags & IEEE80211_RX_IN_SCAN))
 				return 0;
-			rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH;
+			rx->flags &= ~IEEE80211_RX_RA_MATCH;
 		}
 		if (sdata->dev == sdata->local->mdev &&
-		    !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN))
+		    !(rx->flags & IEEE80211_RX_IN_SCAN))
 			/* do not receive anything via
 			 * master device when not scanning */
 			return 0;
@@ -1707,13 +1875,13 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
 static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 					 struct sk_buff *skb,
 					 struct ieee80211_rx_status *status,
-					 u32 load)
+					 u32 load,
+					 struct ieee80211_rate *rate)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata;
-	struct sta_info *sta;
 	struct ieee80211_hdr *hdr;
-	struct ieee80211_txrx_data rx;
+	struct ieee80211_rx_data rx;
 	u16 type;
 	int prepares;
 	struct ieee80211_sub_if_data *prev = NULL;
@@ -1725,42 +1893,33 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 	rx.skb = skb;
 	rx.local = local;
 
-	rx.u.rx.status = status;
-	rx.u.rx.load = load;
+	rx.status = status;
+	rx.load = load;
+	rx.rate = rate;
 	rx.fc = le16_to_cpu(hdr->frame_control);
 	type = rx.fc & IEEE80211_FCTL_FTYPE;
 
 	if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
 		local->dot11ReceivedFragmentCount++;
 
-	sta = rx.sta = sta_info_get(local, hdr->addr2);
-	if (sta) {
-		rx.dev = rx.sta->dev;
-		rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+	rx.sta = sta_info_get(local, hdr->addr2);
+	if (rx.sta) {
+		rx.sdata = rx.sta->sdata;
+		rx.dev = rx.sta->sdata->dev;
 	}
 
 	if ((status->flag & RX_FLAG_MMIC_ERROR)) {
-		ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
-		goto end;
+		ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx);
+		return;
 	}
 
 	if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
-		rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
+		rx.flags |= IEEE80211_RX_IN_SCAN;
 
-	if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
-					   sta) != TXRX_CONTINUE)
-		goto end;
-	skb = rx.skb;
+	ieee80211_parse_qos(&rx);
+	ieee80211_verify_ip_alignment(&rx);
 
-	if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) &&
-	    !atomic_read(&local->iff_promiscs) &&
-	    !is_multicast_ether_addr(hdr->addr1)) {
-		rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
-					     rx.sta);
-		sta_info_put(sta);
-		return;
-	}
+	skb = rx.skb;
 
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (!netif_running(sdata->dev))
@@ -1770,10 +1929,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 			continue;
 
 		bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type);
-		rx.flags |= IEEE80211_TXRXD_RXRA_MATCH;
+		rx.flags |= IEEE80211_RX_RA_MATCH;
 		prepares = prepare_for_handlers(sdata, bssid, &rx, hdr);
-		/* prepare_for_handlers can change sta */
-		sta = rx.sta;
 
 		if (!prepares)
 			continue;
@@ -1804,26 +1961,14 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 			continue;
 		}
 		rx.fc = le16_to_cpu(hdr->frame_control);
-		rx.skb = skb_new;
-		rx.dev = prev->dev;
-		rx.sdata = prev;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-					     &rx, sta);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb_new);
 		prev = sdata;
 	}
 	if (prev) {
 		rx.fc = le16_to_cpu(hdr->frame_control);
-		rx.skb = skb;
-		rx.dev = prev->dev;
-		rx.sdata = prev;
-		ieee80211_invoke_rx_handlers(local, local->rx_handlers,
-					     &rx, sta);
+		ieee80211_invoke_rx_handlers(prev, &rx, skb);
 	} else
 		dev_kfree_skb(skb);
-
- end:
-	if (sta)
-		sta_info_put(sta);
 }
 
 #define SEQ_MODULO 0x1000
@@ -1859,6 +2004,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 	u16 head_seq_num, buf_size;
 	int index;
 	u32 pkt_load;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_rate *rate;
 
 	buf_size = tid_agg_rx->buf_size;
 	head_seq_num = tid_agg_rx->head_seq_num;
@@ -1889,12 +2036,14 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 				memcpy(&status,
 					tid_agg_rx->reorder_buf[index]->cb,
 					sizeof(status));
+				sband = local->hw.wiphy->bands[status.band];
+				rate = &sband->bitrates[status.rate_idx];
 				pkt_load = ieee80211_rx_load_stats(local,
 						tid_agg_rx->reorder_buf[index],
-						&status);
+						&status, rate);
 				__ieee80211_rx_handle_packet(hw,
 					tid_agg_rx->reorder_buf[index],
-					&status, pkt_load);
+					&status, pkt_load, rate);
 				tid_agg_rx->stored_mpdu_num--;
 				tid_agg_rx->reorder_buf[index] = NULL;
 			}
@@ -1934,11 +2083,13 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
 		/* release the reordered frame back to stack */
 		memcpy(&status, tid_agg_rx->reorder_buf[index]->cb,
 			sizeof(status));
+		sband = local->hw.wiphy->bands[status.band];
+		rate = &sband->bitrates[status.rate_idx];
 		pkt_load = ieee80211_rx_load_stats(local,
 					tid_agg_rx->reorder_buf[index],
-					&status);
+					&status, rate);
 		__ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index],
-						&status, pkt_load);
+					     &status, pkt_load, rate);
 		tid_agg_rx->stored_mpdu_num--;
 		tid_agg_rx->reorder_buf[index] = NULL;
 		tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num);
@@ -1973,11 +2124,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 
 	qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN;
 	tid = qc[0] & QOS_CONTROL_TID_MASK;
-	tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]);
 
-	if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL)
+	if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL)
 		goto end_reorder;
 
+	tid_agg_rx = sta->ampdu_mlme.tid_rx[tid];
+
 	/* null data frames are excluded */
 	if (unlikely(fc & IEEE80211_STYPE_NULLFUNC))
 		goto end_reorder;
@@ -1994,7 +2146,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 	/* if this mpdu is fragmented - terminate rx aggregation session */
 	sc = le16_to_cpu(hdr->seq_ctrl);
 	if (sc & IEEE80211_SCTL_FRAG) {
-		ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr,
+		ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr,
 			tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP);
 		ret = 1;
 		goto end_reorder;
@@ -2004,9 +2156,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local,
 	mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4;
 	ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb,
 						mpdu_seq_num, 0);
-end_reorder:
-	if (sta)
-		sta_info_put(sta);
+ end_reorder:
 	return ret;
 }
 
@@ -2019,6 +2169,25 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	u32 pkt_load;
+	struct ieee80211_rate *rate = NULL;
+	struct ieee80211_supported_band *sband;
+
+	if (status->band < 0 ||
+	    status->band > IEEE80211_NUM_BANDS) {
+		WARN_ON(1);
+		return;
+	}
+
+	sband = local->hw.wiphy->bands[status->band];
+
+	if (!sband ||
+	    status->rate_idx < 0 ||
+	    status->rate_idx >= sband->n_bitrates) {
+		WARN_ON(1);
+		return;
+	}
+
+	rate = &sband->bitrates[status->rate_idx];
 
 	/*
 	 * key references and virtual interfaces are protected using RCU
@@ -2033,17 +2202,17 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
 	 * if it was previously present.
 	 * Also, frames with less than 16 bytes are dropped.
 	 */
-	skb = ieee80211_rx_monitor(local, skb, status);
+	skb = ieee80211_rx_monitor(local, skb, status, rate);
 	if (!skb) {
 		rcu_read_unlock();
 		return;
 	}
 
-	pkt_load = ieee80211_rx_load_stats(local, skb, status);
+	pkt_load = ieee80211_rx_load_stats(local, skb, status, rate);
 	local->channel_use_raw += pkt_load;
 
 	if (!ieee80211_rx_reorder_ampdu(local, skb))
-		__ieee80211_rx_handle_packet(hw, skb, status, pkt_load);
+		__ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate);
 
 	rcu_read_unlock();
 }
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 1f74bd296357..7e1e87257647 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -15,21 +15,59 @@
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
 #include <linux/timer.h>
+#include <linux/rtnetlink.h>
 
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
 #include "sta_info.h"
 #include "debugfs_sta.h"
+#include "mesh.h"
 
-/* Caller must hold local->sta_lock */
-static void sta_info_hash_add(struct ieee80211_local *local,
-			      struct sta_info *sta)
-{
-	sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
-	local->sta_hash[STA_HASH(sta->addr)] = sta;
-}
-
+/**
+ * DOC: STA information lifetime rules
+ *
+ * STA info structures (&struct sta_info) are managed in a hash table
+ * for faster lookup and a list for iteration. They are managed using
+ * RCU, i.e. access to the list and hash table is protected by RCU.
+ *
+ * Upon allocating a STA info structure with sta_info_alloc(), the caller owns
+ * that structure. It must then either destroy it using sta_info_destroy()
+ * (which is pretty useless) or insert it into the hash table using
+ * sta_info_insert() which demotes the reference from ownership to a regular
+ * RCU-protected reference; if the function is called without protection by an
+ * RCU critical section the reference is instantly invalidated. Note that the
+ * caller may not do much with the STA info before inserting it, in particular,
+ * it may not start any mesh peer link management or add encryption keys.
+ *
+ * When the insertion fails (sta_info_insert()) returns non-zero), the
+ * structure will have been freed by sta_info_insert()!
+ *
+ * Because there are debugfs entries for each station, and adding those
+ * must be able to sleep, it is also possible to "pin" a station entry,
+ * that means it can be removed from the hash table but not be freed.
+ * See the comment in __sta_info_unlink() for more information, this is
+ * an internal capability only.
+ *
+ * In order to remove a STA info structure, the caller needs to first
+ * unlink it (sta_info_unlink()) from the list and hash tables and
+ * then destroy it while holding the RTNL; sta_info_destroy() will wait
+ * for an RCU grace period to elapse before actually freeing it. Due to
+ * the pinning and the possibility of multiple callers trying to remove
+ * the same STA info at the same time, sta_info_unlink() can clear the
+ * STA info pointer it is passed to indicate that the STA info is owned
+ * by somebody else now.
+ *
+ * If sta_info_unlink() did not clear the pointer then the caller owns
+ * the STA info structure now and is responsible of destroying it with
+ * a call to sta_info_destroy(), not before RCU synchronisation, of
+ * course. Note that sta_info_destroy() must be protected by the RTNL.
+ *
+ * In all other cases, there is no concept of ownership on a STA entry,
+ * each structure is owned by the global hash table/list until it is
+ * removed. All users of the structure need to be RCU protected so that
+ * the structure won't be freed before they are done using it.
+ */
 
 /* Caller must hold local->sta_lock */
 static int sta_info_hash_del(struct ieee80211_local *local,
@@ -41,237 +79,464 @@ static int sta_info_hash_del(struct ieee80211_local *local,
 	if (!s)
 		return -ENOENT;
 	if (s == sta) {
-		local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+		rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)],
+				   s->hnext);
 		return 0;
 	}
 
 	while (s->hnext && s->hnext != sta)
 		s = s->hnext;
 	if (s->hnext) {
-		s->hnext = sta->hnext;
+		rcu_assign_pointer(s->hnext, sta->hnext);
 		return 0;
 	}
 
 	return -ENOENT;
 }
 
-struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+/* protected by RCU */
+static struct sta_info *__sta_info_find(struct ieee80211_local *local,
+					u8 *addr)
 {
 	struct sta_info *sta;
 
-	read_lock_bh(&local->sta_lock);
-	sta = local->sta_hash[STA_HASH(addr)];
+	sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
 	while (sta) {
-		if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
-			__sta_info_get(sta);
+		if (compare_ether_addr(sta->addr, addr) == 0)
 			break;
-		}
-		sta = sta->hnext;
+		sta = rcu_dereference(sta->hnext);
 	}
-	read_unlock_bh(&local->sta_lock);
-
 	return sta;
 }
+
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+{
+	return __sta_info_find(local, addr);
+}
 EXPORT_SYMBOL(sta_info_get);
 
-int sta_info_min_txrate_get(struct ieee80211_local *local)
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+				     struct net_device *dev)
 {
 	struct sta_info *sta;
-	struct ieee80211_hw_mode *mode;
-	int min_txrate = 9999999;
-	int i;
-
-	read_lock_bh(&local->sta_lock);
-	mode = local->oper_hw_mode;
-	for (i = 0; i < STA_HASH_SIZE; i++) {
-		sta = local->sta_hash[i];
-		while (sta) {
-			if (sta->txrate < min_txrate)
-				min_txrate = sta->txrate;
-			sta = sta->hnext;
+	int i = 0;
+
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
+		if (dev && dev != sta->sdata->dev)
+			continue;
+		if (i < idx) {
+			++i;
+			continue;
 		}
+		return sta;
 	}
-	read_unlock_bh(&local->sta_lock);
-	if (min_txrate == 9999999)
-		min_txrate = 0;
 
-	return mode->rates[min_txrate].rate;
+	return NULL;
 }
 
+/**
+ * __sta_info_free - internal STA free helper
+ *
+ * @sta: STA info to free
+ *
+ * This function must undo everything done by sta_info_alloc()
+ * that may happen before sta_info_insert().
+ */
+static void __sta_info_free(struct ieee80211_local *local,
+			    struct sta_info *sta)
+{
+	DECLARE_MAC_BUF(mbuf);
+
+	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
+	rate_control_put(sta->rate_ctrl);
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Destroyed STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
-static void sta_info_release(struct kref *kref)
+	kfree(sta);
+}
+
+void sta_info_destroy(struct sta_info *sta)
 {
-	struct sta_info *sta = container_of(kref, struct sta_info, kref);
-	struct ieee80211_local *local = sta->local;
+	struct ieee80211_local *local;
 	struct sk_buff *skb;
 	int i;
 
-	/* free sta structure; it has already been removed from
-	 * hash table etc. external structures. Make sure that all
-	 * buffered frames are release (one might have been added
-	 * after sta_info_free() was called). */
+	ASSERT_RTNL();
+	might_sleep();
+
+	if (!sta)
+		return;
+
+	local = sta->local;
+
+	rate_control_remove_sta_debugfs(sta);
+	ieee80211_sta_debugfs_remove(sta);
+
+#ifdef CONFIG_MAC80211_MESH
+	if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+		mesh_plink_deactivate(sta);
+#endif
+
+	if (sta->key) {
+		/*
+		 * NOTE: This will call synchronize_rcu() internally to
+		 * make sure no key references can be in use. We rely on
+		 * that when we take this branch to make sure nobody can
+		 * reference this STA struct any longer!
+		 */
+		ieee80211_key_free(sta->key);
+		WARN_ON(sta->key);
+	} else {
+		/*
+		 * Make sure that nobody can reference this STA struct
+		 * any longer.
+		 */
+		synchronize_rcu();
+	}
+
+#ifdef CONFIG_MAC80211_MESH
+	if (ieee80211_vif_is_mesh(&sta->sdata->vif))
+		del_timer_sync(&sta->plink_timer);
+#endif
+
 	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
 		local->total_ps_buffered--;
 		dev_kfree_skb_any(skb);
 	}
-	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+
+	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL)
 		dev_kfree_skb_any(skb);
+
+	for (i = 0; i <  STA_TID_NUM; i++) {
+		spin_lock_bh(&sta->ampdu_mlme.ampdu_rx);
+		if (sta->ampdu_mlme.tid_rx[i])
+		  del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx);
+		spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+		if (sta->ampdu_mlme.tid_tx[i])
+		  del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer);
+		spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
 	}
-	for (i = 0; i <  STA_TID_NUM; i++)
-		del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer);
-	rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
-	rate_control_put(sta->rate_ctrl);
-	kfree(sta);
+
+	__sta_info_free(local, sta);
 }
 
 
-void sta_info_put(struct sta_info *sta)
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_add(struct ieee80211_local *local,
+			      struct sta_info *sta)
 {
-	kref_put(&sta->kref, sta_info_release);
+	sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
+	rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta);
 }
-EXPORT_SYMBOL(sta_info_put);
 
-
-struct sta_info * sta_info_add(struct ieee80211_local *local,
-			       struct net_device *dev, u8 *addr, gfp_t gfp)
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+				u8 *addr, gfp_t gfp)
 {
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	int i;
-	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mbuf);
 
 	sta = kzalloc(sizeof(*sta), gfp);
 	if (!sta)
 		return NULL;
 
-	kref_init(&sta->kref);
+	memcpy(sta->addr, addr, ETH_ALEN);
+	sta->local = local;
+	sta->sdata = sdata;
 
 	sta->rate_ctrl = rate_control_get(local->rate_ctrl);
-	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
+	sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl,
+						     gfp);
 	if (!sta->rate_ctrl_priv) {
 		rate_control_put(sta->rate_ctrl);
 		kfree(sta);
 		return NULL;
 	}
 
-	memcpy(sta->addr, addr, ETH_ALEN);
-	sta->local = local;
-	sta->dev = dev;
 	spin_lock_init(&sta->ampdu_mlme.ampdu_rx);
+	spin_lock_init(&sta->ampdu_mlme.ampdu_tx);
 	for (i = 0; i < STA_TID_NUM; i++) {
 		/* timer_to_tid must be initialized with identity mapping to
 		 * enable session_timer's data differentiation. refer to
 		 * sta_rx_agg_session_timer_expired for useage */
 		sta->timer_to_tid[i] = i;
-		/* rx timers */
-		sta->ampdu_mlme.tid_rx[i].session_timer.function =
-			sta_rx_agg_session_timer_expired;
-		sta->ampdu_mlme.tid_rx[i].session_timer.data =
-			(unsigned long)&sta->timer_to_tid[i];
-		init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer);
+		/* tid to tx queue: initialize according to HW (0 is valid) */
+		sta->tid_to_tx_q[i] = local->hw.queues;
+		/* rx */
+		sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
+		sta->ampdu_mlme.tid_rx[i] = NULL;
+		/* tx */
+		sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE;
+		sta->ampdu_mlme.tid_tx[i] = NULL;
+		sta->ampdu_mlme.addba_req_num[i] = 0;
 	}
 	skb_queue_head_init(&sta->ps_tx_buf);
 	skb_queue_head_init(&sta->tx_filtered);
-	__sta_info_get(sta);	/* sta used by caller, decremented by
-				 * sta_info_put() */
-	write_lock_bh(&local->sta_lock);
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Allocated STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+#ifdef CONFIG_MAC80211_MESH
+	sta->plink_state = PLINK_LISTEN;
+	spin_lock_init(&sta->plink_lock);
+	init_timer(&sta->plink_timer);
+#endif
+
+	return sta;
+}
+
+int sta_info_insert(struct sta_info *sta)
+{
+	struct ieee80211_local *local = sta->local;
+	struct ieee80211_sub_if_data *sdata = sta->sdata;
+	unsigned long flags;
+	int err = 0;
+	DECLARE_MAC_BUF(mac);
+
+	/*
+	 * Can't be a WARN_ON because it can be triggered through a race:
+	 * something inserts a STA (on one CPU) without holding the RTNL
+	 * and another CPU turns off the net device.
+	 */
+	if (unlikely(!netif_running(sdata->dev))) {
+		err = -ENETDOWN;
+		goto out_free;
+	}
+
+	if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0 ||
+	            is_multicast_ether_addr(sta->addr))) {
+		err = -EINVAL;
+		goto out_free;
+	}
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	/* check if STA exists already */
+	if (__sta_info_find(local, sta->addr)) {
+		spin_unlock_irqrestore(&local->sta_lock, flags);
+		err = -EEXIST;
+		goto out_free;
+	}
 	list_add(&sta->list, &local->sta_list);
 	local->num_sta++;
 	sta_info_hash_add(local, sta);
-	if (local->ops->sta_notify) {
-		struct ieee80211_sub_if_data *sdata;
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	/* notify driver */
+	if (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 			sdata = sdata->u.vlan.ap;
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-				       STA_NOTIFY_ADD, addr);
+				       STA_NOTIFY_ADD, sta->addr);
 	}
-	write_unlock_bh(&local->sta_lock);
 
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Added STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, addr));
+	printk(KERN_DEBUG "%s: Inserted STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 
+	spin_unlock_irqrestore(&local->sta_lock, flags);
+
 #ifdef CONFIG_MAC80211_DEBUGFS
-	/* debugfs entry adding might sleep, so schedule process
+	/*
+	 * Debugfs entry adding might sleep, so schedule process
 	 * context task for adding entry for STAs that do not yet
-	 * have one. */
+	 * have one.
+	 * NOTE: due to auto-freeing semantics this may only be done
+	 *       if the insertion is successful!
+	 */
 	queue_work(local->hw.workqueue, &local->sta_debugfs_add);
 #endif
 
-	return sta;
+	if (ieee80211_vif_is_mesh(&sdata->vif))
+		mesh_accept_plinks_update(sdata);
+
+	return 0;
+ out_free:
+	BUG_ON(!err);
+	__sta_info_free(local, sta);
+	return err;
 }
 
-/* Caller must hold local->sta_lock */
-void sta_info_remove(struct sta_info *sta)
+static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
 {
-	struct ieee80211_local *local = sta->local;
-	struct ieee80211_sub_if_data *sdata;
+	/*
+	 * This format has been mandated by the IEEE specifications,
+	 * so this line may not be changed to use the __set_bit() format.
+	 */
+	bss->tim[aid / 8] |= (1 << (aid % 8));
+}
 
-	/* don't do anything if we've been removed already */
-	if (sta_info_hash_del(local, sta))
-		return;
+static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid)
+{
+	/*
+	 * This format has been mandated by the IEEE specifications,
+	 * so this line may not be changed to use the __clear_bit() format.
+	 */
+	bss->tim[aid / 8] &= ~(1 << (aid % 8));
+}
 
-	list_del(&sta->list);
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
-	if (sta->flags & WLAN_STA_PS) {
-		sta->flags &= ~WLAN_STA_PS;
-		if (sdata->bss)
-			atomic_dec(&sdata->bss->num_sta_ps);
+static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss,
+				   struct sta_info *sta)
+{
+	if (bss)
+		__bss_tim_set(bss, sta->aid);
+	if (sta->local->ops->set_tim) {
+		sta->local->tim_in_locked_section = true;
+		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1);
+		sta->local->tim_in_locked_section = false;
 	}
-	local->num_sta--;
-	sta_info_remove_aid_ptr(sta);
+}
 
+void sta_info_set_tim_bit(struct sta_info *sta)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&sta->local->sta_lock, flags);
+	__sta_info_set_tim_bit(sta->sdata->bss, sta);
+	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
 }
 
-void sta_info_free(struct sta_info *sta)
+static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss,
+				     struct sta_info *sta)
 {
-	struct sk_buff *skb;
-	struct ieee80211_local *local = sta->local;
-	DECLARE_MAC_BUF(mac);
+	if (bss)
+		__bss_tim_clear(bss, sta->aid);
+	if (sta->local->ops->set_tim) {
+		sta->local->tim_in_locked_section = true;
+		sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0);
+		sta->local->tim_in_locked_section = false;
+	}
+}
 
-	might_sleep();
+void sta_info_clear_tim_bit(struct sta_info *sta)
+{
+	unsigned long flags;
 
-	write_lock_bh(&local->sta_lock);
-	sta_info_remove(sta);
-	write_unlock_bh(&local->sta_lock);
+	spin_lock_irqsave(&sta->local->sta_lock, flags);
+	__sta_info_clear_tim_bit(sta->sdata->bss, sta);
+	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+}
 
-	while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
-		local->total_ps_buffered--;
-		dev_kfree_skb(skb);
-	}
-	while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
-		dev_kfree_skb(skb);
-	}
+/*
+ * See comment in __sta_info_unlink,
+ * caller must hold local->sta_lock.
+ */
+static void __sta_info_pin(struct sta_info *sta)
+{
+	WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL);
+	sta->pin_status = STA_INFO_PIN_STAT_PINNED;
+}
+
+/*
+ * See comment in __sta_info_unlink, returns sta if it
+ * needs to be destroyed.
+ */
+static struct sta_info *__sta_info_unpin(struct sta_info *sta)
+{
+	struct sta_info *ret = NULL;
+	unsigned long flags;
 
+	spin_lock_irqsave(&sta->local->sta_lock, flags);
+	WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY &&
+		sta->pin_status != STA_INFO_PIN_STAT_PINNED);
+	if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY)
+		ret = sta;
+	sta->pin_status = STA_INFO_PIN_STAT_NORMAL;
+	spin_unlock_irqrestore(&sta->local->sta_lock, flags);
+
+	return ret;
+}
+
+void __sta_info_unlink(struct sta_info **sta)
+{
+	struct ieee80211_local *local = (*sta)->local;
+	struct ieee80211_sub_if_data *sdata = (*sta)->sdata;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-	printk(KERN_DEBUG "%s: Removed STA %s\n",
-	       wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr));
-#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+	DECLARE_MAC_BUF(mbuf);
+#endif
+	/*
+	 * pull caller's reference if we're already gone.
+	 */
+	if (sta_info_hash_del(local, *sta)) {
+		*sta = NULL;
+		return;
+	}
 
-	ieee80211_key_free(sta->key);
-	sta->key = NULL;
+	/*
+	 * Also pull caller's reference if the STA is pinned by the
+	 * task that is adding the debugfs entries. In that case, we
+	 * leave the STA "to be freed".
+	 *
+	 * The rules are not trivial, but not too complex either:
+	 *  (1) pin_status is only modified under the sta_lock
+	 *  (2) sta_info_debugfs_add_work() will set the status
+	 *	to PINNED when it found an item that needs a new
+	 *	debugfs directory created. In that case, that item
+	 *	must not be freed although all *RCU* users are done
+	 *	with it. Hence, we tell the caller of _unlink()
+	 *	that the item is already gone (as can happen when
+	 *	two tasks try to unlink/destroy at the same time)
+	 *  (3) We set the pin_status to DESTROY here when we
+	 *	find such an item.
+	 *  (4) sta_info_debugfs_add_work() will reset the pin_status
+	 *	from PINNED to NORMAL when it is done with the item,
+	 *	but will check for DESTROY before resetting it in
+	 *	which case it will free the item.
+	 */
+	if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) {
+		(*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY;
+		*sta = NULL;
+		return;
+	}
 
-	if (local->ops->sta_notify) {
-		struct ieee80211_sub_if_data *sdata;
+	list_del(&(*sta)->list);
 
-		sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	if ((*sta)->flags & WLAN_STA_PS) {
+		(*sta)->flags &= ~WLAN_STA_PS;
+		if (sdata->bss)
+			atomic_dec(&sdata->bss->num_sta_ps);
+		__sta_info_clear_tim_bit(sdata->bss, *sta);
+	}
 
+	local->num_sta--;
+
+	if (local->ops->sta_notify) {
 		if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
 			sdata = sdata->u.vlan.ap;
 
 		local->ops->sta_notify(local_to_hw(local), &sdata->vif,
-				       STA_NOTIFY_REMOVE, sta->addr);
+				       STA_NOTIFY_REMOVE, (*sta)->addr);
 	}
 
-	rate_control_remove_sta_debugfs(sta);
-	ieee80211_sta_debugfs_remove(sta);
+	if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		mesh_accept_plinks_update(sdata);
+#ifdef CONFIG_MAC80211_MESH
+		del_timer(&(*sta)->plink_timer);
+#endif
+	}
 
-	sta_info_put(sta);
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+	printk(KERN_DEBUG "%s: Removed STA %s\n",
+	       wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 }
 
+void sta_info_unlink(struct sta_info **sta)
+{
+	struct ieee80211_local *local = (*sta)->local;
+	unsigned long flags;
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	__sta_info_unlink(sta);
+	spin_unlock_irqrestore(&local->sta_lock, flags);
+}
 
 static inline int sta_info_buffer_expired(struct ieee80211_local *local,
 					  struct sta_info *sta,
@@ -299,6 +564,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 {
 	unsigned long flags;
 	struct sk_buff *skb;
+	struct ieee80211_sub_if_data *sdata;
 	DECLARE_MAC_BUF(mac);
 
 	if (skb_queue_empty(&sta->ps_tx_buf))
@@ -307,21 +573,23 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
 	for (;;) {
 		spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
 		skb = skb_peek(&sta->ps_tx_buf);
-		if (sta_info_buffer_expired(local, sta, skb)) {
+		if (sta_info_buffer_expired(local, sta, skb))
 			skb = __skb_dequeue(&sta->ps_tx_buf);
-			if (skb_queue_empty(&sta->ps_tx_buf))
-				sta->flags &= ~WLAN_STA_TIM;
-		} else
+		else
 			skb = NULL;
 		spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
 
-		if (skb) {
-			local->total_ps_buffered--;
-			printk(KERN_DEBUG "Buffered frame expired (STA "
-			       "%s)\n", print_mac(mac, sta->addr));
-			dev_kfree_skb(skb);
-		} else
+		if (!skb)
 			break;
+
+		sdata = sta->sdata;
+		local->total_ps_buffered--;
+		printk(KERN_DEBUG "Buffered frame expired (STA "
+		       "%s)\n", print_mac(mac, sta->addr));
+		dev_kfree_skb(skb);
+
+		if (skb_queue_empty(&sta->ps_tx_buf))
+			sta_info_clear_tim_bit(sta);
 	}
 }
 
@@ -331,13 +599,10 @@ static void sta_info_cleanup(unsigned long data)
 	struct ieee80211_local *local = (struct ieee80211_local *) data;
 	struct sta_info *sta;
 
-	read_lock_bh(&local->sta_lock);
-	list_for_each_entry(sta, &local->sta_list, list) {
-		__sta_info_get(sta);
+	rcu_read_lock();
+	list_for_each_entry_rcu(sta, &local->sta_list, list)
 		sta_info_cleanup_expire_buffered(local, sta);
-		sta_info_put(sta);
-	}
-	read_unlock_bh(&local->sta_lock);
+	rcu_read_unlock();
 
 	local->sta_cleanup.expires =
 		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
@@ -345,38 +610,75 @@ static void sta_info_cleanup(unsigned long data)
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-static void sta_info_debugfs_add_task(struct work_struct *work)
+static void sta_info_debugfs_add_work(struct work_struct *work)
 {
 	struct ieee80211_local *local =
 		container_of(work, struct ieee80211_local, sta_debugfs_add);
 	struct sta_info *sta, *tmp;
+	unsigned long flags;
 
 	while (1) {
 		sta = NULL;
-		read_lock_bh(&local->sta_lock);
+
+		spin_lock_irqsave(&local->sta_lock, flags);
 		list_for_each_entry(tmp, &local->sta_list, list) {
 			if (!tmp->debugfs.dir) {
 				sta = tmp;
-				__sta_info_get(sta);
+				__sta_info_pin(sta);
 				break;
 			}
 		}
-		read_unlock_bh(&local->sta_lock);
+		spin_unlock_irqrestore(&local->sta_lock, flags);
 
 		if (!sta)
 			break;
 
 		ieee80211_sta_debugfs_add(sta);
 		rate_control_add_sta_debugfs(sta);
-		sta_info_put(sta);
+
+		sta = __sta_info_unpin(sta);
+		rtnl_lock();
+		sta_info_destroy(sta);
+		rtnl_unlock();
 	}
 }
 #endif
 
+void __ieee80211_run_pending_flush(struct ieee80211_local *local)
+{
+	struct sta_info *sta;
+	unsigned long flags;
+
+	ASSERT_RTNL();
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	while (!list_empty(&local->sta_flush_list)) {
+		sta = list_first_entry(&local->sta_flush_list,
+				       struct sta_info, list);
+		list_del(&sta->list);
+		spin_unlock_irqrestore(&local->sta_lock, flags);
+		sta_info_destroy(sta);
+		spin_lock_irqsave(&local->sta_lock, flags);
+	}
+	spin_unlock_irqrestore(&local->sta_lock, flags);
+}
+
+static void ieee80211_sta_flush_work(struct work_struct *work)
+{
+	struct ieee80211_local *local =
+		container_of(work, struct ieee80211_local, sta_flush_work);
+
+	rtnl_lock();
+	__ieee80211_run_pending_flush(local);
+	rtnl_unlock();
+}
+
 void sta_info_init(struct ieee80211_local *local)
 {
-	rwlock_init(&local->sta_lock);
+	spin_lock_init(&local->sta_lock);
 	INIT_LIST_HEAD(&local->sta_list);
+	INIT_LIST_HEAD(&local->sta_flush_list);
+	INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work);
 
 	setup_timer(&local->sta_cleanup, sta_info_cleanup,
 		    (unsigned long)local);
@@ -384,7 +686,7 @@ void sta_info_init(struct ieee80211_local *local)
 		round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL);
 
 #ifdef CONFIG_MAC80211_DEBUGFS
-	INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task);
+	INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work);
 #endif
 }
 
@@ -397,47 +699,80 @@ int sta_info_start(struct ieee80211_local *local)
 void sta_info_stop(struct ieee80211_local *local)
 {
 	del_timer(&local->sta_cleanup);
+	cancel_work_sync(&local->sta_flush_work);
+
+	rtnl_lock();
 	sta_info_flush(local, NULL);
+	__ieee80211_run_pending_flush(local);
+	rtnl_unlock();
 }
 
-void sta_info_remove_aid_ptr(struct sta_info *sta)
+/**
+ * sta_info_flush - flush matching STA entries from the STA table
+ *
+ * Returns the number of removed STA entries.
+ *
+ * @local: local interface data
+ * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs
+ */
+int sta_info_flush(struct ieee80211_local *local,
+		    struct ieee80211_sub_if_data *sdata)
 {
-	struct ieee80211_sub_if_data *sdata;
+	struct sta_info *sta, *tmp;
+	LIST_HEAD(tmp_list);
+	int ret = 0;
+	unsigned long flags;
 
-	if (sta->aid <= 0)
-		return;
+	might_sleep();
+	ASSERT_RTNL();
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+		if (!sdata || sdata == sta->sdata) {
+			__sta_info_unlink(&sta);
+			if (sta) {
+				list_add_tail(&sta->list, &tmp_list);
+				ret++;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+	list_for_each_entry_safe(sta, tmp, &tmp_list, list)
+		sta_info_destroy(sta);
 
-	if (sdata->local->ops->set_tim)
-		sdata->local->ops->set_tim(local_to_hw(sdata->local),
-					  sta->aid, 0);
-	if (sdata->bss)
-		__bss_tim_clear(sdata->bss, sta->aid);
+	return ret;
 }
 
-
 /**
- * sta_info_flush - flush matching STA entries from the STA table
- * @local: local interface data
- * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
+ * sta_info_flush_delayed - flush matching STA entries from the STA table
+ *
+ * This function unlinks all stations for a given interface and queues
+ * them for freeing. Note that the workqueue function scheduled here has
+ * to run before any new keys can be added to the system to avoid set_key()
+ * callback ordering issues.
+ *
+ * @sdata: the interface
  */
-void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
+void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta, *tmp;
-	LIST_HEAD(tmp_list);
-
-	write_lock_bh(&local->sta_lock);
-	list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
-		if (!dev || dev == sta->dev) {
-			__sta_info_get(sta);
-			sta_info_remove(sta);
-			list_add_tail(&sta->list, &tmp_list);
+	unsigned long flags;
+	bool work = false;
+
+	spin_lock_irqsave(&local->sta_lock, flags);
+	list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+		if (sdata == sta->sdata) {
+			__sta_info_unlink(&sta);
+			if (sta) {
+				list_add_tail(&sta->list,
+					      &local->sta_flush_list);
+				work = true;
+			}
 		}
-	write_unlock_bh(&local->sta_lock);
-
-	list_for_each_entry_safe(sta, tmp, &tmp_list, list) {
-		sta_info_free(sta);
-		sta_info_put(sta);
 	}
+	if (work)
+		schedule_work(&local->sta_flush_work);
+	spin_unlock_irqrestore(&local->sta_lock, flags);
 }
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 96fe3ed95038..ebb7b2b4d0b9 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -12,160 +12,293 @@
 #include <linux/list.h>
 #include <linux/types.h>
 #include <linux/if_ether.h>
-#include <linux/kref.h>
 #include "ieee80211_key.h"
 
-/* Stations flags (struct sta_info::flags) */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
-				    * controlling whether STA is authorized to
-				    * send and receive non-IEEE 802.1X frames
-				    */
-#define WLAN_STA_SHORT_PREAMBLE BIT(7)
-/* whether this is an AP that we are associated with as a client */
-#define WLAN_STA_ASSOC_AP BIT(8)
-#define WLAN_STA_WME BIT(9)
-#define WLAN_STA_WDS BIT(27)
+/**
+ * enum ieee80211_sta_info_flags - Stations flags
+ *
+ * These flags are used with &struct sta_info's @flags member.
+ *
+ * @WLAN_STA_AUTH: Station is authenticated.
+ * @WLAN_STA_ASSOC: Station is associated.
+ * @WLAN_STA_PS: Station is in power-save mode
+ * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic.
+ *	This bit is always checked so needs to be enabled for all stations
+ *	when virtual port control is not in use.
+ * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble
+ *	frames.
+ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP.
+ * @WLAN_STA_WME: Station is a QoS-STA.
+ * @WLAN_STA_WDS: Station is one of our WDS peers.
+ * @WLAN_STA_PSPOLL: Station has just PS-polled us.
+ * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the
+ *	IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next
+ *	frame to this station is transmitted.
+ */
+enum ieee80211_sta_info_flags {
+	WLAN_STA_AUTH		= 1<<0,
+	WLAN_STA_ASSOC		= 1<<1,
+	WLAN_STA_PS		= 1<<2,
+	WLAN_STA_AUTHORIZED	= 1<<3,
+	WLAN_STA_SHORT_PREAMBLE	= 1<<4,
+	WLAN_STA_ASSOC_AP	= 1<<5,
+	WLAN_STA_WME		= 1<<6,
+	WLAN_STA_WDS		= 1<<7,
+	WLAN_STA_PSPOLL		= 1<<8,
+	WLAN_STA_CLEAR_PS_FILT	= 1<<9,
+};
 
 #define STA_TID_NUM 16
 #define ADDBA_RESP_INTERVAL HZ
+#define HT_AGG_MAX_RETRIES		(0x3)
 
 #define HT_AGG_STATE_INITIATOR_SHIFT	(4)
 
+#define HT_ADDBA_REQUESTED_MSK		BIT(0)
+#define HT_ADDBA_DRV_READY_MSK		BIT(1)
+#define HT_ADDBA_RECEIVED_MSK		BIT(2)
 #define HT_AGG_STATE_REQ_STOP_BA_MSK	BIT(3)
-
+#define HT_AGG_STATE_INITIATOR_MSK      BIT(HT_AGG_STATE_INITIATOR_SHIFT)
 #define HT_AGG_STATE_IDLE		(0x0)
-#define HT_AGG_STATE_OPERATIONAL	(0x7)
+#define HT_AGG_STATE_OPERATIONAL	(HT_ADDBA_REQUESTED_MSK |	\
+					 HT_ADDBA_DRV_READY_MSK |	\
+					 HT_ADDBA_RECEIVED_MSK)
+#define HT_AGG_STATE_DEBUGFS_CTL	BIT(7)
 
 /**
- * struct tid_ampdu_rx - TID aggregation information (Rx).
+ * struct tid_ampdu_tx - TID aggregation information (Tx).
  *
- * @state: TID's state in session state machine.
+ * @addba_resp_timer: timer for peer's response to addba request
+ * @ssn: Starting Sequence Number expected to be aggregated.
  * @dialog_token: dialog token for aggregation session
+ */
+struct tid_ampdu_tx {
+	struct timer_list addba_resp_timer;
+	u16 ssn;
+	u8 dialog_token;
+};
+
+/**
+ * struct tid_ampdu_rx - TID aggregation information (Rx).
+ *
+ * @reorder_buf: buffer to reorder incoming aggregated MPDUs
+ * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @head_seq_num: head sequence number in reordering buffer.
+ * @stored_mpdu_num: number of MPDUs in reordering buffer
  * @ssn: Starting Sequence Number expected to be aggregated.
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value.
- * @head_seq_num: head sequence number in reordering buffer.
- * @stored_mpdu_num: number of MPDUs in reordering buffer
- * @reorder_buf: buffer to reorder incoming aggregated MPDUs
- * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
+ * @dialog_token: dialog token for aggregation session
  */
 struct tid_ampdu_rx {
-	u8 state;
-	u8 dialog_token;
+	struct sk_buff **reorder_buf;
+	struct timer_list session_timer;
+	u16 head_seq_num;
+	u16 stored_mpdu_num;
 	u16 ssn;
 	u16 buf_size;
 	u16 timeout;
-	u16 head_seq_num;
-	u16 stored_mpdu_num;
-	struct sk_buff **reorder_buf;
-	struct timer_list session_timer;
+	u8 dialog_token;
+};
+
+/**
+ * enum plink_state - state of a mesh peer link finite state machine
+ *
+ * @PLINK_LISTEN: initial state, considered the implicit state of non existant
+ * 	mesh peer links
+ * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer
+ * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer
+ * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh
+ * 	peer
+ * @PLINK_ESTAB: mesh peer link is established
+ * @PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded
+ */
+enum plink_state {
+	PLINK_LISTEN,
+	PLINK_OPN_SNT,
+	PLINK_OPN_RCVD,
+	PLINK_CNF_RCVD,
+	PLINK_ESTAB,
+	PLINK_HOLDING,
+	PLINK_BLOCKED
 };
 
 /**
  * struct sta_ampdu_mlme - STA aggregation information.
  *
- * @tid_agg_info_rx: aggregation info for Rx per TID
+ * @tid_state_rx: TID's state in Rx session state machine.
+ * @tid_rx: aggregation info for Rx per TID
  * @ampdu_rx: for locking sections in aggregation Rx flow
+ * @tid_state_tx: TID's state in Tx session state machine.
+ * @tid_tx: aggregation info for Tx per TID
+ * @addba_req_num: number of times addBA request has been sent.
+ * @ampdu_tx: for locking sectionsi in aggregation Tx flow
+ * @dialog_token_allocator: dialog token enumerator for each new session;
  */
 struct sta_ampdu_mlme {
-	struct tid_ampdu_rx tid_rx[STA_TID_NUM];
+	/* rx */
+	u8 tid_state_rx[STA_TID_NUM];
+	struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
 	spinlock_t ampdu_rx;
+	/* tx */
+	u8 tid_state_tx[STA_TID_NUM];
+	struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+	u8 addba_req_num[STA_TID_NUM];
+	spinlock_t ampdu_tx;
+	u8 dialog_token_allocator;
 };
 
+
+/* see __sta_info_unlink */
+#define STA_INFO_PIN_STAT_NORMAL	0
+#define STA_INFO_PIN_STAT_PINNED	1
+#define STA_INFO_PIN_STAT_DESTROY	2
+
+/**
+ * struct sta_info - STA information
+ *
+ * This structure collects information about a station that
+ * mac80211 is communicating with.
+ *
+ * @list: global linked list entry
+ * @hnext: hash table linked list pointer
+ * @local: pointer to the global information
+ * @addr: MAC address of this STA
+ * @aid: STA's unique AID (1..2007, 0 = not assigned yet),
+ *	only used in AP (and IBSS?) mode
+ * @flags: STA flags, see &enum ieee80211_sta_info_flags
+ * @ps_tx_buf: buffer of frames to transmit to this station
+ *	when it leaves power saving state
+ * @tx_filtered: buffer of frames we already tried to transmit
+ *	but were filtered by hardware due to STA having entered
+ *	power saving state
+ * @rx_packets: Number of MSDUs received from this STA
+ * @rx_bytes: Number of bytes received from this STA
+ * @supp_rates: Bitmap of supported rates (per band)
+ * @ht_info: HT capabilities of this STA
+ */
 struct sta_info {
-	struct kref kref;
+	/* General information, mostly static */
 	struct list_head list;
-	struct sta_info *hnext; /* next entry in hash table list */
-
+	struct sta_info *hnext;
 	struct ieee80211_local *local;
-
-	u8 addr[ETH_ALEN];
-	u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */
-	u32 flags; /* WLAN_STA_ */
-
-	struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in
-					* power saving state */
-	int pspoll; /* whether STA has send a PS Poll frame */
-	struct sk_buff_head tx_filtered; /* buffer of TX frames that were
-					  * already given to low-level driver,
-					  * but were filtered */
-	int clear_dst_mask;
-
-	unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */
-	unsigned long rx_bytes, tx_bytes;
-	unsigned long tx_retry_failed, tx_retry_count;
-	unsigned long tx_filtered_count;
-
-	unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
-
-	unsigned long last_rx;
-	u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
-	int txrate; /* index in local->curr_rates */
-	int last_txrate; /* last rate used to send a frame to this STA */
-	int last_nonerp_idx;
-
-	struct net_device *dev; /* which net device is this station associated
-				 * to */
-
+	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_key *key;
-
-	u32 tx_num_consecutive_failures;
-	u32 tx_num_mpdu_ok;
-	u32 tx_num_mpdu_fail;
-
 	struct rate_control_ref *rate_ctrl;
 	void *rate_ctrl_priv;
+	struct ieee80211_ht_info ht_info;
+	u64 supp_rates[IEEE80211_NUM_BANDS];
+	u8 addr[ETH_ALEN];
+	u16 aid;
+	u16 listen_interval;
 
-	/* last received seq/frag number from this STA (per RX queue) */
-	__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
+	/*
+	 * for use by the internal lifetime management,
+	 * see __sta_info_unlink
+	 */
+	u8 pin_status;
+
+	/* frequently updated information, needs locking? */
+	u32 flags;
+
+	/*
+	 * STA powersave frame queues, no more than the internal
+	 * locking required.
+	 */
+	struct sk_buff_head ps_tx_buf;
+	struct sk_buff_head tx_filtered;
+
+	/* Updated from RX path only, no locking requirements */
+	unsigned long rx_packets, rx_bytes;
+	unsigned long wep_weak_iv_count;
+	unsigned long last_rx;
 	unsigned long num_duplicates; /* number of duplicate frames received
 				       * from this STA */
-	unsigned long tx_fragments; /* number of transmitted MPDUs */
 	unsigned long rx_fragments; /* number of received MPDUs */
 	unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
-
 	int last_rssi; /* RSSI of last received frame from this STA */
 	int last_signal; /* signal of last received frame from this STA */
 	int last_noise; /* noise of last received frame from this STA */
-	int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */
-	unsigned long last_ack;
-	int channel_use;
-	int channel_use_raw;
-
+	/* last received seq/frag number from this STA (per RX queue) */
+	__le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+#endif
+
+	/* Updated from TX status path only, no locking requirements */
+	unsigned long tx_filtered_count;
+	unsigned long tx_retry_failed, tx_retry_count;
+	/* TODO: update in generic code not rate control? */
+	u32 tx_num_consecutive_failures;
+	u32 tx_num_mpdu_ok;
+	u32 tx_num_mpdu_fail;
+	/* moving percentage of failed MSDUs */
+	unsigned int fail_avg;
+
+	/* Updated from TX path only, no locking requirements */
+	unsigned long tx_packets; /* number of RX/TX MSDUs */
+	unsigned long tx_bytes;
+	unsigned long tx_fragments; /* number of transmitted MPDUs */
+	int txrate_idx;
+	int last_txrate_idx;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 	unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
-#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+#endif
 
-	u16 listen_interval;
+	/* Debug counters, no locking doesn't matter */
+	int channel_use;
+	int channel_use_raw;
 
-	struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities
-					     of this STA */
+	/*
+	 * Aggregation information, comes with own locking.
+	 */
 	struct sta_ampdu_mlme ampdu_mlme;
-	u8 timer_to_tid[STA_TID_NUM];	/* convert timer id to tid */
+	u8 timer_to_tid[STA_TID_NUM];	/* identity mapping to ID timers */
+	u8 tid_to_tx_q[STA_TID_NUM];	/* map tid to tx queue */
+
+#ifdef CONFIG_MAC80211_MESH
+	/*
+	 * Mesh peer link attributes
+	 * TODO: move to a sub-structure that is referenced with pointer?
+	 */
+	__le16 llid;		/* Local link ID */
+	__le16 plid;		/* Peer link ID */
+	__le16 reason;		/* Cancel reason on PLINK_HOLDING state */
+	u8 plink_retries;	/* Retries in establishment */
+	bool ignore_plink_timer;
+	enum plink_state plink_state;
+	u32 plink_timeout;
+	struct timer_list plink_timer;
+	spinlock_t plink_lock;	/* For peer_state reads / updates and other
+				   updates in the structure. Ensures robust
+				   transitions for the peerlink FSM */
+#endif
 
 #ifdef CONFIG_MAC80211_DEBUGFS
 	struct sta_info_debugfsdentries {
 		struct dentry *dir;
 		struct dentry *flags;
 		struct dentry *num_ps_buf_frames;
-		struct dentry *last_ack_rssi;
-		struct dentry *last_ack_ms;
 		struct dentry *inactive_ms;
 		struct dentry *last_seq_ctrl;
 #ifdef CONFIG_MAC80211_DEBUG_COUNTERS
 		struct dentry *wme_rx_queue;
 		struct dentry *wme_tx_queue;
 #endif
+		struct dentry *agg_status;
 	} debugfs;
 #endif
 };
 
+static inline enum plink_state sta_plink_state(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_MESH
+	return sta->plink_state;
+#endif
+	return PLINK_LISTEN;
+}
+
 
 /* Maximum number of concurrently registered stations */
 #define MAX_STA_COUNT 2007
@@ -185,22 +318,47 @@ struct sta_info {
  */
 #define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
 
-static inline void __sta_info_get(struct sta_info *sta)
-{
-	kref_get(&sta->kref);
-}
+/*
+ * Get a STA info, must have be under RCU read lock.
+ */
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr);
+/*
+ * Get STA info by index, BROKEN!
+ */
+struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx,
+				      struct net_device *dev);
+/*
+ * Create a new STA info, caller owns returned structure
+ * until sta_info_insert().
+ */
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+				u8 *addr, gfp_t gfp);
+/*
+ * Insert STA info into hash table/list, returns zero or a
+ * -EEXIST if (if the same MAC address is already present).
+ *
+ * Calling this without RCU protection makes the caller
+ * relinquish its reference to @sta.
+ */
+int sta_info_insert(struct sta_info *sta);
+/*
+ * Unlink a STA info from the hash table/list.
+ * This can NULL the STA pointer if somebody else
+ * has already unlinked it.
+ */
+void sta_info_unlink(struct sta_info **sta);
+void __sta_info_unlink(struct sta_info **sta);
+
+void sta_info_destroy(struct sta_info *sta);
+void sta_info_set_tim_bit(struct sta_info *sta);
+void sta_info_clear_tim_bit(struct sta_info *sta);
 
-struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
-int sta_info_min_txrate_get(struct ieee80211_local *local);
-void sta_info_put(struct sta_info *sta);
-struct sta_info * sta_info_add(struct ieee80211_local *local,
-			       struct net_device *dev, u8 *addr, gfp_t gfp);
-void sta_info_remove(struct sta_info *sta);
-void sta_info_free(struct sta_info *sta);
 void sta_info_init(struct ieee80211_local *local);
 int sta_info_start(struct ieee80211_local *local);
 void sta_info_stop(struct ieee80211_local *local);
-void sta_info_remove_aid_ptr(struct sta_info *sta);
-void sta_info_flush(struct ieee80211_local *local, struct net_device *dev);
+int sta_info_flush(struct ieee80211_local *local,
+		    struct ieee80211_sub_if_data *sdata);
+void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
+void __ieee80211_run_pending_flush(struct ieee80211_local *local);
 
 #endif /* STA_INFO_H */
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 3abe194e4d55..45d59f19c29f 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -214,6 +214,59 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
 			   key->u.tkip.iv16, rc4key);
 }
 
+void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
+			struct sk_buff *skb, enum ieee80211_tkip_key_type type,
+			u8 *outkey)
+{
+	struct ieee80211_key *key = (struct ieee80211_key *)
+			container_of(keyconf, struct ieee80211_key, conf);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	u8 *data = (u8 *) hdr;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	int hdr_len = ieee80211_get_hdrlen(fc);
+	u8 *ta = hdr->addr2;
+	u16 iv16;
+	u32 iv32;
+
+	iv16 = data[hdr_len] << 8;
+	iv16 += data[hdr_len + 2];
+	iv32 = data[hdr_len + 4] +
+		(data[hdr_len + 5] >> 8) +
+		(data[hdr_len + 6] >> 16) +
+		(data[hdr_len + 7] >> 24);
+
+#ifdef CONFIG_TKIP_DEBUG
+	printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
+			iv16, iv32);
+
+	if (iv32 != key->u.tkip.iv32) {
+		printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
+			iv32, key->u.tkip.iv32);
+		printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
+			"fragmented packet\n");
+	}
+#endif /* CONFIG_TKIP_DEBUG */
+
+	/* Update the p1k only when the iv16 in the packet wraps around, this
+	 * might occur after the wrap around of iv16 in the key in case of
+	 * fragmented packets. */
+	if (iv16 == 0 || !key->u.tkip.tx_initialized) {
+		/* IV16 wrapped around - perform TKIP phase 1 */
+		tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
+			iv32, key->u.tkip.p1k);
+		key->u.tkip.tx_initialized = 1;
+	}
+
+	if (type == IEEE80211_TKIP_P1_KEY) {
+		memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5);
+		return;
+	}
+
+	tkip_mixing_phase2(key->u.tkip.p1k,
+		&key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],	iv16, outkey);
+}
+EXPORT_SYMBOL(ieee80211_get_tkip_key);
+
 /* Encrypt packet payload with TKIP using @key. @pos is a pointer to the
  * beginning of the buffer containing payload. This payload must include
  * headroom of eight octets for IV and Ext. IV and taildroom of four octets
@@ -238,7 +291,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
 int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 				struct ieee80211_key *key,
 				u8 *payload, size_t payload_len, u8 *ta,
-				int only_iv, int queue,
+				u8 *ra, int only_iv, int queue,
 				u32 *out_iv32, u16 *out_iv16)
 {
 	u32 iv32;
@@ -315,6 +368,19 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 			printk("\n");
 		}
 #endif /* CONFIG_TKIP_DEBUG */
+		if (key->local->ops->update_tkip_key &&
+			key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
+			u8 bcast[ETH_ALEN] =
+				{0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+			u8 *sta_addr = key->sta->addr;
+
+			if (is_multicast_ether_addr(ra))
+				sta_addr = bcast;
+
+			key->local->ops->update_tkip_key(
+				local_to_hw(key->local), &key->conf,
+				sta_addr, iv32, key->u.tkip.p1k_rx[queue]);
+		}
 	}
 
 	tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index 73d8ef2a93b0..ffaee3253e19 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -31,7 +31,7 @@ enum {
 int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
 				struct ieee80211_key *key,
 				u8 *payload, size_t payload_len, u8 *ta,
-				int only_iv, int queue,
+				u8 *ra, int only_iv, int queue,
 				u32 *out_iv32, u16 *out_iv16);
 
 #endif /* TKIP_H */
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 67b509edd431..80f4343a3007 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -26,6 +26,7 @@
 
 #include "ieee80211_i.h"
 #include "ieee80211_led.h"
+#include "mesh.h"
 #include "wep.h"
 #include "wpa.h"
 #include "wme.h"
@@ -86,15 +87,19 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title,
 }
 #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
 
-static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
+static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
 			      int next_frag_len)
 {
 	int rate, mrate, erp, dur, i;
-	struct ieee80211_rate *txrate = tx->u.tx.rate;
+	struct ieee80211_rate *txrate = tx->rate;
 	struct ieee80211_local *local = tx->local;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+	struct ieee80211_supported_band *sband;
 
-	erp = txrate->flags & IEEE80211_RATE_ERP;
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+	erp = 0;
+	if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
 	/*
 	 * data and mgmt (except PS Poll):
@@ -150,20 +155,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 	 * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
 	 */
 	rate = -1;
-	mrate = 10; /* use 1 Mbps if everything fails */
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *r = &mode->rates[i];
-		if (r->rate > txrate->rate)
-			break;
+	/* use lowest available if everything fails */
+	mrate = sband->bitrates[0].bitrate;
+	for (i = 0; i < sband->n_bitrates; i++) {
+		struct ieee80211_rate *r = &sband->bitrates[i];
 
-		if (IEEE80211_RATE_MODULATION(txrate->flags) !=
-		    IEEE80211_RATE_MODULATION(r->flags))
-			continue;
+		if (r->bitrate > txrate->bitrate)
+			break;
 
-		if (r->flags & IEEE80211_RATE_BASIC)
-			rate = r->rate;
-		else if (r->flags & IEEE80211_RATE_MANDATORY)
-			mrate = r->rate;
+		if (tx->sdata->basic_rates & BIT(i))
+			rate = r->bitrate;
+
+		switch (sband->band) {
+		case IEEE80211_BAND_2GHZ: {
+			u32 flag;
+			if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+				flag = IEEE80211_RATE_MANDATORY_G;
+			else
+				flag = IEEE80211_RATE_MANDATORY_B;
+			if (r->flags & flag)
+				mrate = r->bitrate;
+			break;
+		}
+		case IEEE80211_BAND_5GHZ:
+			if (r->flags & IEEE80211_RATE_MANDATORY_A)
+				mrate = r->bitrate;
+			break;
+		case IEEE80211_NUM_BANDS:
+			WARN_ON(1);
+			break;
+		}
 	}
 	if (rate == -1) {
 		/* No matching basic rate found; use highest suitable mandatory
@@ -184,7 +205,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
 		dur *= 2; /* ACK + SIFS */
 		/* next fragment */
 		dur += ieee80211_frame_duration(local, next_frag_len,
-				txrate->rate, erp,
+				txrate->bitrate, erp,
 				tx->sdata->bss_conf.use_short_preamble);
 	}
 
@@ -212,8 +233,8 @@ static int inline is_ieee80211_device(struct net_device *dev,
 
 /* tx handlers */
 
-static ieee80211_txrx_result
-ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx)
 {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 	struct sk_buff *skb = tx->skb;
@@ -221,20 +242,23 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 	u32 sta_flags;
 
-	if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED))
-		return TXRX_CONTINUE;
+	if (unlikely(tx->flags & IEEE80211_TX_INJECTED))
+		return TX_CONTINUE;
 
 	if (unlikely(tx->local->sta_sw_scanning) &&
 	    ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
 	     (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
-		return TXRX_DROP;
+		return TX_DROP;
 
-	if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)
-		return TXRX_CONTINUE;
+	if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT)
+		return TX_CONTINUE;
+
+	if (tx->flags & IEEE80211_TX_PS_BUFFERED)
+		return TX_CONTINUE;
 
 	sta_flags = tx->sta ? tx->sta->flags : 0;
 
-	if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) {
+	if (likely(tx->flags & IEEE80211_TX_UNICAST)) {
 		if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
 			     tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS &&
 			     (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
@@ -245,7 +269,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 			       tx->dev->name, print_mac(mac, hdr->addr1));
 #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
 			I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
-			return TXRX_DROP;
+			return TX_DROP;
 		}
 	} else {
 		if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
@@ -255,23 +279,23 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
 			 * No associated STAs - no need to send multicast
 			 * frames.
 			 */
-			return TXRX_DROP;
+			return TX_DROP;
 		}
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
 
 	if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
 		ieee80211_include_sequence(tx->sdata, hdr);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 /* This function is called whenever the AP is about to exceed the maximum limit
@@ -303,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 		}
 		total += skb_queue_len(&ap->ps_bc_buf);
 	}
-	rcu_read_unlock();
 
-	read_lock_bh(&local->sta_lock);
-	list_for_each_entry(sta, &local->sta_list, list) {
+	list_for_each_entry_rcu(sta, &local->sta_list, list) {
 		skb = skb_dequeue(&sta->ps_tx_buf);
 		if (skb) {
 			purged++;
@@ -314,15 +336,16 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
 		}
 		total += skb_queue_len(&sta->ps_tx_buf);
 	}
-	read_unlock_bh(&local->sta_lock);
+
+	rcu_read_unlock();
 
 	local->total_ps_buffered = total;
 	printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
 	       wiphy_name(local->hw.wiphy), purged);
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
 {
 	/*
 	 * broadcast/multicast frame
@@ -334,11 +357,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
 
 	/* not AP/IBSS or ordered frame */
 	if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	/* no stations in PS mode */
 	if (!atomic_read(&tx->sdata->bss->num_sta_ps))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	/* buffered in mac80211 */
 	if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) {
@@ -355,17 +378,17 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
 		} else
 			tx->local->total_ps_buffered++;
 		skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
-		return TXRX_QUEUED;
+		return TX_QUEUED;
 	}
 
 	/* buffered in hardware */
-	tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
+	tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
 	struct sta_info *sta = tx->sta;
 	DECLARE_MAC_BUF(mac);
@@ -373,9 +396,10 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 	if (unlikely(!sta ||
 		     ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
 		      (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
-	if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
+	if (unlikely((sta->flags & WLAN_STA_PS) &&
+		     !(sta->flags & WLAN_STA_PSPOLL))) {
 		struct ieee80211_tx_packet_data *pkt_data;
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 		printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries "
@@ -383,7 +407,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 		       print_mac(mac, sta->addr), sta->aid,
 		       skb_queue_len(&sta->ps_tx_buf));
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-		sta->flags |= WLAN_STA_TIM;
 		if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
 			purge_old_ps_buffers(tx->local);
 		if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
@@ -396,18 +419,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 			dev_kfree_skb(old);
 		} else
 			tx->local->total_ps_buffered++;
+
 		/* Queue frame to be sent after STA sends an PS Poll frame */
-		if (skb_queue_empty(&sta->ps_tx_buf)) {
-			if (tx->local->ops->set_tim)
-				tx->local->ops->set_tim(local_to_hw(tx->local),
-						       sta->aid, 1);
-			if (tx->sdata->bss)
-				bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
-		}
+		if (skb_queue_empty(&sta->ps_tx_buf))
+			sta_info_set_tim_bit(sta);
+
 		pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
 		pkt_data->jiffies = jiffies;
 		skb_queue_tail(&sta->ps_tx_buf, tx->skb);
-		return TXRX_QUEUED;
+		return TX_QUEUED;
 	}
 #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
 	else if (unlikely(sta->flags & WLAN_STA_PS)) {
@@ -416,40 +436,40 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
 		       print_mac(mac, sta->addr));
 	}
 #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
-	sta->pspoll = 0;
+	sta->flags &= ~WLAN_STA_PSPOLL;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
 {
-	if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED))
-		return TXRX_CONTINUE;
+	if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
+		return TX_CONTINUE;
 
-	if (tx->flags & IEEE80211_TXRXD_TXUNICAST)
+	if (tx->flags & IEEE80211_TX_UNICAST)
 		return ieee80211_tx_h_unicast_ps_buf(tx);
 	else
 		return ieee80211_tx_h_multicast_ps_buf(tx);
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_key *key;
 	u16 fc = tx->fc;
 
-	if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+	if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
 		tx->key = NULL;
 	else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
 		tx->key = key;
 	else if ((key = rcu_dereference(tx->sdata->default_key)))
 		tx->key = key;
 	else if (tx->sdata->drop_unencrypted &&
-		 !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
-		 !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) {
+		 !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) &&
+		 !(tx->flags & IEEE80211_TX_INJECTED)) {
 		I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
-		return TXRX_DROP;
+		return TX_DROP;
 	} else
 		tx->key = NULL;
 
@@ -476,13 +496,13 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
 	}
 
 	if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-		tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+		tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
 	size_t hdrlen, per_fragm, num_fragm, payload_len, left;
@@ -492,8 +512,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	u8 *pos;
 	int frag_threshold = tx->local->fragmentation_threshold;
 
-	if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED))
-		return TXRX_CONTINUE;
+	if (!(tx->flags & IEEE80211_TX_FRAGMENTED))
+		return TX_CONTINUE;
 
 	first = tx->skb;
 
@@ -544,10 +564,10 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 	}
 	skb_trim(first, hdrlen + per_fragm);
 
-	tx->u.tx.num_extra_frag = num_fragm - 1;
-	tx->u.tx.extra_frag = frags;
+	tx->num_extra_frag = num_fragm - 1;
+	tx->extra_frag = frags;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 
  fail:
 	printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
@@ -558,14 +578,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
 		kfree(frags);
 	}
 	I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
-	return TXRX_DROP;
+	return TX_DROP;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx)
 {
 	if (!tx->key)
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	switch (tx->key->conf.alg) {
 	case ALG_WEP:
@@ -578,59 +598,60 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 
 	/* not reached */
 	WARN_ON(1);
-	return TXRX_DROP;
+	return TX_DROP;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 {
 	struct rate_selection rsel;
+	struct ieee80211_supported_band *sband;
+
+	sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
 
-	if (likely(!tx->u.tx.rate)) {
-		rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel);
-		tx->u.tx.rate = rsel.rate;
-		if (unlikely(rsel.probe != NULL)) {
-			tx->u.tx.control->flags |=
+	if (likely(!tx->rate)) {
+		rate_control_get_rate(tx->dev, sband, tx->skb, &rsel);
+		tx->rate = rsel.rate;
+		if (unlikely(rsel.probe)) {
+			tx->control->flags |=
 				IEEE80211_TXCTL_RATE_CTRL_PROBE;
-			tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
-			tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
-			tx->u.tx.rate = rsel.probe;
+			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+			tx->control->alt_retry_rate = tx->rate;
+			tx->rate = rsel.probe;
 		} else
-			tx->u.tx.control->alt_retry_rate = -1;
+			tx->control->alt_retry_rate = NULL;
 
-		if (!tx->u.tx.rate)
-			return TXRX_DROP;
+		if (!tx->rate)
+			return TX_DROP;
 	} else
-		tx->u.tx.control->alt_retry_rate = -1;
+		tx->control->alt_retry_rate = NULL;
 
-	if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
-	    tx->sdata->bss_conf.use_cts_prot &&
-	    (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) {
-		tx->u.tx.last_frag_rate = tx->u.tx.rate;
+	if (tx->sdata->bss_conf.use_cts_prot &&
+	    (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) {
+		tx->last_frag_rate = tx->rate;
 		if (rsel.probe)
-			tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+			tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
 		else
-			tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
-		tx->u.tx.rate = rsel.nonerp;
-		tx->u.tx.control->rate = rsel.nonerp;
-		tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+			tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
+		tx->rate = rsel.nonerp;
+		tx->control->tx_rate = rsel.nonerp;
+		tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
 	} else {
-		tx->u.tx.last_frag_rate = tx->u.tx.rate;
-		tx->u.tx.control->rate = tx->u.tx.rate;
+		tx->last_frag_rate = tx->rate;
+		tx->control->tx_rate = tx->rate;
 	}
-	tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+	tx->control->tx_rate = tx->rate;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
 	u16 fc = le16_to_cpu(hdr->frame_control);
 	u16 dur;
-	struct ieee80211_tx_control *control = tx->u.tx.control;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+	struct ieee80211_tx_control *control = tx->control;
 
 	if (!control->retry_limit) {
 		if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -652,20 +673,20 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 		}
 	}
 
-	if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
+	if (tx->flags & IEEE80211_TX_FRAGMENTED) {
 		/* Do not use multiple retry rates when sending fragmented
 		 * frames.
 		 * TODO: The last fragment could still use multiple retry
 		 * rates. */
-		control->alt_retry_rate = -1;
+		control->alt_retry_rate = NULL;
 	}
 
 	/* Use CTS protection for unicast frames sent using extended rates if
 	 * there are associated non-ERP stations and RTS/CTS is not configured
 	 * for the frame. */
-	if (mode->mode == MODE_IEEE80211G &&
-	    (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
-	    (tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+	if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
+	    (tx->rate->flags & IEEE80211_RATE_ERP_G) &&
+	    (tx->flags & IEEE80211_TX_UNICAST) &&
 	    tx->sdata->bss_conf.use_cts_prot &&
 	    !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
 		control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
@@ -674,62 +695,76 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
 	 * short preambles at the selected rate and short preambles are
 	 * available on the network at the current point in time. */
 	if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) &&
-	    (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+	    (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
 	    tx->sdata->bss_conf.use_short_preamble &&
 	    (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
-		tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+		tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 	}
 
 	/* Setup duration field for the first fragment of the frame. Duration
 	 * for remaining fragments will be updated when they are being sent
 	 * to low-level driver in ieee80211_tx(). */
 	dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
-				 (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ?
-				 tx->u.tx.extra_frag[0]->len : 0);
+				 (tx->flags & IEEE80211_TX_FRAGMENTED) ?
+				 tx->extra_frag[0]->len : 0);
 	hdr->duration_id = cpu_to_le16(dur);
 
 	if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
 	    (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
-		struct ieee80211_rate *rate;
+		struct ieee80211_supported_band *sband;
+		struct ieee80211_rate *rate, *baserate;
+		int idx;
+
+		sband = tx->local->hw.wiphy->bands[
+				tx->local->hw.conf.channel->band];
 
 		/* Do not use multiple retry rates when using RTS/CTS */
-		control->alt_retry_rate = -1;
+		control->alt_retry_rate = NULL;
 
 		/* Use min(data rate, max base rate) as CTS/RTS rate */
-		rate = tx->u.tx.rate;
-		while (rate > mode->rates &&
-		       !(rate->flags & IEEE80211_RATE_BASIC))
-			rate--;
+		rate = tx->rate;
+		baserate = NULL;
+
+		for (idx = 0; idx < sband->n_bitrates; idx++) {
+			if (sband->bitrates[idx].bitrate > rate->bitrate)
+				continue;
+			if (tx->sdata->basic_rates & BIT(idx) &&
+			    (!baserate ||
+			     (baserate->bitrate < sband->bitrates[idx].bitrate)))
+				baserate = &sband->bitrates[idx];
+		}
 
-		control->rts_cts_rate = rate->val;
-		control->rts_rate = rate;
+		if (baserate)
+			control->rts_cts_rate = baserate;
+		else
+			control->rts_cts_rate = &sband->bitrates[0];
 	}
 
 	if (tx->sta) {
 		tx->sta->tx_packets++;
 		tx->sta->tx_fragments++;
 		tx->sta->tx_bytes += tx->skb->len;
-		if (tx->u.tx.extra_frag) {
+		if (tx->extra_frag) {
 			int i;
-			tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
-			for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+			tx->sta->tx_fragments += tx->num_extra_frag;
+			for (i = 0; i < tx->num_extra_frag; i++) {
 				tx->sta->tx_bytes +=
-					tx->u.tx.extra_frag[i]->len;
+					tx->extra_frag[i]->len;
 			}
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-static ieee80211_txrx_result
-ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+static ieee80211_tx_result
+ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_local *local = tx->local;
-	struct ieee80211_hw_mode *mode = tx->u.tx.mode;
 	struct sk_buff *skb = tx->skb;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	u32 load = 0, hdrtime;
+	struct ieee80211_rate *rate = tx->rate;
 
 	/* TODO: this could be part of tx_status handling, so that the number
 	 * of retries would be known; TX rate should in that case be stored
@@ -740,9 +775,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 	/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
 	 * 1 usec = 1/8 * (1080 / 10) = 13.5 */
 
-	if (mode->mode == MODE_IEEE80211A ||
-	    (mode->mode == MODE_IEEE80211G &&
-	     tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+	if (tx->channel->band == IEEE80211_BAND_5GHZ ||
+	    (tx->channel->band == IEEE80211_BAND_2GHZ &&
+	     rate->flags & IEEE80211_RATE_ERP_G))
 		hdrtime = CHAN_UTIL_HDR_SHORT;
 	else
 		hdrtime = CHAN_UTIL_HDR_LONG;
@@ -751,19 +786,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 	if (!is_multicast_ether_addr(hdr->addr1))
 		load += hdrtime;
 
-	if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+	if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
 		load += 2 * hdrtime;
-	else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+	else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		load += hdrtime;
 
-	load += skb->len * tx->u.tx.rate->rate_inv;
+	/* TODO: optimise again */
+	load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate;
 
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+		for (i = 0; i < tx->num_extra_frag; i++) {
 			load += 2 * hdrtime;
-			load += tx->u.tx.extra_frag[i]->len *
-				tx->u.tx.rate->rate;
+			load += tx->extra_frag[i]->len *
+				tx->rate->bitrate;
 		}
 	}
 
@@ -774,13 +810,12 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
 		tx->sta->channel_use_raw += load;
 	tx->sdata->channel_use_raw += load;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
-/* TODO: implement register/unregister functions for adding TX/RX handlers
- * into ordered list */
 
-ieee80211_tx_handler ieee80211_tx_handlers[] =
+typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *);
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
 {
 	ieee80211_tx_h_check_assoc,
 	ieee80211_tx_h_sequence,
@@ -801,8 +836,8 @@ ieee80211_tx_handler ieee80211_tx_handlers[] =
  * deal with packet injection down monitor interface
  * with Radiotap Header -- only called for monitor mode interface
  */
-static ieee80211_txrx_result
-__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
+static ieee80211_tx_result
+__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
 			      struct sk_buff *skb)
 {
 	/*
@@ -816,13 +851,15 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	struct ieee80211_radiotap_iterator iterator;
 	struct ieee80211_radiotap_header *rthdr =
 		(struct ieee80211_radiotap_header *) skb->data;
-	struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+	struct ieee80211_supported_band *sband;
 	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
-	struct ieee80211_tx_control *control = tx->u.tx.control;
+	struct ieee80211_tx_control *control = tx->control;
+
+	sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band];
 
 	control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
-	tx->flags |= IEEE80211_TXRXD_TX_INJECTED;
-	tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+	tx->flags |= IEEE80211_TX_INJECTED;
+	tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 
 	/*
 	 * for every radiotap entry that is present
@@ -852,11 +889,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 			 * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
 			 */
 			target_rate = (*iterator.this_arg) * 5;
-			for (i = 0; i < mode->num_rates; i++) {
-				struct ieee80211_rate *r = &mode->rates[i];
+			for (i = 0; i < sband->n_bitrates; i++) {
+				struct ieee80211_rate *r;
+
+				r = &sband->bitrates[i];
 
-				if (r->rate == target_rate) {
-					tx->u.tx.rate = r;
+				if (r->bitrate == target_rate) {
+					tx->rate = r;
 					break;
 				}
 			}
@@ -870,9 +909,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 			control->antenna_sel_tx = (*iterator.this_arg) + 1;
 			break;
 
+#if 0
 		case IEEE80211_RADIOTAP_DBM_TX_POWER:
 			control->power_level = *iterator.this_arg;
 			break;
+#endif
 
 		case IEEE80211_RADIOTAP_FLAGS:
 			if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
@@ -884,7 +925,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 				 * on transmission
 				 */
 				if (skb->len < (iterator.max_length + FCS_LEN))
-					return TXRX_DROP;
+					return TX_DROP;
 
 				skb_trim(skb, skb->len - FCS_LEN);
 			}
@@ -892,7 +933,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 				control->flags &=
 					~IEEE80211_TXCTL_DO_NOT_ENCRYPT;
 			if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
-				tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+				tx->flags |= IEEE80211_TX_FRAGMENTED;
 			break;
 
 		/*
@@ -907,7 +948,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	}
 
 	if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
-		return TXRX_DROP;
+		return TX_DROP;
 
 	/*
 	 * remove the radiotap header
@@ -916,14 +957,14 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx,
 	 */
 	skb_pull(skb, iterator.max_length);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 /*
  * initialises @tx
  */
-static ieee80211_txrx_result
-__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+static ieee80211_tx_result
+__ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 		       struct sk_buff *skb,
 		       struct net_device *dev,
 		       struct ieee80211_tx_control *control)
@@ -939,18 +980,18 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	tx->dev = dev; /* use original interface */
 	tx->local = local;
 	tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	tx->u.tx.control = control;
+	tx->control = control;
 	/*
 	 * Set this flag (used below to indicate "automatic fragmentation"),
 	 * it will be cleared/left by radiotap as desired.
 	 */
-	tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+	tx->flags |= IEEE80211_TX_FRAGMENTED;
 
 	/* process and remove the injection radiotap header */
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) {
-		if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP)
-			return TXRX_DROP;
+		if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+			return TX_DROP;
 
 		/*
 		 * __ieee80211_parse_tx_radiotap has now removed
@@ -965,27 +1006,27 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	tx->fc = le16_to_cpu(hdr->frame_control);
 
 	if (is_multicast_ether_addr(hdr->addr1)) {
-		tx->flags &= ~IEEE80211_TXRXD_TXUNICAST;
+		tx->flags &= ~IEEE80211_TX_UNICAST;
 		control->flags |= IEEE80211_TXCTL_NO_ACK;
 	} else {
-		tx->flags |= IEEE80211_TXRXD_TXUNICAST;
+		tx->flags |= IEEE80211_TX_UNICAST;
 		control->flags &= ~IEEE80211_TXCTL_NO_ACK;
 	}
 
-	if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) {
-		if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) &&
+	if (tx->flags & IEEE80211_TX_FRAGMENTED) {
+		if ((tx->flags & IEEE80211_TX_UNICAST) &&
 		    skb->len + FCS_LEN > local->fragmentation_threshold &&
 		    !local->ops->set_frag_threshold)
-			tx->flags |= IEEE80211_TXRXD_FRAGMENTED;
+			tx->flags |= IEEE80211_TX_FRAGMENTED;
 		else
-			tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED;
+			tx->flags &= ~IEEE80211_TX_FRAGMENTED;
 	}
 
 	if (!tx->sta)
-		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
-	else if (tx->sta->clear_dst_mask) {
-		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
-		tx->sta->clear_dst_mask = 0;
+		control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+	else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) {
+		control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
+		tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT;
 	}
 
 	hdrlen = ieee80211_get_hdrlen(tx->fc);
@@ -995,13 +1036,13 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 	}
 	control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 /*
  * NB: @tx is uninitialised when passed in here
  */
-static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 				struct sk_buff *skb,
 				struct net_device *mdev,
 				struct ieee80211_tx_control *control)
@@ -1024,9 +1065,9 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
 }
 
 static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
-			  struct ieee80211_txrx_data *tx)
+			  struct ieee80211_tx_data *tx)
 {
-	struct ieee80211_tx_control *control = tx->u.tx.control;
+	struct ieee80211_tx_control *control = tx->control;
 	int ret, i;
 
 	if (!ieee80211_qdisc_installed(local->mdev) &&
@@ -1043,20 +1084,20 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 		local->mdev->trans_start = jiffies;
 		ieee80211_led_tx(local, 1);
 	}
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
 				    IEEE80211_TXCTL_USE_CTS_PROTECT |
-				    IEEE80211_TXCTL_CLEAR_DST_MASK |
+				    IEEE80211_TXCTL_CLEAR_PS_FILT |
 				    IEEE80211_TXCTL_FIRST_FRAGMENT);
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			if (!tx->u.tx.extra_frag[i])
+		for (i = 0; i < tx->num_extra_frag; i++) {
+			if (!tx->extra_frag[i])
 				continue;
 			if (__ieee80211_queue_stopped(local, control->queue))
 				return IEEE80211_TX_FRAG_AGAIN;
-			if (i == tx->u.tx.num_extra_frag) {
-				control->tx_rate = tx->u.tx.last_frag_hwrate;
-				control->rate = tx->u.tx.last_frag_rate;
-				if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG)
+			if (i == tx->num_extra_frag) {
+				control->tx_rate = tx->last_frag_rate;
+
+				if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
 					control->flags |=
 						IEEE80211_TXCTL_RATE_CTRL_PROBE;
 				else
@@ -1066,18 +1107,18 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 
 			ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
 					     "TX to low-level driver",
-					     tx->u.tx.extra_frag[i]);
+					     tx->extra_frag[i]);
 			ret = local->ops->tx(local_to_hw(local),
-					    tx->u.tx.extra_frag[i],
+					    tx->extra_frag[i],
 					    control);
 			if (ret)
 				return IEEE80211_TX_FRAG_AGAIN;
 			local->mdev->trans_start = jiffies;
 			ieee80211_led_tx(local, 1);
-			tx->u.tx.extra_frag[i] = NULL;
+			tx->extra_frag[i] = NULL;
 		}
-		kfree(tx->u.tx.extra_frag);
-		tx->u.tx.extra_frag = NULL;
+		kfree(tx->extra_frag);
+		tx->extra_frag = NULL;
 	}
 	return IEEE80211_TX_OK;
 }
@@ -1088,8 +1129,8 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
 	struct sta_info *sta;
 	ieee80211_tx_handler *handler;
-	struct ieee80211_txrx_data tx;
-	ieee80211_txrx_result res = TXRX_DROP, res_prepare;
+	struct ieee80211_tx_data tx;
+	ieee80211_tx_result res = TX_DROP, res_prepare;
 	int ret, i;
 
 	WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1099,59 +1140,52 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
 		return 0;
 	}
 
+	rcu_read_lock();
+
 	/* initialises tx */
 	res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
 
-	if (res_prepare == TXRX_DROP) {
+	if (res_prepare == TX_DROP) {
 		dev_kfree_skb(skb);
+		rcu_read_unlock();
 		return 0;
 	}
 
-	/*
-	 * key references are protected using RCU and this requires that
-	 * we are in a read-site RCU section during receive processing
-	 */
-	rcu_read_lock();
-
 	sta = tx.sta;
-	tx.u.tx.mode = local->hw.conf.mode;
+	tx.channel = local->hw.conf.channel;
 
-	for (handler = local->tx_handlers; *handler != NULL;
+	for (handler = ieee80211_tx_handlers; *handler != NULL;
 	     handler++) {
 		res = (*handler)(&tx);
-		if (res != TXRX_CONTINUE)
+		if (res != TX_CONTINUE)
 			break;
 	}
 
 	skb = tx.skb; /* handlers are allowed to change skb */
 
-	if (sta)
-		sta_info_put(sta);
-
-	if (unlikely(res == TXRX_DROP)) {
+	if (unlikely(res == TX_DROP)) {
 		I802_DEBUG_INC(local->tx_handlers_drop);
 		goto drop;
 	}
 
-	if (unlikely(res == TXRX_QUEUED)) {
+	if (unlikely(res == TX_QUEUED)) {
 		I802_DEBUG_INC(local->tx_handlers_queued);
 		rcu_read_unlock();
 		return 0;
 	}
 
-	if (tx.u.tx.extra_frag) {
-		for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
+	if (tx.extra_frag) {
+		for (i = 0; i < tx.num_extra_frag; i++) {
 			int next_len, dur;
 			struct ieee80211_hdr *hdr =
 				(struct ieee80211_hdr *)
-				tx.u.tx.extra_frag[i]->data;
+				tx.extra_frag[i]->data;
 
-			if (i + 1 < tx.u.tx.num_extra_frag) {
-				next_len = tx.u.tx.extra_frag[i + 1]->len;
+			if (i + 1 < tx.num_extra_frag) {
+				next_len = tx.extra_frag[i + 1]->len;
 			} else {
 				next_len = 0;
-				tx.u.tx.rate = tx.u.tx.last_frag_rate;
-				tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
+				tx.rate = tx.last_frag_rate;
 			}
 			dur = ieee80211_duration(&tx, 0, next_len);
 			hdr->duration_id = cpu_to_le16(dur);
@@ -1186,12 +1220,11 @@ retry:
 		memcpy(&store->control, control,
 		       sizeof(struct ieee80211_tx_control));
 		store->skb = skb;
-		store->extra_frag = tx.u.tx.extra_frag;
-		store->num_extra_frag = tx.u.tx.num_extra_frag;
-		store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
-		store->last_frag_rate = tx.u.tx.last_frag_rate;
+		store->extra_frag = tx.extra_frag;
+		store->num_extra_frag = tx.num_extra_frag;
+		store->last_frag_rate = tx.last_frag_rate;
 		store->last_frag_rate_ctrl_probe =
-			!!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
+			!!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
 	}
 	rcu_read_unlock();
 	return 0;
@@ -1199,10 +1232,10 @@ retry:
  drop:
 	if (skb)
 		dev_kfree_skb(skb);
-	for (i = 0; i < tx.u.tx.num_extra_frag; i++)
-		if (tx.u.tx.extra_frag[i])
-			dev_kfree_skb(tx.u.tx.extra_frag[i]);
-	kfree(tx.u.tx.extra_frag);
+	for (i = 0; i < tx.num_extra_frag; i++)
+		if (tx.extra_frag[i])
+			dev_kfree_skb(tx.extra_frag[i]);
+	kfree(tx.extra_frag);
 	rcu_read_unlock();
 	return 0;
 }
@@ -1260,6 +1293,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb,
 		control.flags |= IEEE80211_TXCTL_REQUEUE;
 	if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME)
 		control.flags |= IEEE80211_TXCTL_EAPOL_FRAME;
+	if (pkt_data->flags & IEEE80211_TXPD_AMPDU)
+		control.flags |= IEEE80211_TXCTL_AMPDU;
 	control.queue = pkt_data->queue;
 
 	ret = ieee80211_tx(odev, skb, &control);
@@ -1346,8 +1381,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	struct ieee80211_tx_packet_data *pkt_data;
 	struct ieee80211_sub_if_data *sdata;
 	int ret = 1, head_need;
-	u16 ethertype, hdrlen, fc;
+	u16 ethertype, hdrlen,  meshhdrlen = 0, fc;
 	struct ieee80211_hdr hdr;
+	struct ieee80211s_hdr mesh_hdr;
 	const u8 *encaps_data;
 	int encaps_len, skip_header_bytes;
 	int nh_pos, h_pos;
@@ -1389,6 +1425,37 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
 		hdrlen = 30;
 		break;
+#ifdef CONFIG_MAC80211_MESH
+	case IEEE80211_IF_TYPE_MESH_POINT:
+		fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+		/* RA TA DA SA */
+		if (is_multicast_ether_addr(skb->data))
+			memcpy(hdr.addr1, skb->data, ETH_ALEN);
+		else if (mesh_nexthop_lookup(hdr.addr1, skb, dev))
+				return 0;
+		memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+		memcpy(hdr.addr3, skb->data, ETH_ALEN);
+		memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+		if (skb->pkt_type == PACKET_OTHERHOST) {
+			/* Forwarded frame, keep mesh ttl and seqnum */
+			struct ieee80211s_hdr *prev_meshhdr;
+			prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb);
+			meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr);
+			memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen);
+			sdata->u.sta.mshstats.fwded_frames++;
+		} else {
+			if (!sdata->u.sta.mshcfg.dot11MeshTTL) {
+				/* Do not send frames with mesh_ttl == 0 */
+				sdata->u.sta.mshstats.dropped_frames_ttl++;
+				ret = 0;
+				goto fail;
+			}
+			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+							       sdata);
+		}
+		hdrlen = 30;
+		break;
+#endif
 	case IEEE80211_IF_TYPE_STA:
 		fc |= IEEE80211_FCTL_TODS;
 		/* BSSID SA DA */
@@ -1409,10 +1476,17 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		goto fail;
 	}
 
-	sta = sta_info_get(local, hdr.addr1);
-	if (sta) {
-		sta_flags = sta->flags;
-		sta_info_put(sta);
+	/*
+	 * There's no need to try to look up the destination
+	 * if it is a multicast address (which can only happen
+	 * in AP mode)
+	 */
+	if (!is_multicast_ether_addr(hdr.addr1)) {
+		rcu_read_lock();
+		sta = sta_info_get(local, hdr.addr1);
+		if (sta)
+			sta_flags = sta->flags;
+		rcu_read_unlock();
 	}
 
 	/* receiver is QoS enabled, use a QoS type frame */
@@ -1422,12 +1496,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	}
 
 	/*
-	 * If port access control is enabled, drop frames to unauthorised
-	 * stations unless they are EAPOL frames from the local station.
+	 * Drop unicast frames to unauthorised stations unless they are
+	 * EAPOL frames from the local station.
 	 */
-	if (unlikely(sdata->ieee802_1x_pac &&
-		     !(sta_flags & WLAN_STA_AUTHORIZED) &&
-		     !(ethertype == ETH_P_PAE &&
+	if (unlikely(!is_multicast_ether_addr(hdr.addr1) &&
+		      !(sta_flags & WLAN_STA_AUTHORIZED) &&
+		      !(ethertype == ETH_P_PAE &&
 		       compare_ether_addr(dev->dev_addr,
 					  skb->data + ETH_ALEN) == 0))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -1480,7 +1554,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 	 * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
 	 * alloc_skb() (net/core/skbuff.c)
 	 */
-	head_need = hdrlen + encaps_len + local->tx_headroom;
+	head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom;
 	head_need -= skb_headroom(skb);
 
 	/* We are going to modify skb data, so make a copy of it if happens to
@@ -1514,6 +1588,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		h_pos += encaps_len;
 	}
 
+	if (meshhdrlen > 0) {
+		memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
+		nh_pos += meshhdrlen;
+		h_pos += meshhdrlen;
+	}
+
 	if (fc & IEEE80211_STYPE_QOS_DATA) {
 		__le16 *qos_control;
 
@@ -1583,7 +1663,7 @@ void ieee80211_tx_pending(unsigned long data)
 	struct ieee80211_local *local = (struct ieee80211_local *)data;
 	struct net_device *dev = local->mdev;
 	struct ieee80211_tx_stored_packet *store;
-	struct ieee80211_txrx_data tx;
+	struct ieee80211_tx_data tx;
 	int i, ret, reschedule = 0;
 
 	netif_tx_lock_bh(dev);
@@ -1595,14 +1675,13 @@ void ieee80211_tx_pending(unsigned long data)
 			continue;
 		}
 		store = &local->pending_packet[i];
-		tx.u.tx.control = &store->control;
-		tx.u.tx.extra_frag = store->extra_frag;
-		tx.u.tx.num_extra_frag = store->num_extra_frag;
-		tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
-		tx.u.tx.last_frag_rate = store->last_frag_rate;
+		tx.control = &store->control;
+		tx.extra_frag = store->extra_frag;
+		tx.num_extra_frag = store->num_extra_frag;
+		tx.last_frag_rate = store->last_frag_rate;
 		tx.flags = 0;
 		if (store->last_frag_rate_ctrl_probe)
-			tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
+			tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
 		ret = __ieee80211_tx(local, store->skb, &tx);
 		if (ret) {
 			if (ret == IEEE80211_TX_FRAG_AGAIN)
@@ -1636,7 +1715,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 
 	/* Generate bitmap for TIM only if there are any STAs in power save
 	 * mode. */
-	read_lock_bh(&local->sta_lock);
 	if (atomic_read(&bss->num_sta_ps) > 0)
 		/* in the hope that this is faster than
 		 * checking byte-for-byte */
@@ -1687,7 +1765,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
 		*pos++ = aid0; /* Bitmap control */
 		*pos++ = 0; /* Part Virt Bitmap */
 	}
-	read_unlock_bh(&local->sta_lock);
 }
 
 struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
@@ -1701,16 +1778,96 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 	struct ieee80211_if_ap *ap = NULL;
 	struct rate_selection rsel;
 	struct beacon_data *beacon;
+	struct ieee80211_supported_band *sband;
+	struct ieee80211_mgmt *mgmt;
+	int *num_beacons;
+	bool err = true;
+	u8 *pos;
+
+	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	rcu_read_lock();
 
 	sdata = vif_to_sdata(vif);
 	bdev = sdata->dev;
-	ap = &sdata->u.ap;
 
-	beacon = rcu_dereference(ap->beacon);
+	if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+		ap = &sdata->u.ap;
+		beacon = rcu_dereference(ap->beacon);
+		if (ap && beacon) {
+			/*
+			 * headroom, head length,
+			 * tail length and maximum TIM length
+			 */
+			skb = dev_alloc_skb(local->tx_headroom +
+					    beacon->head_len +
+					    beacon->tail_len + 256);
+			if (!skb)
+				goto out;
+
+			skb_reserve(skb, local->tx_headroom);
+			memcpy(skb_put(skb, beacon->head_len), beacon->head,
+			       beacon->head_len);
+
+			ieee80211_include_sequence(sdata,
+					(struct ieee80211_hdr *)skb->data);
+
+			/*
+			 * Not very nice, but we want to allow the driver to call
+			 * ieee80211_beacon_get() as a response to the set_tim()
+			 * callback. That, however, is already invoked under the
+			 * sta_lock to guarantee consistent and race-free update
+			 * of the tim bitmap in mac80211 and the driver.
+			 */
+			if (local->tim_in_locked_section) {
+				ieee80211_beacon_add_tim(local, ap, skb, beacon);
+			} else {
+				unsigned long flags;
+
+				spin_lock_irqsave(&local->sta_lock, flags);
+				ieee80211_beacon_add_tim(local, ap, skb, beacon);
+				spin_unlock_irqrestore(&local->sta_lock, flags);
+			}
+
+			if (beacon->tail)
+				memcpy(skb_put(skb, beacon->tail_len),
+				       beacon->tail, beacon->tail_len);
 
-	if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) {
+			num_beacons = &ap->num_beacons;
+
+			err = false;
+		}
+	} else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+		/* headroom, head length, tail length and maximum TIM length */
+		skb = dev_alloc_skb(local->tx_headroom + 400);
+		if (!skb)
+			goto out;
+
+		skb_reserve(skb, local->hw.extra_tx_headroom);
+		mgmt = (struct ieee80211_mgmt *)
+			skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+		memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+		mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+						   IEEE80211_STYPE_BEACON);
+		memset(mgmt->da, 0xff, ETH_ALEN);
+		memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+		/* BSSID is left zeroed, wildcard value */
+		mgmt->u.beacon.beacon_int =
+			cpu_to_le16(local->hw.conf.beacon_int);
+		mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */
+
+		pos = skb_put(skb, 2);
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = 0x0;
+
+		mesh_mgmt_ies_add(skb, sdata->dev);
+
+		num_beacons = &sdata->u.sta.num_beacons;
+
+		err = false;
+	}
+
+	if (err) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
 		if (net_ratelimit())
 			printk(KERN_DEBUG "no beacon data avail for %s\n",
@@ -1720,27 +1877,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 		goto out;
 	}
 
-	/* headroom, head length, tail length and maximum TIM length */
-	skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
-			    beacon->tail_len + 256);
-	if (!skb)
-		goto out;
-
-	skb_reserve(skb, local->tx_headroom);
-	memcpy(skb_put(skb, beacon->head_len), beacon->head,
-	       beacon->head_len);
-
-	ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
-
-	ieee80211_beacon_add_tim(local, ap, skb, beacon);
-
-	if (beacon->tail)
-		memcpy(skb_put(skb, beacon->tail_len), beacon->tail,
-		       beacon->tail_len);
-
 	if (control) {
-		rate_control_get_rate(local->mdev, local->oper_hw_mode, skb,
-				      &rsel);
+		rate_control_get_rate(local->mdev, sband, skb, &rsel);
 		if (!rsel.rate) {
 			if (net_ratelimit()) {
 				printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
@@ -1753,20 +1891,17 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
 		}
 
 		control->vif = vif;
-		control->tx_rate =
-			(sdata->bss_conf.use_short_preamble &&
-			(rsel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			rsel.rate->val2 : rsel.rate->val;
+		control->tx_rate = rsel.rate;
+		if (sdata->bss_conf.use_short_preamble &&
+		    rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+			control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE;
 		control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
-		control->power_level = local->hw.conf.power_level;
 		control->flags |= IEEE80211_TXCTL_NO_ACK;
 		control->retry_limit = 1;
-		control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+		control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT;
 	}
-
-	ap->num_beacons++;
-
- out:
+	(*num_beacons)++;
+out:
 	rcu_read_unlock();
 	return skb;
 }
@@ -1814,8 +1949,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 	struct sk_buff *skb;
 	struct sta_info *sta;
 	ieee80211_tx_handler *handler;
-	struct ieee80211_txrx_data tx;
-	ieee80211_txrx_result res = TXRX_DROP;
+	struct ieee80211_tx_data tx;
+	ieee80211_tx_result res = TX_DROP;
 	struct net_device *bdev;
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_if_ap *bss = NULL;
@@ -1836,7 +1971,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 		rcu_read_unlock();
 		return NULL;
 	}
-	rcu_read_unlock();
 
 	if (bss->dtim_count != 0)
 		return NULL; /* send buffered bc/mc only after DTIM beacon */
@@ -1862,27 +1996,26 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
 		dev_kfree_skb_any(skb);
 	}
 	sta = tx.sta;
-	tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED;
-	tx.u.tx.mode = local->hw.conf.mode;
+	tx.flags |= IEEE80211_TX_PS_BUFFERED;
+	tx.channel = local->hw.conf.channel;
 
-	for (handler = local->tx_handlers; *handler != NULL; handler++) {
+	for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) {
 		res = (*handler)(&tx);
-		if (res == TXRX_DROP || res == TXRX_QUEUED)
+		if (res == TX_DROP || res == TX_QUEUED)
 			break;
 	}
 	skb = tx.skb; /* handlers are allowed to change skb */
 
-	if (res == TXRX_DROP) {
+	if (res == TX_DROP) {
 		I802_DEBUG_INC(local->tx_handlers_drop);
 		dev_kfree_skb(skb);
 		skb = NULL;
-	} else if (res == TXRX_QUEUED) {
+	} else if (res == TX_QUEUED) {
 		I802_DEBUG_INC(local->tx_handlers_queued);
 		skb = NULL;
 	}
 
-	if (sta)
-		sta_info_put(sta);
+	rcu_read_unlock();
 
 	return skb;
 }
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5e631ce98d7e..57c404f3f6d0 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -26,6 +26,7 @@
 
 #include "ieee80211_i.h"
 #include "ieee80211_rate.h"
+#include "mesh.h"
 #include "wme.h"
 
 /* privid for wiphys to determine whether they belong to us or not */
@@ -41,92 +42,6 @@ const unsigned char bridge_tunnel_header[] =
 	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 
 
-static int rate_list_match(const int *rate_list, int rate)
-{
-	int i;
-
-	if (!rate_list)
-		return 0;
-
-	for (i = 0; rate_list[i] >= 0; i++)
-		if (rate_list[i] == rate)
-			return 1;
-
-	return 0;
-}
-
-void ieee80211_prepare_rates(struct ieee80211_local *local,
-			     struct ieee80211_hw_mode *mode)
-{
-	int i;
-
-	for (i = 0; i < mode->num_rates; i++) {
-		struct ieee80211_rate *rate = &mode->rates[i];
-
-		rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
-				 IEEE80211_RATE_BASIC);
-
-		if (local->supp_rates[mode->mode]) {
-			if (!rate_list_match(local->supp_rates[mode->mode],
-					     rate->rate))
-				continue;
-		}
-
-		rate->flags |= IEEE80211_RATE_SUPPORTED;
-
-		/* Use configured basic rate set if it is available. If not,
-		 * use defaults that are sane for most cases. */
-		if (local->basic_rates[mode->mode]) {
-			if (rate_list_match(local->basic_rates[mode->mode],
-					    rate->rate))
-				rate->flags |= IEEE80211_RATE_BASIC;
-		} else switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10 || rate->rate == 20)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110)
-				rate->flags |= IEEE80211_RATE_BASIC;
-			break;
-		case NUM_IEEE80211_MODES:
-			/* not useful */
-			break;
-		}
-
-		/* Set ERP and MANDATORY flags based on phymode */
-		switch (mode->mode) {
-		case MODE_IEEE80211A:
-			if (rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211B:
-			if (rate->rate == 10)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case MODE_IEEE80211G:
-			if (rate->rate == 10 || rate->rate == 20 ||
-			    rate->rate == 55 || rate->rate == 110 ||
-			    rate->rate == 60 || rate->rate == 120 ||
-			    rate->rate == 240)
-				rate->flags |= IEEE80211_RATE_MANDATORY;
-			break;
-		case NUM_IEEE80211_MODES:
-			/* not useful */
-			break;
-		}
-		if (ieee80211_is_erp_rate(mode->mode, rate->rate))
-			rate->flags |= IEEE80211_RATE_ERP;
-	}
-}
-
 u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
 			enum ieee80211_if_types type)
 {
@@ -232,17 +147,35 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 
-void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
+{
+	int ae = meshhdr->flags & IEEE80211S_FLAGS_AE;
+	/* 7.1.3.5a.2 */
+	switch (ae) {
+	case 0:
+		return 5;
+	case 1:
+		return 11;
+	case 2:
+		return 17;
+	case 3:
+		return 23;
+	default:
+		return 5;
+	}
+}
+
+void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
 
 	hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		struct ieee80211_hdr *fhdr;
 		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+		for (i = 0; i < tx->num_extra_frag; i++) {
 			fhdr = (struct ieee80211_hdr *)
-				tx->u.tx.extra_frag[i]->data;
+				tx->extra_frag[i]->data;
 			fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 		}
 	}
@@ -262,7 +195,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 	 * DIV_ROUND_UP() operations.
 	 */
 
-	if (local->hw.conf.phymode == MODE_IEEE80211A || erp) {
+	if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
 		/*
 		 * OFDM:
 		 *
@@ -304,15 +237,19 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
 /* Exported duration function for driver use */
 __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
 					struct ieee80211_vif *vif,
-					size_t frame_len, int rate)
+					size_t frame_len,
+					struct ieee80211_rate *rate)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 	u16 dur;
 	int erp;
 
-	erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
-	dur = ieee80211_frame_duration(local, frame_len, rate, erp,
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
+
+	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
 				       sdata->bss_conf.use_short_preamble);
 
 	return cpu_to_le16(dur);
@@ -332,17 +269,20 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
 
 	short_preamble = sdata->bss_conf.use_short_preamble;
 
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	rate = frame_txctl->rts_cts_rate;
+
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
 
 	/* CTS duration */
-	dur = ieee80211_frame_duration(local, 10, rate->rate,
+	dur = ieee80211_frame_duration(local, 10, rate->bitrate,
 				       erp, short_preamble);
 	/* Data frame duration */
-	dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+	dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
 					erp, short_preamble);
 	/* ACK duration */
-	dur += ieee80211_frame_duration(local, 10, rate->rate,
+	dur += ieee80211_frame_duration(local, 10, rate->bitrate,
 					erp, short_preamble);
 
 	return cpu_to_le16(dur);
@@ -363,15 +303,17 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 
 	short_preamble = sdata->bss_conf.use_short_preamble;
 
-	rate = frame_txctl->rts_rate;
-	erp = !!(rate->flags & IEEE80211_RATE_ERP);
+	rate = frame_txctl->rts_cts_rate;
+	erp = 0;
+	if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+		erp = rate->flags & IEEE80211_RATE_ERP_G;
 
 	/* Data frame duration */
-	dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
 				       erp, short_preamble);
 	if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
 		/* ACK duration */
-		dur += ieee80211_frame_duration(local, 10, rate->rate,
+		dur += ieee80211_frame_duration(local, 10, rate->bitrate,
 						erp, short_preamble);
 	}
 
@@ -379,27 +321,6 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_ctstoself_duration);
 
-struct ieee80211_rate *
-ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
-{
-	struct ieee80211_hw_mode *mode;
-	int r;
-
-	list_for_each_entry(mode, &local->modes_list, list) {
-		if (mode->mode != phymode)
-			continue;
-		for (r = 0; r < mode->num_rates; r++) {
-			struct ieee80211_rate *rate = &mode->rates[r];
-			if (rate->val == hw_rate ||
-			    (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
-			     rate->val2 == hw_rate))
-				return rate;
-		}
-	}
-
-	return NULL;
-}
-
 void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -480,6 +401,7 @@ void ieee80211_iterate_active_interfaces(
 		case IEEE80211_IF_TYPE_STA:
 		case IEEE80211_IF_TYPE_IBSS:
 		case IEEE80211_IF_TYPE_WDS:
+		case IEEE80211_IF_TYPE_MESH_POINT:
 			break;
 		}
 		if (sdata->dev == local->mdev)
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index a0cff72a580b..affcecd78c10 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -305,39 +305,39 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
 	return NULL;
 }
 
-ieee80211_txrx_result
-ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
 {
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
 	    ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
 	     (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
-	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
 		if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
 #ifdef CONFIG_MAC80211_DEBUG
 			if (net_ratelimit())
 				printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
 				       "failed\n", rx->dev->name);
 #endif /* CONFIG_MAC80211_DEBUG */
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
-	} else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) {
+	} else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) {
 		ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
 		/* remove ICV */
 		skb_trim(rx->skb, rx->skb->len - 4);
 	}
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
-static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
+static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 {
 	if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
 		if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
 			return -1;
 	} else {
-		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
+		tx->control->key_idx = tx->key->conf.hw_key_idx;
 		if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) {
 			if (!ieee80211_wep_add_iv(tx->local, skb, tx->key))
 				return -1;
@@ -346,28 +346,28 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
 	return 0;
 }
 
-ieee80211_txrx_result
-ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx)
 {
-	tx->u.tx.control->iv_len = WEP_IV_LEN;
-	tx->u.tx.control->icv_len = WEP_ICV_LEN;
-	ieee80211_tx_set_iswep(tx);
+	tx->control->iv_len = WEP_IV_LEN;
+	tx->control->icv_len = WEP_ICV_LEN;
+	ieee80211_tx_set_protected(tx);
 
 	if (wep_encrypt_skb(tx, tx->skb) < 0) {
 		I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
-		return TXRX_DROP;
+		return TX_DROP;
 	}
 
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
+		for (i = 0; i < tx->num_extra_frag; i++) {
+			if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) {
 				I802_DEBUG_INC(tx->local->
 					       tx_handlers_drop_wep);
-				return TXRX_DROP;
+				return TX_DROP;
 			}
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 785fbb4e0dd7..9f723938b63f 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
 			  struct ieee80211_key *key);
 u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
 
-ieee80211_txrx_result
-ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx);
-ieee80211_txrx_result
-ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx);
 
 #endif /* WEP_H */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 4e236599dd31..4e94e4026e78 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -19,10 +19,13 @@
 #include "wme.h"
 
 /* maximum number of hardware queues we support. */
-#define TC_80211_MAX_QUEUES 8
+#define TC_80211_MAX_QUEUES 16
+
+const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 struct ieee80211_sched_data
 {
+	unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)];
 	struct tcf_proto *filter_list;
 	struct Qdisc *queues[TC_80211_MAX_QUEUES];
 	struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
@@ -98,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	unsigned short fc = le16_to_cpu(hdr->frame_control);
 	int qos;
-	const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
 
 	/* see if frame is data or non data frame */
 	if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
@@ -146,9 +148,26 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 	unsigned short fc = le16_to_cpu(hdr->frame_control);
 	struct Qdisc *qdisc;
 	int err, queue;
+	struct sta_info *sta;
+	u8 tid;
 
 	if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) {
-		skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+		queue = pkt_data->queue;
+		rcu_read_lock();
+		sta = sta_info_get(local, hdr->addr1);
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
+		if (sta) {
+			int ampdu_queue = sta->tid_to_tx_q[tid];
+			if ((ampdu_queue < local->hw.queues) &&
+			    test_bit(ampdu_queue, q->qdisc_pool)) {
+				queue = ampdu_queue;
+				pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+			} else {
+				pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+			}
+		}
+		rcu_read_unlock();
+		skb_queue_tail(&q->requeued[queue], skb);
 		qd->q.qlen++;
 		return 0;
 	}
@@ -159,14 +178,31 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 	 */
 	if (WLAN_FC_IS_QOS_DATA(fc)) {
 		u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
-		u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+		u8 ack_policy = 0;
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
 		if (local->wifi_wme_noack_test)
-			qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+			ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
 					QOS_CONTROL_ACK_POLICY_SHIFT;
 		/* qos header is 2 bytes, second reserved */
-		*p = qos_hdr;
+		*p = ack_policy | tid;
 		p++;
 		*p = 0;
+
+		rcu_read_lock();
+
+		sta = sta_info_get(local, hdr->addr1);
+		if (sta) {
+			int ampdu_queue = sta->tid_to_tx_q[tid];
+			if ((ampdu_queue < local->hw.queues) &&
+				test_bit(ampdu_queue, q->qdisc_pool)) {
+				queue = ampdu_queue;
+				pkt_data->flags |= IEEE80211_TXPD_AMPDU;
+			} else {
+				pkt_data->flags &= ~IEEE80211_TXPD_AMPDU;
+			}
+		}
+
+		rcu_read_unlock();
 	}
 
 	if (unlikely(queue >= local->hw.queues)) {
@@ -184,6 +220,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
 			kfree_skb(skb);
 			err = NET_XMIT_DROP;
 	} else {
+		tid = skb->priority & QOS_CONTROL_TAG1D_MASK;
 		pkt_data->queue = (unsigned int) queue;
 		qdisc = q->queues[queue];
 		err = qdisc->enqueue(skb, qdisc);
@@ -235,10 +272,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
 	/* check all the h/w queues in numeric/priority order */
 	for (queue = 0; queue < hw->queues; queue++) {
 		/* see if there is room in this hardware queue */
-		if (test_bit(IEEE80211_LINK_STATE_XOFF,
-			     &local->state[queue]) ||
-		    test_bit(IEEE80211_LINK_STATE_PENDING,
-			     &local->state[queue]))
+		if ((test_bit(IEEE80211_LINK_STATE_XOFF,
+				&local->state[queue])) ||
+		    (test_bit(IEEE80211_LINK_STATE_PENDING,
+				&local->state[queue])) ||
+			 (!test_bit(queue, q->qdisc_pool)))
 			continue;
 
 		/* there is space - try and get a frame */
@@ -360,6 +398,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt)
 		}
 	}
 
+	/* reserve all legacy QoS queues */
+	for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++)
+		set_bit(i, q->qdisc_pool);
+
 	return err;
 }
 
@@ -605,3 +647,80 @@ void ieee80211_wme_unregister(void)
 {
 	unregister_qdisc(&wme_qdisc_ops);
 }
+
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+			struct sta_info *sta, u16 tid)
+{
+	int i;
+	struct ieee80211_sched_data *q =
+			qdisc_priv(local->mdev->qdisc_sleeping);
+	DECLARE_MAC_BUF(mac);
+
+	/* prepare the filter and save it for the SW queue
+	 * matching the recieved HW queue */
+
+	/* try to get a Qdisc from the pool */
+	for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++)
+		if (!test_and_set_bit(i, q->qdisc_pool)) {
+			ieee80211_stop_queue(local_to_hw(local), i);
+			sta->tid_to_tx_q[tid] = i;
+
+			/* IF there are already pending packets
+			 * on this tid first we need to drain them
+			 * on the previous queue
+			 * since HT is strict in order */
+#ifdef CONFIG_MAC80211_HT_DEBUG
+			if (net_ratelimit())
+				printk(KERN_DEBUG "allocated aggregation queue"
+					" %d tid %d addr %s pool=0x%lX",
+					i, tid, print_mac(mac, sta->addr),
+					q->qdisc_pool[0]);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+			return 0;
+		}
+
+	return -EAGAIN;
+}
+
+/**
+ * the caller needs to hold local->mdev->queue_lock
+ */
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+				   struct sta_info *sta, u16 tid,
+				   u8 requeue)
+{
+	struct ieee80211_sched_data *q =
+		qdisc_priv(local->mdev->qdisc_sleeping);
+	int agg_queue = sta->tid_to_tx_q[tid];
+
+	/* return the qdisc to the pool */
+	clear_bit(agg_queue, q->qdisc_pool);
+	sta->tid_to_tx_q[tid] = local->hw.queues;
+
+	if (requeue)
+		ieee80211_requeue(local, agg_queue);
+	else
+		q->queues[agg_queue]->ops->reset(q->queues[agg_queue]);
+}
+
+void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+	struct Qdisc *root_qd = local->mdev->qdisc_sleeping;
+	struct ieee80211_sched_data *q = qdisc_priv(root_qd);
+	struct Qdisc *qdisc = q->queues[queue];
+	struct sk_buff *skb = NULL;
+	u32 len = qdisc->q.qlen;
+
+	if (!qdisc || !qdisc->dequeue)
+		return;
+
+	printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen);
+	for (len = qdisc->q.qlen; len > 0; len--) {
+		skb = qdisc->dequeue(qdisc);
+		root_qd->q.qlen--;
+		/* packet will be classified again and */
+		/* skb->packet_data->queue will be overridden if needed */
+		if (skb)
+			wme_qdiscop_enqueue(skb, root_qd);
+	}
+}
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
index 76c713a6450c..fcc6b05508cc 100644
--- a/net/mac80211/wme.h
+++ b/net/mac80211/wme.h
@@ -24,6 +24,8 @@
 
 #define QOS_CONTROL_TAG1D_MASK 0x07
 
+extern const int ieee802_1d_to_ac[8];
+
 static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 {
 	return (fc & 0x8C) == 0x88;
@@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
 #ifdef CONFIG_NET_SCHED
 void ieee80211_install_qdisc(struct net_device *dev);
 int ieee80211_qdisc_installed(struct net_device *dev);
-
+int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+			       struct sta_info *sta, u16 tid);
+void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+				   struct sta_info *sta, u16 tid,
+				   u8 requeue);
+void ieee80211_requeue(struct ieee80211_local *local, int queue);
 int ieee80211_wme_register(void);
 void ieee80211_wme_unregister(void);
 #else
@@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev)
 {
 	return 0;
 }
-
+static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
+					     struct sta_info *sta, u16 tid)
+{
+	return -EAGAIN;
+}
+static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
+						 struct sta_info *sta, u16 tid,
+						 u8 requeue)
+{
+}
+static inline void ieee80211_requeue(struct ieee80211_local *local, int queue)
+{
+}
 static inline int ieee80211_wme_register(void)
 {
 	return 0;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 6f04311cf0a0..45709ada8fee 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -70,8 +70,8 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
 }
 
 
-ieee80211_txrx_result
-ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx)
 {
 	u8 *data, *sa, *da, *key, *mic, qos_tid;
 	size_t data_len;
@@ -84,18 +84,18 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 
 	if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 ||
 	    !WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 
 	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
-		return TXRX_DROP;
+		return TX_DROP;
 
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
-	    !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) &&
+	    !(tx->flags & IEEE80211_TX_FRAGMENTED) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) &&
 	    !wpa_test) {
 		/* hwaccel - with no need for preallocated room for Michael MIC
 		 */
-		return TXRX_CONTINUE;
+		return TX_CONTINUE;
 	}
 
 	if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
@@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 					      GFP_ATOMIC))) {
 			printk(KERN_DEBUG "%s: failed to allocate more memory "
 			       "for Michael MIC\n", tx->dev->name);
-			return TXRX_DROP;
+			return TX_DROP;
 		}
 	}
 
@@ -119,12 +119,12 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
 	mic = skb_put(skb, MICHAEL_MIC_LEN);
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
-ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
 {
 	u8 *data, *sa, *da, *key = NULL, qos_tid;
 	size_t data_len;
@@ -139,16 +139,16 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 	/*
 	 * No way to verify the MIC if the hardware stripped it
 	 */
-	if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED)
-		return TXRX_CONTINUE;
+	if (rx->status->flag & RX_FLAG_MMIC_STRIPPED)
+		return RX_CONTINUE;
 
 	if (!rx->key || rx->key->conf.alg != ALG_TKIP ||
 	    !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
 	    || data_len < MICHAEL_MIC_LEN)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
 	data_len -= MICHAEL_MIC_LEN;
 
@@ -161,29 +161,29 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
 				 ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
 	michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
 	if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
-		if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
-			return TXRX_DROP;
+		if (!(rx->flags & IEEE80211_RX_RA_MATCH))
+			return RX_DROP_UNUSABLE;
 
 		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
 		       "%s\n", rx->dev->name, print_mac(mac, sa));
 
 		mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx,
 						(void *) skb->data);
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
 	/* remove Michael MIC from payload */
 	skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
 
 	/* update IV in key information to be able to detect replays */
-	rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32;
-	rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16;
+	rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32;
+	rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16;
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
-static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
+static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
 			    struct sk_buff *skb, int test)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
 					    0x7f),
 				      (u8) key->u.tkip.iv16);
 
-		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
+		tx->control->key_idx = tx->key->conf.hw_key_idx;
 		return 0;
 	}
 
@@ -242,42 +242,42 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
-ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
 {
 	struct sk_buff *skb = tx->skb;
 	int wpa_test = 0, test = 0;
 
-	tx->u.tx.control->icv_len = TKIP_ICV_LEN;
-	tx->u.tx.control->iv_len = TKIP_IV_LEN;
-	ieee80211_tx_set_iswep(tx);
+	tx->control->icv_len = TKIP_ICV_LEN;
+	tx->control->iv_len = TKIP_IV_LEN;
+	ieee80211_tx_set_protected(tx);
 
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
 	    !wpa_test) {
 		/* hwaccel - with no need for preallocated room for IV/ICV */
-		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-		return TXRX_CONTINUE;
+		tx->control->key_idx = tx->key->conf.hw_key_idx;
+		return TX_CONTINUE;
 	}
 
 	if (tkip_encrypt_skb(tx, skb, test) < 0)
-		return TXRX_DROP;
+		return TX_DROP;
 
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+		for (i = 0; i < tx->num_extra_frag; i++) {
+			if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
 			    < 0)
-				return TXRX_DROP;
+				return TX_DROP;
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
-ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 	u16 fc;
@@ -290,19 +290,19 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 	hdrlen = ieee80211_get_hdrlen(fc);
 
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	if (!rx->sta || skb->len - hdrlen < 12)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
-	if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) {
-		if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) {
+	if (rx->status->flag & RX_FLAG_DECRYPTED) {
+		if (rx->status->flag & RX_FLAG_IV_STRIPPED) {
 			/*
 			 * Hardware took care of all processing, including
 			 * replay protection, and stripped the ICV/IV so
 			 * we cannot do any checks here.
 			 */
-			return TXRX_CONTINUE;
+			return RX_CONTINUE;
 		}
 
 		/* let TKIP code verify IV, but skip decryption */
@@ -312,9 +312,9 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 	res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
 					  key, skb->data + hdrlen,
 					  skb->len - hdrlen, rx->sta->addr,
-					  hwaccel, rx->u.rx.queue,
-					  &rx->u.rx.tkip_iv32,
-					  &rx->u.rx.tkip_iv16);
+					  hdr->addr1, hwaccel, rx->queue,
+					  &rx->tkip_iv32,
+					  &rx->tkip_iv16);
 	if (res != TKIP_DECRYPT_OK || wpa_test) {
 #ifdef CONFIG_MAC80211_DEBUG
 		if (net_ratelimit())
@@ -322,7 +322,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 			       "frame from %s (res=%d)\n", rx->dev->name,
 			       print_mac(mac, rx->sta->addr), res);
 #endif /* CONFIG_MAC80211_DEBUG */
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
 	/* Trim ICV */
@@ -332,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx)
 	memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
 	skb_pull(skb, TKIP_IV_LEN);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
 
 
@@ -429,7 +429,7 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
 }
 
 
-static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
+static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx,
 			    struct sk_buff *skb, int test)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -478,7 +478,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
 
 	if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
 		/* hwaccel - with preallocated room for CCMP header */
-		tx->u.tx.control->key_idx = key->conf.hw_key_idx;
+		tx->control->key_idx = key->conf.hw_key_idx;
 		return 0;
 	}
 
@@ -491,42 +491,42 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
 }
 
 
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx)
+ieee80211_tx_result
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx)
 {
 	struct sk_buff *skb = tx->skb;
 	int test = 0;
 
-	tx->u.tx.control->icv_len = CCMP_MIC_LEN;
-	tx->u.tx.control->iv_len = CCMP_HDR_LEN;
-	ieee80211_tx_set_iswep(tx);
+	tx->control->icv_len = CCMP_MIC_LEN;
+	tx->control->iv_len = CCMP_HDR_LEN;
+	ieee80211_tx_set_protected(tx);
 
 	if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) &&
 	    !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
 		/* hwaccel - with no need for preallocated room for CCMP "
 		 * header or MIC fields */
-		tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx;
-		return TXRX_CONTINUE;
+		tx->control->key_idx = tx->key->conf.hw_key_idx;
+		return TX_CONTINUE;
 	}
 
 	if (ccmp_encrypt_skb(tx, skb, test) < 0)
-		return TXRX_DROP;
+		return TX_DROP;
 
-	if (tx->u.tx.extra_frag) {
+	if (tx->extra_frag) {
 		int i;
-		for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
-			if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+		for (i = 0; i < tx->num_extra_frag; i++) {
+			if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test)
 			    < 0)
-				return TXRX_DROP;
+				return TX_DROP;
 		}
 	}
 
-	return TXRX_CONTINUE;
+	return TX_CONTINUE;
 }
 
 
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
+ieee80211_rx_result
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
 	u16 fc;
@@ -541,21 +541,21 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 	hdrlen = ieee80211_get_hdrlen(fc);
 
 	if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
-		return TXRX_CONTINUE;
+		return RX_CONTINUE;
 
 	data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
 	if (!rx->sta || data_len < 0)
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 
-	if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
-	    (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED))
-		return TXRX_CONTINUE;
+	if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
+	    (rx->status->flag & RX_FLAG_IV_STRIPPED))
+		return RX_CONTINUE;
 
 	(void) ccmp_hdr2pn(pn, skb->data + hdrlen);
 
-	if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
+	if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) {
 #ifdef CONFIG_MAC80211_DEBUG
-		u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+		u8 *ppn = key->u.ccmp.rx_pn[rx->queue];
 
 		printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
 		       "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
@@ -565,10 +565,10 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 		       ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
 #endif /* CONFIG_MAC80211_DEBUG */
 		key->u.ccmp.replays++;
-		return TXRX_DROP;
+		return RX_DROP_UNUSABLE;
 	}
 
-	if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) {
+	if (!(rx->status->flag & RX_FLAG_DECRYPTED)) {
 		/* hardware didn't decrypt/verify MIC */
 		u8 *scratch, *b_0, *aad;
 
@@ -589,16 +589,16 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx)
 				       "for RX frame from %s\n", rx->dev->name,
 				       print_mac(mac, rx->sta->addr));
 #endif /* CONFIG_MAC80211_DEBUG */
-			return TXRX_DROP;
+			return RX_DROP_UNUSABLE;
 		}
 	}
 
-	memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN);
+	memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN);
 
 	/* Remove CCMP header and MIC */
 	skb_trim(skb, skb->len - CCMP_MIC_LEN);
 	memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
 	skb_pull(skb, CCMP_HDR_LEN);
 
-	return TXRX_CONTINUE;
+	return RX_CONTINUE;
 }
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h
index 49d80cf0cd75..d42d221d8a1d 100644
--- a/net/mac80211/wpa.h
+++ b/net/mac80211/wpa.h
@@ -13,19 +13,19 @@
 #include <linux/types.h>
 #include "ieee80211_i.h"
 
-ieee80211_txrx_result
-ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx);
 
-ieee80211_txrx_result
-ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx);
 
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx);
-ieee80211_txrx_result
-ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx);
+ieee80211_tx_result
+ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx);
+ieee80211_rx_result
+ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx);
 
 #endif /* WPA_H */
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index c4065b8f9a95..292fa28146fb 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -165,6 +165,14 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
 	unsigned int verdict;
 	int ret = 0;
 
+#ifdef CONFIG_NET_NS
+	struct net *net;
+
+	net = indev == NULL ? dev_net(outdev) : dev_net(indev);
+	if (net != &init_net)
+		return 1;
+#endif
+
 	/* We may already have this, but read-locks nest anyway */
 	rcu_read_lock();
 
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index 7b8239c0cd5e..d14585a19b7d 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -148,7 +148,8 @@ static int amanda_help(struct sk_buff *skb,
 			goto out;
 		}
 		tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
-		nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+				  &tuple->src.u3, &tuple->dst.u3,
 				  IPPROTO_TCP, NULL, &port);
 
 		nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
@@ -164,26 +165,29 @@ out:
 	return ret;
 }
 
+static const struct nf_conntrack_expect_policy amanda_exp_policy = {
+	.max_expected		= 3,
+	.timeout		= 180,
+};
+
 static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
 	{
 		.name			= "amanda",
-		.max_expected		= 3,
-		.timeout		= 180,
 		.me			= THIS_MODULE,
 		.help			= amanda_help,
 		.tuple.src.l3num	= AF_INET,
 		.tuple.src.u.udp.port	= __constant_htons(10080),
 		.tuple.dst.protonum	= IPPROTO_UDP,
+		.expect_policy		= &amanda_exp_policy,
 	},
 	{
 		.name			= "amanda",
-		.max_expected		= 3,
-		.timeout		= 180,
 		.me			= THIS_MODULE,
 		.help			= amanda_help,
 		.tuple.src.l3num	= AF_INET6,
 		.tuple.src.u.udp.port	= __constant_htons(10080),
 		.tuple.dst.protonum	= IPPROTO_UDP,
+		.expect_policy		= &amanda_exp_policy,
 	},
 };
 
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 684ec9c1ad38..e31beeb33b2b 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -54,7 +54,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
 	nf_ct_expect_count--;
 
 	hlist_del(&exp->lnode);
-	master_help->expecting--;
+	master_help->expecting[exp->class]--;
 	nf_ct_expect_put(exp);
 
 	NF_CT_STAT_INC(expect_delete);
@@ -126,9 +126,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
 struct nf_conntrack_expect *
 nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
 {
-	struct nf_conntrack_expect *exp;
+	struct nf_conntrack_expect *i, *exp = NULL;
+	struct hlist_node *n;
+	unsigned int h;
+
+	if (!nf_ct_expect_count)
+		return NULL;
 
-	exp = __nf_ct_expect_find(tuple);
+	h = nf_ct_expect_dst_hash(tuple);
+	hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
+		if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
+		    nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
+			exp = i;
+			break;
+		}
+	}
 	if (!exp)
 		return NULL;
 
@@ -159,7 +171,7 @@ void nf_ct_remove_expectations(struct nf_conn *ct)
 	struct hlist_node *n, *next;
 
 	/* Optimization: most connection never expect any others. */
-	if (!help || help->expecting == 0)
+	if (!help)
 		return;
 
 	hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
@@ -193,7 +205,7 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
 static inline int expect_matches(const struct nf_conntrack_expect *a,
 				 const struct nf_conntrack_expect *b)
 {
-	return a->master == b->master
+	return a->master == b->master && a->class == b->class
 		&& nf_ct_tuple_equal(&a->tuple, &b->tuple)
 		&& nf_ct_tuple_mask_equal(&a->mask, &b->mask);
 }
@@ -228,10 +240,11 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
 
-void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
-		       union nf_inet_addr *saddr,
-		       union nf_inet_addr *daddr,
-		       u_int8_t proto, __be16 *src, __be16 *dst)
+void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
+		       int family,
+		       const union nf_inet_addr *saddr,
+		       const union nf_inet_addr *daddr,
+		       u_int8_t proto, const __be16 *src, const __be16 *dst)
 {
 	int len;
 
@@ -241,6 +254,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
 		len = 16;
 
 	exp->flags = 0;
+	exp->class = class;
 	exp->expectfn = NULL;
 	exp->helper = NULL;
 	exp->tuple.src.l3num = family;
@@ -297,19 +311,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_put);
 static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
 {
 	struct nf_conn_help *master_help = nfct_help(exp->master);
+	const struct nf_conntrack_expect_policy *p;
 	unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
 
 	atomic_inc(&exp->use);
 
 	hlist_add_head(&exp->lnode, &master_help->expectations);
-	master_help->expecting++;
+	master_help->expecting[exp->class]++;
 
 	hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
 	nf_ct_expect_count++;
 
 	setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
 		    (unsigned long)exp);
-	exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
+	p = &master_help->helper->expect_policy[exp->class];
+	exp->timeout.expires = jiffies + p->timeout * HZ;
 	add_timer(&exp->timeout);
 
 	atomic_inc(&exp->use);
@@ -317,35 +333,41 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
 }
 
 /* Race with expectations being used means we could have none to find; OK. */
-static void evict_oldest_expect(struct nf_conn *master)
+static void evict_oldest_expect(struct nf_conn *master,
+				struct nf_conntrack_expect *new)
 {
 	struct nf_conn_help *master_help = nfct_help(master);
-	struct nf_conntrack_expect *exp = NULL;
+	struct nf_conntrack_expect *exp, *last = NULL;
 	struct hlist_node *n;
 
-	hlist_for_each_entry(exp, n, &master_help->expectations, lnode)
-		; /* nothing */
+	hlist_for_each_entry(exp, n, &master_help->expectations, lnode) {
+		if (exp->class == new->class)
+			last = exp;
+	}
 
-	if (exp && del_timer(&exp->timeout)) {
-		nf_ct_unlink_expect(exp);
-		nf_ct_expect_put(exp);
+	if (last && del_timer(&last->timeout)) {
+		nf_ct_unlink_expect(last);
+		nf_ct_expect_put(last);
 	}
 }
 
 static inline int refresh_timer(struct nf_conntrack_expect *i)
 {
 	struct nf_conn_help *master_help = nfct_help(i->master);
+	const struct nf_conntrack_expect_policy *p;
 
 	if (!del_timer(&i->timeout))
 		return 0;
 
-	i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
+	p = &master_help->helper->expect_policy[i->class];
+	i->timeout.expires = jiffies + p->timeout * HZ;
 	add_timer(&i->timeout);
 	return 1;
 }
 
 int nf_ct_expect_related(struct nf_conntrack_expect *expect)
 {
+	const struct nf_conntrack_expect_policy *p;
 	struct nf_conntrack_expect *i;
 	struct nf_conn *master = expect->master;
 	struct nf_conn_help *master_help = nfct_help(master);
@@ -374,9 +396,15 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect)
 		}
 	}
 	/* Will be over limit? */
-	if (master_help->helper->max_expected &&
-	    master_help->expecting >= master_help->helper->max_expected)
-		evict_oldest_expect(master);
+	p = &master_help->helper->expect_policy[expect->class];
+	if (p->max_expected &&
+	    master_help->expecting[expect->class] >= p->max_expected) {
+		evict_oldest_expect(master, expect);
+		if (master_help->expecting[expect->class] >= p->max_expected) {
+			ret = -EMFILE;
+			goto out;
+		}
+	}
 
 	if (nf_ct_expect_count >= nf_ct_expect_max) {
 		if (net_ratelimit())
@@ -460,6 +488,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
 {
 	struct nf_conntrack_expect *expect;
 	struct hlist_node *n = v;
+	char *delim = "";
 
 	expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
 
@@ -475,6 +504,14 @@ static int exp_seq_show(struct seq_file *s, void *v)
 		    __nf_ct_l3proto_find(expect->tuple.src.l3num),
 		    __nf_ct_l4proto_find(expect->tuple.src.l3num,
 				       expect->tuple.dst.protonum));
+
+	if (expect->flags & NF_CT_EXPECT_PERMANENT) {
+		seq_printf(s, "PERMANENT");
+		delim = ",";
+	}
+	if (expect->flags & NF_CT_EXPECT_INACTIVE)
+		seq_printf(s, "%sINACTIVE", delim);
+
 	return seq_putc(s, '\n');
 }
 
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 6770baf2e845..7eff876bb8bc 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -483,7 +483,7 @@ static int help(struct sk_buff *skb,
 		daddr = &cmd.u3;
 	}
 
-	nf_ct_expect_init(exp, cmd.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, cmd.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3, daddr,
 			  IPPROTO_TCP, NULL, &cmd.u.tcp.port);
 
@@ -517,6 +517,11 @@ out_update_nl:
 static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
 static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")] __read_mostly;
 
+static const struct nf_conntrack_expect_policy ftp_exp_policy = {
+	.max_expected	= 1,
+	.timeout	= 5 * 60,
+};
+
 /* don't make this __exit, since it's called from __init ! */
 static void nf_conntrack_ftp_fini(void)
 {
@@ -556,8 +561,7 @@ static int __init nf_conntrack_ftp_init(void)
 		for (j = 0; j < 2; j++) {
 			ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
 			ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
-			ftp[i][j].max_expected = 1;
-			ftp[i][j].timeout = 5 * 60;	/* 5 Minutes */
+			ftp[i][j].expect_policy = &ftp_exp_policy;
 			ftp[i][j].me = THIS_MODULE;
 			ftp[i][j].help = help;
 			tmpname = &ftp_names[i][j][0];
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 898f1922b5b8..505052d495cf 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -277,7 +277,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 	/* Create expect for RTP */
 	if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_UDP, NULL, &rtp_port);
@@ -287,7 +288,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 		nf_ct_expect_put(rtp_exp);
 		return -1;
 	}
-	nf_ct_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_UDP, NULL, &rtcp_port);
@@ -344,7 +346,8 @@ static int expect_t120(struct sk_buff *skb,
 	/* Create expect for T.120 connections */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_TCP, NULL, &port);
@@ -612,13 +615,17 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
 }
 
 /****************************************************************************/
+static const struct nf_conntrack_expect_policy h245_exp_policy = {
+	.max_expected	= H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
+	.timeout	= 240,
+};
+
 static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
 	.name			= "H.245",
 	.me			= THIS_MODULE,
-	.max_expected		= H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
-	.timeout		= 240,
 	.tuple.dst.protonum	= IPPROTO_UDP,
-	.help			= h245_help
+	.help			= h245_help,
+	.expect_policy		= &h245_exp_policy,
 };
 
 /****************************************************************************/
@@ -676,7 +683,8 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
 	/* Create expect for h245 connection */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
 			  IPPROTO_TCP, NULL, &port);
@@ -792,7 +800,8 @@ static int expect_callforwarding(struct sk_buff *skb,
 	/* Create expect for the second call leg */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
 	exp->helper = nf_conntrack_helper_q931;
@@ -1156,28 +1165,30 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
 }
 
 /****************************************************************************/
+static const struct nf_conntrack_expect_policy q931_exp_policy = {
+	/* T.120 and H.245 */
+	.max_expected		= H323_RTP_CHANNEL_MAX * 4 + 4,
+	.timeout		= 240,
+};
+
 static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
 	{
 		.name			= "Q.931",
 		.me			= THIS_MODULE,
-					  /* T.120 and H.245 */
-		.max_expected		= H323_RTP_CHANNEL_MAX * 4 + 4,
-		.timeout		= 240,
 		.tuple.src.l3num	= AF_INET,
 		.tuple.src.u.tcp.port	= __constant_htons(Q931_PORT),
 		.tuple.dst.protonum	= IPPROTO_TCP,
-		.help			= q931_help
+		.help			= q931_help,
+		.expect_policy		= &q931_exp_policy,
 	},
 	{
 		.name			= "Q.931",
 		.me			= THIS_MODULE,
-					  /* T.120 and H.245 */
-		.max_expected		= H323_RTP_CHANNEL_MAX * 4 + 4,
-		.timeout		= 240,
 		.tuple.src.l3num	= AF_INET6,
 		.tuple.src.u.tcp.port	= __constant_htons(Q931_PORT),
 		.tuple.dst.protonum	= IPPROTO_TCP,
-		.help			= q931_help
+		.help			= q931_help,
+		.expect_policy		= &q931_exp_policy,
 	},
 };
 
@@ -1261,7 +1272,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 	/* Create expect for Q.931 */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  gkrouted_only ? /* only accept calls from GK? */
 				&ct->tuplehash[!dir].tuple.src.u3 : NULL,
 			  &ct->tuplehash[!dir].tuple.dst.u3,
@@ -1332,7 +1344,8 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
 	/* Need new expect */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_UDP, NULL, &port);
 	exp->helper = nf_conntrack_helper_ras;
@@ -1536,7 +1549,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 	/* Need new expect */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
 	exp->flags = NF_CT_EXPECT_PERMANENT;
@@ -1589,7 +1603,8 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
 	/* Need new expect for call signal */
 	if ((exp = nf_ct_expect_alloc(ct)) == NULL)
 		return -1;
-	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[!dir].tuple.src.l3num,
 			  &ct->tuplehash[!dir].tuple.src.u3, &addr,
 			  IPPROTO_TCP, NULL, &port);
 	exp->flags = NF_CT_EXPECT_PERMANENT;
@@ -1728,26 +1743,29 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
 }
 
 /****************************************************************************/
+static const struct nf_conntrack_expect_policy ras_exp_policy = {
+	.max_expected		= 32,
+	.timeout		= 240,
+};
+
 static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
 	{
 		.name			= "RAS",
 		.me			= THIS_MODULE,
-		.max_expected		= 32,
-		.timeout		= 240,
 		.tuple.src.l3num	= AF_INET,
 		.tuple.src.u.udp.port	= __constant_htons(RAS_PORT),
 		.tuple.dst.protonum	= IPPROTO_UDP,
 		.help			= ras_help,
+		.expect_policy		= &ras_exp_policy,
 	},
 	{
 		.name			= "RAS",
 		.me			= THIS_MODULE,
-		.max_expected		= 32,
-		.timeout		= 240,
 		.tuple.src.l3num	= AF_INET6,
 		.tuple.src.u.udp.port	= __constant_htons(RAS_PORT),
 		.tuple.dst.protonum	= IPPROTO_UDP,
 		.help			= ras_help,
+		.expect_policy		= &ras_exp_policy,
 	},
 };
 
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index b1fd21cc1dbc..e350f56d43c9 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -110,7 +110,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
 {
 	unsigned int h = helper_hash(&me->tuple);
 
-	BUG_ON(me->timeout == 0);
+	BUG_ON(me->expect_policy == NULL);
+	BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
 
 	mutex_lock(&nf_ct_helper_mutex);
 	hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]);
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index c336b07a0d4c..02f21cbe5ae7 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -187,7 +187,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 			}
 			tuple = &ct->tuplehash[!dir].tuple;
 			port = htons(dcc_port);
-			nf_ct_expect_init(exp, tuple->src.l3num,
+			nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
+					  tuple->src.l3num,
 					  NULL, &tuple->dst.u3,
 					  IPPROTO_TCP, NULL, &port);
 
@@ -210,6 +211,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 
 static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly;
 static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly;
+static struct nf_conntrack_expect_policy irc_exp_policy;
 
 static void nf_conntrack_irc_fini(void);
 
@@ -223,6 +225,9 @@ static int __init nf_conntrack_irc_init(void)
 		return -EINVAL;
 	}
 
+	irc_exp_policy.max_expected = max_dcc_channels;
+	irc_exp_policy.timeout = dcc_timeout;
+
 	irc_buffer = kmalloc(65536, GFP_KERNEL);
 	if (!irc_buffer)
 		return -ENOMEM;
@@ -235,8 +240,7 @@ static int __init nf_conntrack_irc_init(void)
 		irc[i].tuple.src.l3num = AF_INET;
 		irc[i].tuple.src.u.tcp.port = htons(ports[i]);
 		irc[i].tuple.dst.protonum = IPPROTO_TCP;
-		irc[i].max_expected = max_dcc_channels;
-		irc[i].timeout = dcc_timeout;
+		irc[i].expect_policy = &irc_exp_policy;
 		irc[i].me = THIS_MODULE;
 		irc[i].help = help;
 
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 9810d81e2a06..08404e6755fb 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -47,7 +47,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 {
 	struct nf_conntrack_expect *exp;
 	struct iphdr *iph = ip_hdr(skb);
-	struct rtable *rt = (struct rtable *)skb->dst;
+	struct rtable *rt = skb->rtable;
 	struct in_device *in_dev;
 	__be32 mask = 0;
 
@@ -86,6 +86,7 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 
 	exp->expectfn             = NULL;
 	exp->flags                = NF_CT_EXPECT_PERMANENT;
+	exp->class		  = NF_CT_EXPECT_CLASS_DEFAULT;
 	exp->helper               = NULL;
 
 	nf_ct_expect_related(exp);
@@ -96,19 +97,23 @@ out:
 	return NF_ACCEPT;
 }
 
+static struct nf_conntrack_expect_policy exp_policy = {
+	.max_expected	= 1,
+};
+
 static struct nf_conntrack_helper helper __read_mostly = {
 	.name			= "netbios-ns",
 	.tuple.src.l3num	= AF_INET,
 	.tuple.src.u.udp.port	= __constant_htons(NMBD_PORT),
 	.tuple.dst.protonum	= IPPROTO_UDP,
-	.max_expected		= 1,
 	.me			= THIS_MODULE,
 	.help			= help,
+	.expect_policy		= &exp_policy,
 };
 
 static int __init nf_conntrack_netbios_ns_init(void)
 {
-	helper.timeout = timeout;
+	exp_policy.timeout = timeout;
 	return nf_conntrack_helper_register(&helper);
 }
 
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index b5cb8e831230..8fd83470d1b3 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -208,7 +208,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
 
 	/* original direction, PNS->PAC */
 	dir = IP_CT_DIR_ORIGINAL;
-	nf_ct_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num,
+	nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[dir].tuple.src.l3num,
 			  &ct->tuplehash[dir].tuple.src.u3,
 			  &ct->tuplehash[dir].tuple.dst.u3,
 			  IPPROTO_GRE, &peer_callid, &callid);
@@ -216,7 +217,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
 
 	/* reply direction, PAC->PNS */
 	dir = IP_CT_DIR_REPLY;
-	nf_ct_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num,
+	nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT,
+			  ct->tuplehash[dir].tuple.src.l3num,
 			  &ct->tuplehash[dir].tuple.src.u3,
 			  &ct->tuplehash[dir].tuple.dst.u3,
 			  IPPROTO_GRE, &callid, &peer_callid);
@@ -575,17 +577,21 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
 	return ret;
 }
 
+static const struct nf_conntrack_expect_policy pptp_exp_policy = {
+	.max_expected	= 2,
+	.timeout	= 5 * 60,
+};
+
 /* control protocol helper */
 static struct nf_conntrack_helper pptp __read_mostly = {
 	.name			= "pptp",
 	.me			= THIS_MODULE,
-	.max_expected		= 2,
-	.timeout		= 5 * 60,
 	.tuple.src.l3num	= AF_INET,
 	.tuple.src.u.tcp.port	= __constant_htons(PPTP_CONTROL_PORT),
 	.tuple.dst.protonum	= IPPROTO_TCP,
 	.help			= conntrack_pptp_help,
 	.destroy		= pptp_destroy_siblings,
+	.expect_policy		= &pptp_exp_policy,
 };
 
 static int __init nf_conntrack_pptp_init(void)
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index a70051d741a7..7542e25eede3 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -143,7 +143,8 @@ static int help(struct sk_buff *skb,
 	}
 
 	tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
-	nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+	nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+			  &tuple->src.u3, &tuple->dst.u3,
 			  IPPROTO_TCP, NULL, &reply->port);
 
 	pr_debug("nf_ct_sane: expect: ");
@@ -163,6 +164,11 @@ out:
 static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly;
 static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly;
 
+static const struct nf_conntrack_expect_policy sane_exp_policy = {
+	.max_expected	= 1,
+	.timeout	= 5 * 60,
+};
+
 /* don't make this __exit, since it's called from __init ! */
 static void nf_conntrack_sane_fini(void)
 {
@@ -200,8 +206,7 @@ static int __init nf_conntrack_sane_init(void)
 		for (j = 0; j < 2; j++) {
 			sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
 			sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
-			sane[i][j].max_expected = 1;
-			sane[i][j].timeout = 5 * 60;	/* 5 Minutes */
+			sane[i][j].expect_policy = &sane_exp_policy;
 			sane[i][j].me = THIS_MODULE;
 			sane[i][j].help = help;
 			tmpname = &sane_names[i][j][0];
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index c521c891d351..da5dec6e6158 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -2,6 +2,8 @@
  *
  * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
  * based on RR's ip_conntrack_ftp.c and other modules.
+ * (C) 2007 United Security Providers
+ * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
  *
  * 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
@@ -17,6 +19,7 @@
 #include <linux/netfilter.h>
 
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <linux/netfilter/nf_conntrack_sip.h>
@@ -36,214 +39,102 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT;
 module_param(sip_timeout, uint, 0600);
 MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
 
+static int sip_direct_signalling __read_mostly = 1;
+module_param(sip_direct_signalling, int, 0600);
+MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar "
+					"only (default 1)");
+
+static int sip_direct_media __read_mostly = 1;
+module_param(sip_direct_media, int, 0600);
+MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling "
+				   "endpoints only (default 1)");
+
 unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
-				enum ip_conntrack_info ctinfo,
-				struct nf_conn *ct,
-				const char **dptr) __read_mostly;
+				const char **dptr,
+				unsigned int *datalen) __read_mostly;
 EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
 
-unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
-				enum ip_conntrack_info ctinfo,
-				struct nf_conntrack_expect *exp,
-				const char *dptr) __read_mostly;
-EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
-
-static int digits_len(const struct nf_conn *, const char *, const char *, int *);
-static int epaddr_len(const struct nf_conn *, const char *, const char *, int *);
-static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *);
-static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *);
-
-struct sip_header_nfo {
-	const char	*lname;
-	const char	*sname;
-	const char	*ln_str;
-	size_t		lnlen;
-	size_t		snlen;
-	size_t		ln_strlen;
-	int		case_sensitive;
-	int		(*match_len)(const struct nf_conn *, const char *,
-				     const char *, int *);
-};
+unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
+				       const char **dptr,
+				       unsigned int *datalen,
+				       struct nf_conntrack_expect *exp,
+				       unsigned int matchoff,
+				       unsigned int matchlen) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
 
-static const struct sip_header_nfo ct_sip_hdrs[] = {
-	[POS_REG_REQ_URI] = { 	/* SIP REGISTER request URI */
-		.lname		= "sip:",
-		.lnlen		= sizeof("sip:") - 1,
-		.ln_str		= ":",
-		.ln_strlen	= sizeof(":") - 1,
-		.match_len	= epaddr_len,
-	},
-	[POS_REQ_URI] = { 	/* SIP request URI */
-		.lname		= "sip:",
-		.lnlen		= sizeof("sip:") - 1,
-		.ln_str		= "@",
-		.ln_strlen	= sizeof("@") - 1,
-		.match_len	= epaddr_len,
-	},
-	[POS_FROM] = {		/* SIP From header */
-		.lname		= "From:",
-		.lnlen		= sizeof("From:") - 1,
-		.sname		= "\r\nf:",
-		.snlen		= sizeof("\r\nf:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len,
-	},
-	[POS_TO] = {		/* SIP To header */
-		.lname		= "To:",
-		.lnlen		= sizeof("To:") - 1,
-		.sname		= "\r\nt:",
-		.snlen		= sizeof("\r\nt:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len
-	},
-	[POS_VIA] = { 		/* SIP Via header */
-		.lname		= "Via:",
-		.lnlen		= sizeof("Via:") - 1,
-		.sname		= "\r\nv:",
-		.snlen		= sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
-		.ln_str		= "UDP ",
-		.ln_strlen	= sizeof("UDP ") - 1,
-		.match_len	= epaddr_len,
-	},
-	[POS_CONTACT] = { 	/* SIP Contact header */
-		.lname		= "Contact:",
-		.lnlen		= sizeof("Contact:") - 1,
-		.sname		= "\r\nm:",
-		.snlen		= sizeof("\r\nm:") - 1,
-		.ln_str		= "sip:",
-		.ln_strlen	= sizeof("sip:") - 1,
-		.match_len	= skp_epaddr_len
-	},
-	[POS_CONTENT] = { 	/* SIP Content length header */
-		.lname		= "Content-Length:",
-		.lnlen		= sizeof("Content-Length:") - 1,
-		.sname		= "\r\nl:",
-		.snlen		= sizeof("\r\nl:") - 1,
-		.ln_str		= ":",
-		.ln_strlen	= sizeof(":") - 1,
-		.match_len	= skp_digits_len
-	},
-	[POS_MEDIA] = {		/* SDP media info */
-		.case_sensitive	= 1,
-		.lname		= "\nm=",
-		.lnlen		= sizeof("\nm=") - 1,
-		.sname		= "\rm=",
-		.snlen		= sizeof("\rm=") - 1,
-		.ln_str		= "audio ",
-		.ln_strlen	= sizeof("audio ") - 1,
-		.match_len	= digits_len
-	},
-	[POS_OWNER_IP4] = {	/* SDP owner address*/
-		.case_sensitive	= 1,
-		.lname		= "\no=",
-		.lnlen		= sizeof("\no=") - 1,
-		.sname		= "\ro=",
-		.snlen		= sizeof("\ro=") - 1,
-		.ln_str		= "IN IP4 ",
-		.ln_strlen	= sizeof("IN IP4 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_CONNECTION_IP4] = {/* SDP connection info */
-		.case_sensitive	= 1,
-		.lname		= "\nc=",
-		.lnlen		= sizeof("\nc=") - 1,
-		.sname		= "\rc=",
-		.snlen		= sizeof("\rc=") - 1,
-		.ln_str		= "IN IP4 ",
-		.ln_strlen	= sizeof("IN IP4 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_OWNER_IP6] = {	/* SDP owner address*/
-		.case_sensitive	= 1,
-		.lname		= "\no=",
-		.lnlen		= sizeof("\no=") - 1,
-		.sname		= "\ro=",
-		.snlen		= sizeof("\ro=") - 1,
-		.ln_str		= "IN IP6 ",
-		.ln_strlen	= sizeof("IN IP6 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_CONNECTION_IP6] = {/* SDP connection info */
-		.case_sensitive	= 1,
-		.lname		= "\nc=",
-		.lnlen		= sizeof("\nc=") - 1,
-		.sname		= "\rc=",
-		.snlen		= sizeof("\rc=") - 1,
-		.ln_str		= "IN IP6 ",
-		.ln_strlen	= sizeof("IN IP6 ") - 1,
-		.match_len	= epaddr_len
-	},
-	[POS_SDP_HEADER] = { 	/* SDP version header */
-		.case_sensitive	= 1,
-		.lname		= "\nv=",
-		.lnlen		= sizeof("\nv=") - 1,
-		.sname		= "\rv=",
-		.snlen		= sizeof("\rv=") - 1,
-		.ln_str		= "=",
-		.ln_strlen	= sizeof("=") - 1,
-		.match_len	= digits_len
-	}
-};
+unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
+				     const char **dptr,
+				     unsigned int dataoff,
+				     unsigned int *datalen,
+				     enum sdp_header_types type,
+				     enum sdp_header_types term,
+				     const union nf_inet_addr *addr)
+				     __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
 
-/* get line length until first CR or LF seen. */
-int ct_sip_lnlen(const char *line, const char *limit)
-{
-	const char *k = line;
+unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
+				     const char **dptr,
+				     unsigned int *datalen,
+				     unsigned int matchoff,
+				     unsigned int matchlen,
+				     u_int16_t port) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
 
-	while ((line <= limit) && (*line == '\r' || *line == '\n'))
-		line++;
+unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
+					const char **dptr,
+					unsigned int dataoff,
+					unsigned int *datalen,
+					const union nf_inet_addr *addr)
+					__read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook);
 
-	while (line <= limit) {
-		if (*line == '\r' || *line == '\n')
-			break;
-		line++;
-	}
-	return line - k;
-}
-EXPORT_SYMBOL_GPL(ct_sip_lnlen);
+unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
+				      const char **dptr,
+				      unsigned int *datalen,
+				      struct nf_conntrack_expect *rtp_exp,
+				      struct nf_conntrack_expect *rtcp_exp,
+				      unsigned int mediaoff,
+				      unsigned int medialen,
+				      union nf_inet_addr *rtp_addr)
+				      __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook);
 
-/* Linear string search, case sensitive. */
-const char *ct_sip_search(const char *needle, const char *haystack,
-			  size_t needle_len, size_t haystack_len,
-			  int case_sensitive)
+static int string_len(const struct nf_conn *ct, const char *dptr,
+		      const char *limit, int *shift)
 {
-	const char *limit = haystack + (haystack_len - needle_len);
+	int len = 0;
 
-	while (haystack <= limit) {
-		if (case_sensitive) {
-			if (strncmp(haystack, needle, needle_len) == 0)
-				return haystack;
-		} else {
-			if (strnicmp(haystack, needle, needle_len) == 0)
-				return haystack;
-		}
-		haystack++;
+	while (dptr < limit && isalpha(*dptr)) {
+		dptr++;
+		len++;
 	}
-	return NULL;
+	return len;
 }
-EXPORT_SYMBOL_GPL(ct_sip_search);
 
 static int digits_len(const struct nf_conn *ct, const char *dptr,
 		      const char *limit, int *shift)
 {
 	int len = 0;
-	while (dptr <= limit && isdigit(*dptr)) {
+	while (dptr < limit && isdigit(*dptr)) {
 		dptr++;
 		len++;
 	}
 	return len;
 }
 
-/* get digits length, skipping blank spaces. */
-static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
-			  const char *limit, int *shift)
+/* get media type + port length */
+static int media_len(const struct nf_conn *ct, const char *dptr,
+		     const char *limit, int *shift)
 {
-	for (; dptr <= limit && *dptr == ' '; dptr++)
-		(*shift)++;
+	int len = string_len(ct, dptr, limit, shift);
+
+	dptr += len;
+	if (dptr >= limit || *dptr != ' ')
+		return 0;
+	len++;
+	dptr++;
 
-	return digits_len(ct, dptr, limit, shift);
+	return len + digits_len(ct, dptr, limit, shift);
 }
 
 static int parse_addr(const struct nf_conn *ct, const char *cp,
@@ -302,13 +193,13 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
 	/* Search for @, but stop at the end of the line.
 	 * We are inside a sip: URI, so we don't need to worry about
 	 * continuation lines. */
-	while (dptr <= limit &&
+	while (dptr < limit &&
 	       *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
 		(*shift)++;
 		dptr++;
 	}
 
-	if (dptr <= limit && *dptr == '@') {
+	if (dptr < limit && *dptr == '@') {
 		dptr++;
 		(*shift)++;
 	} else {
@@ -319,74 +210,894 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
 	return epaddr_len(ct, dptr, limit, shift);
 }
 
-/* Returns 0 if not found, -1 error parsing. */
-int ct_sip_get_info(const struct nf_conn *ct,
-		    const char *dptr, size_t dlen,
-		    unsigned int *matchoff,
-		    unsigned int *matchlen,
-		    enum sip_header_pos pos)
+/* Parse a SIP request line of the form:
+ *
+ * Request-Line = Method SP Request-URI SP SIP-Version CRLF
+ *
+ * and return the offset and length of the address contained in the Request-URI.
+ */
+int ct_sip_parse_request(const struct nf_conn *ct,
+			 const char *dptr, unsigned int datalen,
+			 unsigned int *matchoff, unsigned int *matchlen,
+			 union nf_inet_addr *addr, __be16 *port)
 {
-	const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
-	const char *limit, *aux, *k = dptr;
+	const char *start = dptr, *limit = dptr + datalen, *end;
+	unsigned int mlen;
+	unsigned int p;
 	int shift = 0;
 
-	limit = dptr + (dlen - hnfo->lnlen);
+	/* Skip method and following whitespace */
+	mlen = string_len(ct, dptr, limit, NULL);
+	if (!mlen)
+		return 0;
+	dptr += mlen;
+	if (++dptr >= limit)
+		return 0;
+
+	/* Find SIP URI */
+	limit -= strlen("sip:");
+	for (; dptr < limit; dptr++) {
+		if (*dptr == '\r' || *dptr == '\n')
+			return -1;
+		if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
+			break;
+	}
+	if (!skp_epaddr_len(ct, dptr, limit, &shift))
+		return 0;
+	dptr += shift;
+
+	if (!parse_addr(ct, dptr, &end, addr, limit))
+		return -1;
+	if (end < limit && *end == ':') {
+		end++;
+		p = simple_strtoul(end, (char **)&end, 10);
+		if (p < 1024 || p > 65535)
+			return -1;
+		*port = htons(p);
+	} else
+		*port = htons(SIP_PORT);
+
+	if (end == dptr)
+		return 0;
+	*matchoff = dptr - start;
+	*matchlen = end - dptr;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_request);
+
+/* SIP header parsing: SIP headers are located at the beginning of a line, but
+ * may span several lines, in which case the continuation lines begin with a
+ * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or
+ * CRLF, RFC 3261 allows only CRLF, we support both.
+ *
+ * Headers are followed by (optionally) whitespace, a colon, again (optionally)
+ * whitespace and the values. Whitespace in this context means any amount of
+ * tabs, spaces and continuation lines, which are treated as a single whitespace
+ * character.
+ *
+ * Some headers may appear multiple times. A comma seperated list of values is
+ * equivalent to multiple headers.
+ */
+static const struct sip_header ct_sip_hdrs[] = {
+	[SIP_HDR_CSEQ]			= SIP_HDR("CSeq", NULL, NULL, digits_len),
+	[SIP_HDR_FROM]			= SIP_HDR("From", "f", "sip:", skp_epaddr_len),
+	[SIP_HDR_TO]			= SIP_HDR("To", "t", "sip:", skp_epaddr_len),
+	[SIP_HDR_CONTACT]		= SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
+	[SIP_HDR_VIA]			= SIP_HDR("Via", "v", "UDP ", epaddr_len),
+	[SIP_HDR_EXPIRES]		= SIP_HDR("Expires", NULL, NULL, digits_len),
+	[SIP_HDR_CONTENT_LENGTH]	= SIP_HDR("Content-Length", "l", NULL, digits_len),
+};
+
+static const char *sip_follow_continuation(const char *dptr, const char *limit)
+{
+	/* Walk past newline */
+	if (++dptr >= limit)
+		return NULL;
+
+	/* Skip '\n' in CR LF */
+	if (*(dptr - 1) == '\r' && *dptr == '\n') {
+		if (++dptr >= limit)
+			return NULL;
+	}
+
+	/* Continuation line? */
+	if (*dptr != ' ' && *dptr != '\t')
+		return NULL;
+
+	/* skip leading whitespace */
+	for (; dptr < limit; dptr++) {
+		if (*dptr != ' ' && *dptr != '\t')
+			break;
+	}
+	return dptr;
+}
+
+static const char *sip_skip_whitespace(const char *dptr, const char *limit)
+{
+	for (; dptr < limit; dptr++) {
+		if (*dptr == ' ')
+			continue;
+		if (*dptr != '\r' && *dptr != '\n')
+			break;
+		dptr = sip_follow_continuation(dptr, limit);
+		if (dptr == NULL)
+			return NULL;
+	}
+	return dptr;
+}
+
+/* Search within a SIP header value, dealing with continuation lines */
+static const char *ct_sip_header_search(const char *dptr, const char *limit,
+					const char *needle, unsigned int len)
+{
+	for (limit -= len; dptr < limit; dptr++) {
+		if (*dptr == '\r' || *dptr == '\n') {
+			dptr = sip_follow_continuation(dptr, limit);
+			if (dptr == NULL)
+				break;
+			continue;
+		}
+
+		if (strnicmp(dptr, needle, len) == 0)
+			return dptr;
+	}
+	return NULL;
+}
+
+int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
+		      unsigned int dataoff, unsigned int datalen,
+		      enum sip_header_types type,
+		      unsigned int *matchoff, unsigned int *matchlen)
+{
+	const struct sip_header *hdr = &ct_sip_hdrs[type];
+	const char *start = dptr, *limit = dptr + datalen;
+	int shift = 0;
 
-	while (dptr <= limit) {
-		if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
-		    (hnfo->sname == NULL ||
-		     strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
-			dptr++;
+	for (dptr += dataoff; dptr < limit; dptr++) {
+		/* Find beginning of line */
+		if (*dptr != '\r' && *dptr != '\n')
 			continue;
+		if (++dptr >= limit)
+			break;
+		if (*(dptr - 1) == '\r' && *dptr == '\n') {
+			if (++dptr >= limit)
+				break;
 		}
-		aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
-				    ct_sip_lnlen(dptr, limit),
-				    hnfo->case_sensitive);
-		if (!aux) {
-			pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str,
-				 hnfo->lname);
-			return -1;
+
+		/* Skip continuation lines */
+		if (*dptr == ' ' || *dptr == '\t')
+			continue;
+
+		/* Find header. Compact headers must be followed by a
+		 * non-alphabetic character to avoid mismatches. */
+		if (limit - dptr >= hdr->len &&
+		    strnicmp(dptr, hdr->name, hdr->len) == 0)
+			dptr += hdr->len;
+		else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
+			 strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
+			 !isalpha(*(dptr + hdr->clen + 1)))
+			dptr += hdr->clen;
+		else
+			continue;
+
+		/* Find and skip colon */
+		dptr = sip_skip_whitespace(dptr, limit);
+		if (dptr == NULL)
+			break;
+		if (*dptr != ':' || ++dptr >= limit)
+			break;
+
+		/* Skip whitespace after colon */
+		dptr = sip_skip_whitespace(dptr, limit);
+		if (dptr == NULL)
+			break;
+
+		*matchoff = dptr - start;
+		if (hdr->search) {
+			dptr = ct_sip_header_search(dptr, limit, hdr->search,
+						    hdr->slen);
+			if (!dptr)
+				return -1;
+			dptr += hdr->slen;
 		}
-		aux += hnfo->ln_strlen;
 
-		*matchlen = hnfo->match_len(ct, aux, limit, &shift);
+		*matchlen = hdr->match_len(ct, dptr, limit, &shift);
 		if (!*matchlen)
 			return -1;
+		*matchoff = dptr - start + shift;
+		return 1;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ct_sip_get_header);
+
+/* Get next header field in a list of comma seperated values */
+static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr,
+			      unsigned int dataoff, unsigned int datalen,
+			      enum sip_header_types type,
+			      unsigned int *matchoff, unsigned int *matchlen)
+{
+	const struct sip_header *hdr = &ct_sip_hdrs[type];
+	const char *start = dptr, *limit = dptr + datalen;
+	int shift = 0;
+
+	dptr += dataoff;
+
+	dptr = ct_sip_header_search(dptr, limit, ",", strlen(","));
+	if (!dptr)
+		return 0;
+
+	dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen);
+	if (!dptr)
+		return 0;
+	dptr += hdr->slen;
+
+	*matchoff = dptr - start;
+	*matchlen = hdr->match_len(ct, dptr, limit, &shift);
+	if (!*matchlen)
+		return -1;
+	*matchoff += shift;
+	return 1;
+}
+
+/* Walk through headers until a parsable one is found or no header of the
+ * given type is left. */
+static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr,
+			       unsigned int dataoff, unsigned int datalen,
+			       enum sip_header_types type, int *in_header,
+			       unsigned int *matchoff, unsigned int *matchlen)
+{
+	int ret;
+
+	if (in_header && *in_header) {
+		while (1) {
+			ret = ct_sip_next_header(ct, dptr, dataoff, datalen,
+						 type, matchoff, matchlen);
+			if (ret > 0)
+				return ret;
+			if (ret == 0)
+				break;
+			dataoff += *matchoff;
+		}
+		*in_header = 0;
+	}
+
+	while (1) {
+		ret = ct_sip_get_header(ct, dptr, dataoff, datalen,
+					type, matchoff, matchlen);
+		if (ret > 0)
+			break;
+		if (ret == 0)
+			return ret;
+		dataoff += *matchoff;
+	}
+
+	if (in_header)
+		*in_header = 1;
+	return 1;
+}
+
+/* Locate a SIP header, parse the URI and return the offset and length of
+ * the address as well as the address and port themselves. A stream of
+ * headers can be parsed by handing in a non-NULL datalen and in_header
+ * pointer.
+ */
+int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
+			    unsigned int *dataoff, unsigned int datalen,
+			    enum sip_header_types type, int *in_header,
+			    unsigned int *matchoff, unsigned int *matchlen,
+			    union nf_inet_addr *addr, __be16 *port)
+{
+	const char *c, *limit = dptr + datalen;
+	unsigned int p;
+	int ret;
+
+	ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
+				  type, in_header, matchoff, matchlen);
+	WARN_ON(ret < 0);
+	if (ret == 0)
+		return ret;
+
+	if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
+		return -1;
+	if (*c == ':') {
+		c++;
+		p = simple_strtoul(c, (char **)&c, 10);
+		if (p < 1024 || p > 65535)
+			return -1;
+		*port = htons(p);
+	} else
+		*port = htons(SIP_PORT);
+
+	if (dataoff)
+		*dataoff = c - dptr;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri);
+
+/* Parse address from header parameter and return address, offset and length */
+int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
+			       unsigned int dataoff, unsigned int datalen,
+			       const char *name,
+			       unsigned int *matchoff, unsigned int *matchlen,
+			       union nf_inet_addr *addr)
+{
+	const char *limit = dptr + datalen;
+	const char *start, *end;
+
+	limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
+	if (!limit)
+		limit = dptr + datalen;
+
+	start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
+	if (!start)
+		return 0;
+
+	start += strlen(name);
+	if (!parse_addr(ct, start, &end, addr, limit))
+		return 0;
+	*matchoff = start - dptr;
+	*matchlen = end - start;
+	return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_address_param);
+
+/* Parse numerical header parameter and return value, offset and length */
+int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
+				 unsigned int dataoff, unsigned int datalen,
+				 const char *name,
+				 unsigned int *matchoff, unsigned int *matchlen,
+				 unsigned int *val)
+{
+	const char *limit = dptr + datalen;
+	const char *start;
+	char *end;
+
+	limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
+	if (!limit)
+		limit = dptr + datalen;
+
+	start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
+	if (!start)
+		return 0;
+
+	start += strlen(name);
+	*val = simple_strtoul(start, &end, 0);
+	if (start == end)
+		return 0;
+	if (matchoff && matchlen) {
+		*matchoff = start - dptr;
+		*matchlen = end - start;
+	}
+	return 1;
+}
+EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param);
+
+/* SDP header parsing: a SDP session description contains an ordered set of
+ * headers, starting with a section containing general session parameters,
+ * optionally followed by multiple media descriptions.
+ *
+ * SDP headers always start at the beginning of a line. According to RFC 2327:
+ * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should
+ * be tolerant and also accept records terminated with a single newline
+ * character". We handle both cases.
+ */
+static const struct sip_header ct_sdp_hdrs[] = {
+	[SDP_HDR_VERSION]		= SDP_HDR("v=", NULL, digits_len),
+	[SDP_HDR_OWNER_IP4]		= SDP_HDR("o=", "IN IP4 ", epaddr_len),
+	[SDP_HDR_CONNECTION_IP4]	= SDP_HDR("c=", "IN IP4 ", epaddr_len),
+	[SDP_HDR_OWNER_IP6]		= SDP_HDR("o=", "IN IP6 ", epaddr_len),
+	[SDP_HDR_CONNECTION_IP6]	= SDP_HDR("c=", "IN IP6 ", epaddr_len),
+	[SDP_HDR_MEDIA]			= SDP_HDR("m=", NULL, media_len),
+};
+
+/* Linear string search within SDP header values */
+static const char *ct_sdp_header_search(const char *dptr, const char *limit,
+					const char *needle, unsigned int len)
+{
+	for (limit -= len; dptr < limit; dptr++) {
+		if (*dptr == '\r' || *dptr == '\n')
+			break;
+		if (strncmp(dptr, needle, len) == 0)
+			return dptr;
+	}
+	return NULL;
+}
+
+/* Locate a SDP header (optionally a substring within the header value),
+ * optionally stopping at the first occurence of the term header, parse
+ * it and return the offset and length of the data we're interested in.
+ */
+int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
+			  unsigned int dataoff, unsigned int datalen,
+			  enum sdp_header_types type,
+			  enum sdp_header_types term,
+			  unsigned int *matchoff, unsigned int *matchlen)
+{
+	const struct sip_header *hdr = &ct_sdp_hdrs[type];
+	const struct sip_header *thdr = &ct_sdp_hdrs[term];
+	const char *start = dptr, *limit = dptr + datalen;
+	int shift = 0;
+
+	for (dptr += dataoff; dptr < limit; dptr++) {
+		/* Find beginning of line */
+		if (*dptr != '\r' && *dptr != '\n')
+			continue;
+		if (++dptr >= limit)
+			break;
+		if (*(dptr - 1) == '\r' && *dptr == '\n') {
+			if (++dptr >= limit)
+				break;
+		}
 
-		*matchoff = (aux - k) + shift;
+		if (term != SDP_HDR_UNSPEC &&
+		    limit - dptr >= thdr->len &&
+		    strnicmp(dptr, thdr->name, thdr->len) == 0)
+			break;
+		else if (limit - dptr >= hdr->len &&
+			 strnicmp(dptr, hdr->name, hdr->len) == 0)
+			dptr += hdr->len;
+		else
+			continue;
 
-		pr_debug("%s match succeeded! - len: %u\n", hnfo->lname,
-			 *matchlen);
+		*matchoff = dptr - start;
+		if (hdr->search) {
+			dptr = ct_sdp_header_search(dptr, limit, hdr->search,
+						    hdr->slen);
+			if (!dptr)
+				return -1;
+			dptr += hdr->slen;
+		}
+
+		*matchlen = hdr->match_len(ct, dptr, limit, &shift);
+		if (!*matchlen)
+			return -1;
+		*matchoff = dptr - start + shift;
 		return 1;
 	}
-	pr_debug("%s header not found.\n", hnfo->lname);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(ct_sip_get_info);
+EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
+
+static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr,
+				 unsigned int dataoff, unsigned int datalen,
+				 enum sdp_header_types type,
+				 enum sdp_header_types term,
+				 unsigned int *matchoff, unsigned int *matchlen,
+				 union nf_inet_addr *addr)
+{
+	int ret;
+
+	ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term,
+				    matchoff, matchlen);
+	if (ret <= 0)
+		return ret;
+
+	if (!parse_addr(ct, dptr + *matchoff, NULL, addr,
+			dptr + *matchoff + *matchlen))
+		return -1;
+	return 1;
+}
+
+static int refresh_signalling_expectation(struct nf_conn *ct,
+					  union nf_inet_addr *addr,
+					  __be16 port,
+					  unsigned int expires)
+{
+	struct nf_conn_help *help = nfct_help(ct);
+	struct nf_conntrack_expect *exp;
+	struct hlist_node *n, *next;
+	int found = 0;
+
+	spin_lock_bh(&nf_conntrack_lock);
+	hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+		if (exp->class != SIP_EXPECT_SIGNALLING ||
+		    !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) ||
+		    exp->tuple.dst.u.udp.port != port)
+			continue;
+		if (!del_timer(&exp->timeout))
+			continue;
+		exp->flags &= ~NF_CT_EXPECT_INACTIVE;
+		exp->timeout.expires = jiffies + expires * HZ;
+		add_timer(&exp->timeout);
+		found = 1;
+		break;
+	}
+	spin_unlock_bh(&nf_conntrack_lock);
+	return found;
+}
 
-static int set_expected_rtp(struct sk_buff *skb,
-			    struct nf_conn *ct,
-			    enum ip_conntrack_info ctinfo,
-			    union nf_inet_addr *addr,
-			    __be16 port,
-			    const char *dptr)
+static void flush_expectations(struct nf_conn *ct, bool media)
 {
+	struct nf_conn_help *help = nfct_help(ct);
 	struct nf_conntrack_expect *exp;
+	struct hlist_node *n, *next;
+
+	spin_lock_bh(&nf_conntrack_lock);
+	hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+		if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media)
+			continue;
+		if (!del_timer(&exp->timeout))
+			continue;
+		nf_ct_unlink_expect(exp);
+		nf_ct_expect_put(exp);
+		if (!media)
+			break;
+	}
+	spin_unlock_bh(&nf_conntrack_lock);
+}
+
+static int set_expected_rtp_rtcp(struct sk_buff *skb,
+				 const char **dptr, unsigned int *datalen,
+				 union nf_inet_addr *daddr, __be16 port,
+				 enum sip_expectation_classes class,
+				 unsigned int mediaoff, unsigned int medialen)
+{
+	struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	union nf_inet_addr *saddr;
+	struct nf_conntrack_tuple tuple;
 	int family = ct->tuplehash[!dir].tuple.src.l3num;
+	int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
+	u_int16_t base_port;
+	__be16 rtp_port, rtcp_port;
+	typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
+	typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
+
+	saddr = NULL;
+	if (sip_direct_media) {
+		if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3))
+			return NF_ACCEPT;
+		saddr = &ct->tuplehash[!dir].tuple.src.u3;
+	}
+
+	/* We need to check whether the registration exists before attempting
+	 * to register it since we can see the same media description multiple
+	 * times on different connections in case multiple endpoints receive
+	 * the same call.
+	 *
+	 * RTP optimization: if we find a matching media channel expectation
+	 * and both the expectation and this connection are SNATed, we assume
+	 * both sides can reach each other directly and use the final
+	 * destination address from the expectation. We still need to keep
+	 * the NATed expectations for media that might arrive from the
+	 * outside, and additionally need to expect the direct RTP stream
+	 * in case it passes through us even without NAT.
+	 */
+	memset(&tuple, 0, sizeof(tuple));
+	if (saddr)
+		tuple.src.u3 = *saddr;
+	tuple.src.l3num		= family;
+	tuple.dst.protonum	= IPPROTO_UDP;
+	tuple.dst.u3		= *daddr;
+	tuple.dst.u.udp.port	= port;
+
+	rcu_read_lock();
+	do {
+		exp = __nf_ct_expect_find(&tuple);
+
+		if (!exp || exp->master == ct ||
+		    nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
+		    exp->class != class)
+			break;
+
+		if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
+		    (exp->saved_ip != exp->tuple.dst.u3.ip ||
+		     exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
+		    ct->status & IPS_NAT_MASK) {
+			daddr->ip		= exp->saved_ip;
+			tuple.dst.u3.ip		= exp->saved_ip;
+			tuple.dst.u.udp.port	= exp->saved_proto.udp.port;
+			direct_rtp = 1;
+		} else
+			skip_expect = 1;
+	} while (!skip_expect);
+	rcu_read_unlock();
+
+	base_port = ntohs(tuple.dst.u.udp.port) & ~1;
+	rtp_port = htons(base_port);
+	rtcp_port = htons(base_port + 1);
+
+	if (direct_rtp) {
+		nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
+		if (nf_nat_sdp_port &&
+		    !nf_nat_sdp_port(skb, dptr, datalen,
+				     mediaoff, medialen, ntohs(rtp_port)))
+			goto err1;
+	}
+
+	if (skip_expect)
+		return NF_ACCEPT;
+
+	rtp_exp = nf_ct_expect_alloc(ct);
+	if (rtp_exp == NULL)
+		goto err1;
+	nf_ct_expect_init(rtp_exp, class, family, saddr, daddr,
+			  IPPROTO_UDP, NULL, &rtp_port);
+
+	rtcp_exp = nf_ct_expect_alloc(ct);
+	if (rtcp_exp == NULL)
+		goto err2;
+	nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr,
+			  IPPROTO_UDP, NULL, &rtcp_port);
+
+	nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
+	if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
+		ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp,
+				       mediaoff, medialen, daddr);
+	else {
+		if (nf_ct_expect_related(rtp_exp) == 0) {
+			if (nf_ct_expect_related(rtcp_exp) != 0)
+				nf_ct_unexpect_related(rtp_exp);
+			else
+				ret = NF_ACCEPT;
+		}
+	}
+	nf_ct_expect_put(rtcp_exp);
+err2:
+	nf_ct_expect_put(rtp_exp);
+err1:
+	return ret;
+}
+
+static const struct sdp_media_type sdp_media_types[] = {
+	SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO),
+	SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO),
+};
+
+static const struct sdp_media_type *sdp_media_type(const char *dptr,
+						   unsigned int matchoff,
+						   unsigned int matchlen)
+{
+	const struct sdp_media_type *t;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) {
+		t = &sdp_media_types[i];
+		if (matchlen < t->len ||
+		    strncmp(dptr + matchoff, t->name, t->len))
+			continue;
+		return t;
+	}
+	return NULL;
+}
+
+static int process_sdp(struct sk_buff *skb,
+		       const char **dptr, unsigned int *datalen,
+		       unsigned int cseq)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+	unsigned int matchoff, matchlen;
+	unsigned int mediaoff, medialen;
+	unsigned int sdpoff;
+	unsigned int caddr_len, maddr_len;
+	unsigned int i;
+	union nf_inet_addr caddr, maddr, rtp_addr;
+	unsigned int port;
+	enum sdp_header_types c_hdr;
+	const struct sdp_media_type *t;
+	int ret = NF_ACCEPT;
+	typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
+	typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
+
+	nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
+	c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
+				    SDP_HDR_CONNECTION_IP6;
+
+	/* Find beginning of session description */
+	if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
+				  SDP_HDR_VERSION, SDP_HDR_UNSPEC,
+				  &matchoff, &matchlen) <= 0)
+		return NF_ACCEPT;
+	sdpoff = matchoff;
+
+	/* The connection information is contained in the session description
+	 * and/or once per media description. The first media description marks
+	 * the end of the session description. */
+	caddr_len = 0;
+	if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen,
+				  c_hdr, SDP_HDR_MEDIA,
+				  &matchoff, &matchlen, &caddr) > 0)
+		caddr_len = matchlen;
+
+	mediaoff = sdpoff;
+	for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
+		if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
+					  SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
+					  &mediaoff, &medialen) <= 0)
+			break;
+
+		/* Get media type and port number. A media port value of zero
+		 * indicates an inactive stream. */
+		t = sdp_media_type(*dptr, mediaoff, medialen);
+		if (!t) {
+			mediaoff += medialen;
+			continue;
+		}
+		mediaoff += t->len;
+		medialen -= t->len;
+
+		port = simple_strtoul(*dptr + mediaoff, NULL, 10);
+		if (port == 0)
+			continue;
+		if (port < 1024 || port > 65535)
+			return NF_DROP;
+
+		/* The media description overrides the session description. */
+		maddr_len = 0;
+		if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen,
+					  c_hdr, SDP_HDR_MEDIA,
+					  &matchoff, &matchlen, &maddr) > 0) {
+			maddr_len = matchlen;
+			memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
+		} else if (caddr_len)
+			memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
+		else
+			return NF_DROP;
+
+		ret = set_expected_rtp_rtcp(skb, dptr, datalen,
+					    &rtp_addr, htons(port), t->class,
+					    mediaoff, medialen);
+		if (ret != NF_ACCEPT)
+			return ret;
+
+		/* Update media connection address if present */
+		if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+			ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen,
+					      c_hdr, SDP_HDR_MEDIA, &rtp_addr);
+			if (ret != NF_ACCEPT)
+				return ret;
+		}
+		i++;
+	}
+
+	/* Update session connection and owner addresses */
+	nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
+	if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
+		ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr);
+
+	return ret;
+}
+static int process_invite_response(struct sk_buff *skb,
+				   const char **dptr, unsigned int *datalen,
+				   unsigned int cseq, unsigned int code)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	if ((code >= 100 && code <= 199) ||
+	    (code >= 200 && code <= 299))
+		return process_sdp(skb, dptr, datalen, cseq);
+	else {
+		flush_expectations(ct, true);
+		return NF_ACCEPT;
+	}
+}
+
+static int process_update_response(struct sk_buff *skb,
+				   const char **dptr, unsigned int *datalen,
+				   unsigned int cseq, unsigned int code)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	if ((code >= 100 && code <= 199) ||
+	    (code >= 200 && code <= 299))
+		return process_sdp(skb, dptr, datalen, cseq);
+	else {
+		flush_expectations(ct, true);
+		return NF_ACCEPT;
+	}
+}
+
+static int process_prack_response(struct sk_buff *skb,
+				  const char **dptr, unsigned int *datalen,
+				  unsigned int cseq, unsigned int code)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	if ((code >= 100 && code <= 199) ||
+	    (code >= 200 && code <= 299))
+		return process_sdp(skb, dptr, datalen, cseq);
+	else {
+		flush_expectations(ct, true);
+		return NF_ACCEPT;
+	}
+}
+
+static int process_bye_request(struct sk_buff *skb,
+			       const char **dptr, unsigned int *datalen,
+			       unsigned int cseq)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+
+	flush_expectations(ct, true);
+	return NF_ACCEPT;
+}
+
+/* Parse a REGISTER request and create a permanent expectation for incoming
+ * signalling connections. The expectation is marked inactive and is activated
+ * when receiving a response indicating success from the registrar.
+ */
+static int process_register_request(struct sk_buff *skb,
+				    const char **dptr, unsigned int *datalen,
+				    unsigned int cseq)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
+	unsigned int matchoff, matchlen;
+	struct nf_conntrack_expect *exp;
+	union nf_inet_addr *saddr, daddr;
+	__be16 port;
+	unsigned int expires = 0;
 	int ret;
-	typeof(nf_nat_sdp_hook) nf_nat_sdp;
+	typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect;
+
+	/* Expected connections can not register again. */
+	if (ct->status & IPS_EXPECTED)
+		return NF_ACCEPT;
+
+	/* We must check the expiration time: a value of zero signals the
+	 * registrar to release the binding. We'll remove our expectation
+	 * when receiving the new bindings in the response, but we don't
+	 * want to create new ones.
+	 *
+	 * The expiration time may be contained in Expires: header, the
+	 * Contact: header parameters or the URI parameters.
+	 */
+	if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
+			      &matchoff, &matchlen) > 0)
+		expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+
+	ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
+				      SIP_HDR_CONTACT, NULL,
+				      &matchoff, &matchlen, &daddr, &port);
+	if (ret < 0)
+		return NF_DROP;
+	else if (ret == 0)
+		return NF_ACCEPT;
+
+	/* We don't support third-party registrations */
+	if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr))
+		return NF_ACCEPT;
+
+	if (ct_sip_parse_numerical_param(ct, *dptr,
+					 matchoff + matchlen, *datalen,
+					 "expires=", NULL, NULL, &expires) < 0)
+		return NF_DROP;
+
+	if (expires == 0) {
+		ret = NF_ACCEPT;
+		goto store_cseq;
+	}
 
 	exp = nf_ct_expect_alloc(ct);
-	if (exp == NULL)
+	if (!exp)
 		return NF_DROP;
-	nf_ct_expect_init(exp, family,
-			  &ct->tuplehash[!dir].tuple.src.u3, addr,
+
+	saddr = NULL;
+	if (sip_direct_signalling)
+		saddr = &ct->tuplehash[!dir].tuple.src.u3;
+
+	nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr,
 			  IPPROTO_UDP, NULL, &port);
+	exp->timeout.expires = sip_timeout * HZ;
+	exp->helper = nfct_help(ct)->helper;
+	exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
 
-	nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
-	if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
-		ret = nf_nat_sdp(skb, ctinfo, exp, dptr);
+	nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
+	if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
+		ret = nf_nat_sip_expect(skb, dptr, datalen, exp,
+					matchoff, matchlen);
 	else {
 		if (nf_ct_expect_related(exp) != 0)
 			ret = NF_DROP;
@@ -395,22 +1106,160 @@ static int set_expected_rtp(struct sk_buff *skb,
 	}
 	nf_ct_expect_put(exp);
 
+store_cseq:
+	if (ret == NF_ACCEPT)
+		help->help.ct_sip_info.register_cseq = cseq;
 	return ret;
 }
 
+static int process_register_response(struct sk_buff *skb,
+				     const char **dptr, unsigned int *datalen,
+				     unsigned int cseq, unsigned int code)
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	struct nf_conn_help *help = nfct_help(ct);
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+	union nf_inet_addr addr;
+	__be16 port;
+	unsigned int matchoff, matchlen, dataoff = 0;
+	unsigned int expires = 0;
+	int in_contact = 0, ret;
+
+	/* According to RFC 3261, "UAs MUST NOT send a new registration until
+	 * they have received a final response from the registrar for the
+	 * previous one or the previous REGISTER request has timed out".
+	 *
+	 * However, some servers fail to detect retransmissions and send late
+	 * responses, so we store the sequence number of the last valid
+	 * request and compare it here.
+	 */
+	if (help->help.ct_sip_info.register_cseq != cseq)
+		return NF_ACCEPT;
+
+	if (code >= 100 && code <= 199)
+		return NF_ACCEPT;
+	if (code < 200 || code > 299)
+		goto flush;
+
+	if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES,
+			      &matchoff, &matchlen) > 0)
+		expires = simple_strtoul(*dptr + matchoff, NULL, 10);
+
+	while (1) {
+		unsigned int c_expires = expires;
+
+		ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
+					      SIP_HDR_CONTACT, &in_contact,
+					      &matchoff, &matchlen,
+					      &addr, &port);
+		if (ret < 0)
+			return NF_DROP;
+		else if (ret == 0)
+			break;
+
+		/* We don't support third-party registrations */
+		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr))
+			continue;
+
+		ret = ct_sip_parse_numerical_param(ct, *dptr,
+						   matchoff + matchlen,
+						   *datalen, "expires=",
+						   NULL, NULL, &c_expires);
+		if (ret < 0)
+			return NF_DROP;
+		if (c_expires == 0)
+			break;
+		if (refresh_signalling_expectation(ct, &addr, port, c_expires))
+			return NF_ACCEPT;
+	}
+
+flush:
+	flush_expectations(ct, false);
+	return NF_ACCEPT;
+}
+
+static const struct sip_handler sip_handlers[] = {
+	SIP_HANDLER("INVITE", process_sdp, process_invite_response),
+	SIP_HANDLER("UPDATE", process_sdp, process_update_response),
+	SIP_HANDLER("ACK", process_sdp, NULL),
+	SIP_HANDLER("PRACK", process_sdp, process_prack_response),
+	SIP_HANDLER("BYE", process_bye_request, NULL),
+	SIP_HANDLER("REGISTER", process_register_request, process_register_response),
+};
+
+static int process_sip_response(struct sk_buff *skb,
+				const char **dptr, unsigned int *datalen)
+{
+	static const struct sip_handler *handler;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	unsigned int matchoff, matchlen;
+	unsigned int code, cseq, dataoff, i;
+
+	if (*datalen < strlen("SIP/2.0 200"))
+		return NF_ACCEPT;
+	code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
+	if (!code)
+		return NF_DROP;
+
+	if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
+			      &matchoff, &matchlen) <= 0)
+		return NF_DROP;
+	cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
+	if (!cseq)
+		return NF_DROP;
+	dataoff = matchoff + matchlen + 1;
+
+	for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+		handler = &sip_handlers[i];
+		if (handler->response == NULL)
+			continue;
+		if (*datalen < dataoff + handler->len ||
+		    strnicmp(*dptr + dataoff, handler->method, handler->len))
+			continue;
+		return handler->response(skb, dptr, datalen, cseq, code);
+	}
+	return NF_ACCEPT;
+}
+
+static int process_sip_request(struct sk_buff *skb,
+			       const char **dptr, unsigned int *datalen)
+{
+	static const struct sip_handler *handler;
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	unsigned int matchoff, matchlen;
+	unsigned int cseq, i;
+
+	for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
+		handler = &sip_handlers[i];
+		if (handler->request == NULL)
+			continue;
+		if (*datalen < handler->len ||
+		    strnicmp(*dptr, handler->method, handler->len))
+			continue;
+
+		if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
+				      &matchoff, &matchlen) <= 0)
+			return NF_DROP;
+		cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
+		if (!cseq)
+			return NF_DROP;
+
+		return handler->request(skb, dptr, datalen, cseq);
+	}
+	return NF_ACCEPT;
+}
+
 static int sip_help(struct sk_buff *skb,
 		    unsigned int protoff,
 		    struct nf_conn *ct,
 		    enum ip_conntrack_info ctinfo)
 {
-	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
-	union nf_inet_addr addr;
 	unsigned int dataoff, datalen;
 	const char *dptr;
-	int ret = NF_ACCEPT;
-	unsigned int matchoff, matchlen;
-	u_int16_t port;
-	enum sip_header_pos pos;
+	int ret;
 	typeof(nf_nat_sip_hook) nf_nat_sip;
 
 	/* No Data ? */
@@ -424,58 +1273,45 @@ static int sip_help(struct sk_buff *skb,
 		dptr = skb->data + dataoff;
 	else {
 		pr_debug("Copy of skbuff not supported yet.\n");
-		goto out;
-	}
-
-	nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
-	if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
-		if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) {
-			ret = NF_DROP;
-			goto out;
-		}
+		return NF_ACCEPT;
 	}
 
 	datalen = skb->len - dataoff;
-	if (datalen < sizeof("SIP/2.0 200") - 1)
-		goto out;
-
-	/* RTP info only in some SDP pkts */
-	if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
-	    memcmp(dptr, "UPDATE", sizeof("UPDATE") - 1) != 0 &&
-	    memcmp(dptr, "SIP/2.0 180", sizeof("SIP/2.0 180") - 1) != 0 &&
-	    memcmp(dptr, "SIP/2.0 183", sizeof("SIP/2.0 183") - 1) != 0 &&
-	    memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
-		goto out;
-	}
-	/* Get address and port from SDP packet. */
-	pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6;
-	if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) {
-
-		/* We'll drop only if there are parse problems. */
-		if (!parse_addr(ct, dptr + matchoff, NULL, &addr,
-				dptr + datalen)) {
-			ret = NF_DROP;
-			goto out;
-		}
-		if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen,
-				    POS_MEDIA) > 0) {
+	if (datalen < strlen("SIP/2.0 200"))
+		return NF_ACCEPT;
 
-			port = simple_strtoul(dptr + matchoff, NULL, 10);
-			if (port < 1024) {
-				ret = NF_DROP;
-				goto out;
-			}
-			ret = set_expected_rtp(skb, ct, ctinfo, &addr,
-					       htons(port), dptr);
-		}
+	if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
+		ret = process_sip_request(skb, &dptr, &datalen);
+	else
+		ret = process_sip_response(skb, &dptr, &datalen);
+
+	if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
+		nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
+		if (nf_nat_sip && !nf_nat_sip(skb, &dptr, &datalen))
+			ret = NF_DROP;
 	}
-out:
+
 	return ret;
 }
 
 static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
 static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
 
+static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
+	[SIP_EXPECT_SIGNALLING] = {
+		.max_expected	= 1,
+		.timeout	= 3 * 60,
+	},
+	[SIP_EXPECT_AUDIO] = {
+		.max_expected	= 2 * IP_CT_DIR_MAX,
+		.timeout	= 3 * 60,
+	},
+	[SIP_EXPECT_VIDEO] = {
+		.max_expected	= 2 * IP_CT_DIR_MAX,
+		.timeout	= 3 * 60,
+	},
+};
+
 static void nf_conntrack_sip_fini(void)
 {
 	int i, j;
@@ -505,8 +1341,8 @@ static int __init nf_conntrack_sip_init(void)
 		for (j = 0; j < 2; j++) {
 			sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
 			sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
-			sip[i][j].max_expected = 2;
-			sip[i][j].timeout = 3 * 60; /* 3 minutes */
+			sip[i][j].expect_policy = sip_exp_policy;
+			sip[i][j].expect_class_max = SIP_EXPECT_MAX;
 			sip[i][j].me = THIS_MODULE;
 			sip[i][j].help = sip_help;
 
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 8599068050ec..9d0b8bb4113c 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -293,7 +293,7 @@ static const struct file_operations ct_cpu_seq_fops = {
 	.open	 = ct_cpu_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
-	.release = seq_release_private,
+	.release = seq_release,
 };
 #endif /* CONFIG_PROC_FS */
 
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index bd2e800f23cc..a28341b30f21 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -63,7 +63,8 @@ static int tftp_help(struct sk_buff *skb,
 		if (exp == NULL)
 			return NF_DROP;
 		tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
-		nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
+				  &tuple->src.u3, &tuple->dst.u3,
 				  IPPROTO_UDP, NULL, &tuple->dst.u.udp.port);
 
 		pr_debug("expect: ");
@@ -92,6 +93,11 @@ static int tftp_help(struct sk_buff *skb,
 static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly;
 static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly;
 
+static const struct nf_conntrack_expect_policy tftp_exp_policy = {
+	.max_expected	= 1,
+	.timeout	= 5 * 60,
+};
+
 static void nf_conntrack_tftp_fini(void)
 {
 	int i, j;
@@ -118,8 +124,7 @@ static int __init nf_conntrack_tftp_init(void)
 		for (j = 0; j < 2; j++) {
 			tftp[i][j].tuple.dst.protonum = IPPROTO_UDP;
 			tftp[i][j].tuple.src.u.udp.port = htons(ports[i]);
-			tftp[i][j].max_expected = 1;
-			tftp[i][j].timeout = 5 * 60; /* 5 minutes */
+			tftp[i][j].expect_policy = &tftp_exp_policy;
 			tftp[i][j].me = THIS_MODULE;
 			tftp[i][j].help = tftp_help;
 
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c
index 3dd4b3c76d81..69d699f95f4c 100644
--- a/net/netfilter/nf_sockopt.c
+++ b/net/netfilter/nf_sockopt.c
@@ -65,7 +65,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf,
 {
 	struct nf_sockopt_ops *ops;
 
-	if (sk->sk_net != &init_net)
+	if (sock_net(sk) != &init_net)
 		return ERR_PTR(-ENOPROTOOPT);
 
 	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 10522c04ed24..2c9fe5c12894 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -557,7 +557,7 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* Drop any packets associated with the downed device */
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index a6792089fcf9..0bd95680a494 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -727,7 +727,7 @@ struct xt_names_priv {
 static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	struct xt_names_priv *priv = seq->private;
-	struct net *net = priv->p.net;
+	struct net *net = seq_file_net(seq);
 	int af = priv->af;
 
 	mutex_lock(&xt[af].mutex);
@@ -737,7 +737,7 @@ static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos)
 static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
 	struct xt_names_priv *priv = seq->private;
-	struct net *net = priv->p.net;
+	struct net *net = seq_file_net(seq);
 	int af = priv->af;
 
 	return seq_list_next(v, &net->xt.tables[af], pos);
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 4478f2f6079d..a547c6320eb3 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -954,7 +954,7 @@ static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,
 	struct net_device *dev = ptr;
 	struct netlbl_unlhsh_iface *iface = NULL;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	/* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1ab0da2632e1..36f75d873898 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -228,7 +228,7 @@ static inline struct sock *netlink_lookup(struct net *net, int protocol,
 	read_lock(&nl_table_lock);
 	head = nl_pid_hashfn(hash, pid);
 	sk_for_each(sk, node, head) {
-		if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) {
+		if (net_eq(sock_net(sk), net) && (nlk_sk(sk)->pid == pid)) {
 			sock_hold(sk);
 			goto found;
 		}
@@ -348,7 +348,7 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 pid)
 	head = nl_pid_hashfn(hash, pid);
 	len = 0;
 	sk_for_each(osk, node, head) {
-		if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid))
+		if (net_eq(sock_net(osk), net) && (nlk_sk(osk)->pid == pid))
 			break;
 		len++;
 	}
@@ -486,7 +486,7 @@ static int netlink_release(struct socket *sock)
 
 	if (nlk->pid && !nlk->subscriptions) {
 		struct netlink_notify n = {
-						.net = sk->sk_net,
+						.net = sock_net(sk),
 						.protocol = sk->sk_protocol,
 						.pid = nlk->pid,
 					  };
@@ -518,7 +518,7 @@ static int netlink_release(struct socket *sock)
 static int netlink_autobind(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash;
 	struct hlist_head *head;
 	struct sock *osk;
@@ -532,7 +532,7 @@ retry:
 	netlink_table_grab();
 	head = nl_pid_hashfn(hash, pid);
 	sk_for_each(osk, node, head) {
-		if ((osk->sk_net != net))
+		if (!net_eq(sock_net(osk), net))
 			continue;
 		if (nlk_sk(osk)->pid == pid) {
 			/* Bind collision, search negative pid values. */
@@ -611,7 +611,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
 			int addr_len)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct netlink_sock *nlk = nlk_sk(sk);
 	struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
 	int err;
@@ -720,7 +720,7 @@ static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid)
 	struct sock *sock;
 	struct netlink_sock *nlk;
 
-	sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid);
+	sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, pid);
 	if (!sock)
 		return ERR_PTR(-ECONNREFUSED);
 
@@ -886,6 +886,13 @@ retry:
 	if (netlink_is_kernel(sk))
 		return netlink_unicast_kernel(sk, skb);
 
+	if (sk_filter(sk, skb)) {
+		int err = skb->len;
+		kfree_skb(skb);
+		sock_put(sk);
+		return err;
+	}
+
 	err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk);
 	if (err == 1)
 		goto retry;
@@ -955,7 +962,7 @@ static inline int do_one_broadcast(struct sock *sk,
 	    !test_bit(p->group - 1, nlk->groups))
 		goto out;
 
-	if ((sk->sk_net != p->net))
+	if (!net_eq(sock_net(sk), p->net))
 		goto out;
 
 	if (p->failure) {
@@ -980,6 +987,9 @@ static inline int do_one_broadcast(struct sock *sk,
 		netlink_overrun(sk);
 		/* Clone failed. Notify ALL listeners. */
 		p->failure = 1;
+	} else if (sk_filter(sk, p->skb2)) {
+		kfree_skb(p->skb2);
+		p->skb2 = NULL;
 	} else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {
 		netlink_overrun(sk);
 	} else {
@@ -996,7 +1006,7 @@ out:
 int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
 		      u32 group, gfp_t allocation)
 {
-	struct net *net = ssk->sk_net;
+	struct net *net = sock_net(ssk);
 	struct netlink_broadcast_data info;
 	struct hlist_node *node;
 	struct sock *sk;
@@ -1054,7 +1064,7 @@ static inline int do_one_set_err(struct sock *sk,
 	if (sk == p->exclude_sk)
 		goto out;
 
-	if (sk->sk_net != p->exclude_sk->sk_net)
+	if (sock_net(sk) != sock_net(p->exclude_sk))
 		goto out;
 
 	if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups ||
@@ -1344,22 +1354,6 @@ static void netlink_data_ready(struct sock *sk, int len)
  *	queueing.
  */
 
-static void __netlink_release(struct sock *sk)
-{
-	/*
-	 * Last sock_put should drop referrence to sk->sk_net. It has already
-	 * been dropped in netlink_kernel_create. Taking referrence to stopping
-	 * namespace is not an option.
-	 * Take referrence to a socket to remove it from netlink lookup table
-	 * _alive_ and after that destroy it in the context of init_net.
-	 */
-
-	sock_hold(sk);
-	sock_release(sk->sk_socket);
-	sk->sk_net = get_net(&init_net);
-	sock_put(sk);
-}
-
 struct sock *
 netlink_kernel_create(struct net *net, int unit, unsigned int groups,
 		      void (*input)(struct sk_buff *skb),
@@ -1388,8 +1382,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
 		goto out_sock_release_nosk;
 
 	sk = sock->sk;
-	put_net(sk->sk_net);
-	sk->sk_net = net;
+	sk_change_net(sk, net);
 
 	if (groups < 32)
 		groups = 32;
@@ -1424,7 +1417,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups,
 
 out_sock_release:
 	kfree(listeners);
-	__netlink_release(sk);
+	netlink_kernel_release(sk);
 	return NULL;
 
 out_sock_release_nosk:
@@ -1437,10 +1430,7 @@ EXPORT_SYMBOL(netlink_kernel_create);
 void
 netlink_kernel_release(struct sock *sk)
 {
-	if (sk == NULL || sk->sk_socket == NULL)
-		return;
-
-	__netlink_release(sk);
+	sk_release_kernel(sk);
 }
 EXPORT_SYMBOL(netlink_kernel_release);
 
@@ -1553,8 +1543,13 @@ static int netlink_dump(struct sock *sk)
 
 	if (len > 0) {
 		mutex_unlock(nlk->cb_mutex);
-		skb_queue_tail(&sk->sk_receive_queue, skb);
-		sk->sk_data_ready(sk, len);
+
+		if (sk_filter(sk, skb))
+			kfree_skb(skb);
+		else {
+			skb_queue_tail(&sk->sk_receive_queue, skb);
+			sk->sk_data_ready(sk, skb->len);
+		}
 		return 0;
 	}
 
@@ -1564,8 +1559,12 @@ static int netlink_dump(struct sock *sk)
 
 	memcpy(nlmsg_data(nlh), &len, sizeof(len));
 
-	skb_queue_tail(&sk->sk_receive_queue, skb);
-	sk->sk_data_ready(sk, skb->len);
+	if (sk_filter(sk, skb))
+		kfree_skb(skb);
+	else {
+		skb_queue_tail(&sk->sk_receive_queue, skb);
+		sk->sk_data_ready(sk, skb->len);
+	}
 
 	if (cb->done)
 		cb->done(cb);
@@ -1602,7 +1601,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
 	atomic_inc(&skb->users);
 	cb->skb = skb;
 
-	sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid);
+	sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid);
 	if (sk == NULL) {
 		netlink_destroy_callback(cb);
 		return -ECONNREFUSED;
@@ -1644,7 +1643,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err)
 	if (!skb) {
 		struct sock *sk;
 
-		sk = netlink_lookup(in_skb->sk->sk_net,
+		sk = netlink_lookup(sock_net(in_skb->sk),
 				    in_skb->sk->sk_protocol,
 				    NETLINK_CB(in_skb).pid);
 		if (sk) {
@@ -1759,7 +1758,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos)
 
 		for (j = 0; j <= hash->mask; j++) {
 			sk_for_each(s, node, &hash->table[j]) {
-				if (iter->p.net != s->sk_net)
+				if (sock_net(s) != seq_file_net(seq))
 					continue;
 				if (off == pos) {
 					iter->link = i;
@@ -1795,7 +1794,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 	s = v;
 	do {
 		s = sk_next(s);
-	} while (s && (iter->p.net != s->sk_net));
+	} while (s && sock_net(s) != seq_file_net(seq));
 	if (s)
 		return s;
 
@@ -1807,7 +1806,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 
 		for (; j <= hash->mask; j++) {
 			s = sk_head(&hash->table[j]);
-			while (s && (iter->p.net != s->sk_net))
+			while (s && sock_net(s) != seq_file_net(seq))
 				s = sk_next(s);
 			if (s) {
 				iter->link = i;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 972250c974f1..4bae8b998cab 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -106,7 +106,7 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event != NETDEV_DOWN)
@@ -466,7 +466,7 @@ static struct sock *nr_make_new(struct sock *osk)
 	if (osk->sk_type != SOCK_SEQPACKET)
 		return NULL;
 
-	sk = sk_alloc(osk->sk_net, PF_NETROM, GFP_ATOMIC, osk->sk_prot);
+	sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot);
 	if (sk == NULL)
 		return NULL;
 
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b8b827c7062d..25070240d4ae 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -263,7 +263,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,  struct
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		goto out;
 
-	if (dev->nd_net != sk->sk_net)
+	if (dev_net(dev) != sock_net(sk))
 		goto out;
 
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
@@ -337,7 +337,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
 	 */
 
 	saddr->spkt_device[13] = 0;
-	dev = dev_get_by_name(sk->sk_net, saddr->spkt_device);
+	dev = dev_get_by_name(sock_net(sk), saddr->spkt_device);
 	err = -ENODEV;
 	if (dev == NULL)
 		goto out_unlock;
@@ -451,7 +451,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
 	sk = pt->af_packet_priv;
 	po = pkt_sk(sk);
 
-	if (dev->nd_net != sk->sk_net)
+	if (dev_net(dev) != sock_net(sk))
 		goto drop;
 
 	skb->dev = dev;
@@ -568,7 +568,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
 	sk = pt->af_packet_priv;
 	po = pkt_sk(sk);
 
-	if (dev->nd_net != sk->sk_net)
+	if (dev_net(dev) != sock_net(sk))
 		goto drop;
 
 	if (dev->header_ops) {
@@ -728,7 +728,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock,
 	}
 
 
-	dev = dev_get_by_index(sk->sk_net, ifindex);
+	dev = dev_get_by_index(sock_net(sk), ifindex);
 	err = -ENXIO;
 	if (dev == NULL)
 		goto out_unlock;
@@ -800,7 +800,7 @@ static int packet_release(struct socket *sock)
 	if (!sk)
 		return 0;
 
-	net = sk->sk_net;
+	net = sock_net(sk);
 	po = pkt_sk(sk);
 
 	write_lock_bh(&net->packet.sklist_lock);
@@ -914,7 +914,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add
 		return -EINVAL;
 	strlcpy(name,uaddr->sa_data,sizeof(name));
 
-	dev = dev_get_by_name(sk->sk_net, name);
+	dev = dev_get_by_name(sock_net(sk), name);
 	if (dev) {
 		err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
 		dev_put(dev);
@@ -941,7 +941,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
 
 	if (sll->sll_ifindex) {
 		err = -ENODEV;
-		dev = dev_get_by_index(sk->sk_net, sll->sll_ifindex);
+		dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
 		if (dev == NULL)
 			goto out;
 	}
@@ -1135,7 +1135,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr,
 		return -EOPNOTSUPP;
 
 	uaddr->sa_family = AF_PACKET;
-	dev = dev_get_by_index(sk->sk_net, pkt_sk(sk)->ifindex);
+	dev = dev_get_by_index(sock_net(sk), pkt_sk(sk)->ifindex);
 	if (dev) {
 		strlcpy(uaddr->sa_data, dev->name, 15);
 		dev_put(dev);
@@ -1160,7 +1160,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr,
 	sll->sll_family = AF_PACKET;
 	sll->sll_ifindex = po->ifindex;
 	sll->sll_protocol = po->num;
-	dev = dev_get_by_index(sk->sk_net, po->ifindex);
+	dev = dev_get_by_index(sock_net(sk), po->ifindex);
 	if (dev) {
 		sll->sll_hatype = dev->type;
 		sll->sll_halen = dev->addr_len;
@@ -1212,7 +1212,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq)
 	rtnl_lock();
 
 	err = -ENODEV;
-	dev = __dev_get_by_index(sk->sk_net, mreq->mr_ifindex);
+	dev = __dev_get_by_index(sock_net(sk), mreq->mr_ifindex);
 	if (!dev)
 		goto done;
 
@@ -1266,7 +1266,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq)
 			if (--ml->count == 0) {
 				struct net_device *dev;
 				*mlp = ml->next;
-				dev = dev_get_by_index(sk->sk_net, ml->ifindex);
+				dev = dev_get_by_index(sock_net(sk), ml->ifindex);
 				if (dev) {
 					packet_dev_mc(dev, ml, -1);
 					dev_put(dev);
@@ -1294,7 +1294,7 @@ static void packet_flush_mclist(struct sock *sk)
 		struct net_device *dev;
 
 		po->mclist = ml->next;
-		if ((dev = dev_get_by_index(sk->sk_net, ml->ifindex)) != NULL) {
+		if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) {
 			packet_dev_mc(dev, ml, -1);
 			dev_put(dev);
 		}
@@ -1450,7 +1450,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
 	struct sock *sk;
 	struct hlist_node *node;
 	struct net_device *dev = data;
-	struct net *net = dev->nd_net;
+	struct net *net = dev_net(dev);
 
 	read_lock(&net->packet.sklist_lock);
 	sk_for_each(sk, node, &net->packet.sklist) {
@@ -1540,7 +1540,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd,
 		case SIOCGIFDSTADDR:
 		case SIOCSIFDSTADDR:
 		case SIOCSIFFLAGS:
-			if (sk->sk_net != &init_net)
+			if (sock_net(sk) != &init_net)
 				return -ENOIOCTLCMD;
 			return inet_dgram_ops.ioctl(sock, cmd, arg);
 #endif
@@ -1658,7 +1658,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
 	int err = 0;
 
 	if (req->tp_block_nr) {
-		int i, l;
+		int i;
 
 		/* Sanity tests and some calculations */
 
@@ -1687,7 +1687,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing
 		if (unlikely(!pg_vec))
 			goto out;
 
-		l = 0;
 		for (i = 0; i < req->tp_block_nr; i++) {
 			char *ptr = pg_vec[i];
 			struct tpacket_hdr *header;
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 063cbc5c26b1..d1ff3f885c5d 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -197,7 +197,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event,
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (event != NETDEV_DOWN)
@@ -551,7 +551,7 @@ static struct sock *rose_make_new(struct sock *osk)
 	if (osk->sk_type != SOCK_SEQPACKET)
 		return NULL;
 
-	sk = sk_alloc(osk->sk_net, PF_ROSE, GFP_ATOMIC, &rose_proto);
+	sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto);
 	if (sk == NULL)
 		return NULL;
 
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 1aaa2e804b0d..e58cc65728b5 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -619,8 +619,8 @@ void _dbprintk(const char *fmt, ...)
 {
 }
 
-#define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kenter(FMT,...)	dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define kleave(FMT,...)	dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
 #define kdebug(FMT,...)	dbgprintk("    "FMT ,##__VA_ARGS__)
 #define kproto(FMT,...)	dbgprintk("### "FMT ,##__VA_ARGS__)
 #define knet(FMT,...)	dbgprintk("@@@ "FMT ,##__VA_ARGS__)
@@ -671,8 +671,8 @@ do {							\
 } while (0)
 
 #else
-#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _enter(FMT,...)	_dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define _leave(FMT,...)	_dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
 #define _debug(FMT,...)	_dbprintk("    "FMT ,##__VA_ARGS__)
 #define _proto(FMT,...)	_dbprintk("### "FMT ,##__VA_ARGS__)
 #define _net(FMT,...)	_dbprintk("@@@ "FMT ,##__VA_ARGS__)
diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c
index 83eda247fe48..017322e2786d 100644
--- a/net/rxrpc/ar-proc.c
+++ b/net/rxrpc/ar-proc.c
@@ -103,7 +103,7 @@ const struct file_operations rxrpc_call_seq_fops = {
 	.open		= rxrpc_call_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= seq_release_private,
+	.release	= seq_release,
 };
 
 /*
@@ -188,5 +188,5 @@ const struct file_operations rxrpc_connection_seq_fops = {
 	.open		= rxrpc_connection_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= seq_release_private,
+	.release	= seq_release,
 };
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 0b8eb235bc13..74e662cbb2c5 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -951,7 +951,7 @@ done:
 
 static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *tca[TCA_ACT_MAX + 1];
 	u32 pid = skb ? NETLINK_CB(skb).pid : 0;
 	int ret = 0, ovr = 0;
@@ -1029,7 +1029,7 @@ find_dump_kind(struct nlmsghdr *n)
 static int
 tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlmsghdr *nlh;
 	unsigned char *b = skb_tail_pointer(skb);
 	struct nlattr *nest;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 0fbedcabf111..1086df7478bc 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -118,7 +118,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
 
 static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct nlattr *tca[TCA_MAX + 1];
 	struct tcmsg *t;
 	u32 protocol;
@@ -389,7 +389,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
 
 static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int t;
 	int s_t;
 	struct net_device *dev;
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 3da4129b89d1..72cf86e3c090 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -256,10 +256,10 @@ META_COLLECTOR(int_rtclassid)
 
 META_COLLECTOR(int_rtiif)
 {
-	if (unlikely(skb->dst == NULL))
+	if (unlikely(skb->rtable == NULL))
 		*err = -1;
 	else
-		dst->value = ((struct rtable*) skb->dst)->fl.iif;
+		dst->value = skb->rtable->fl.iif;
 }
 
 /**************************************************************************
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 7e3c048ba9b1..15b91a9ee8e8 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -605,7 +605,7 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w)
 
 static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct tcmsg *tcm = NLMSG_DATA(n);
 	struct nlattr *tca[TCA_MAX + 1];
 	struct net_device *dev;
@@ -674,7 +674,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 
 static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct tcmsg *tcm;
 	struct nlattr *tca[TCA_MAX + 1];
 	struct net_device *dev;
@@ -893,7 +893,7 @@ err_out:
 
 static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int idx, q_idx;
 	int s_idx, s_q_idx;
 	struct net_device *dev;
@@ -945,7 +945,7 @@ done:
 
 static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	struct tcmsg *tcm = NLMSG_DATA(n);
 	struct nlattr *tca[TCA_MAX + 1];
 	struct net_device *dev;
@@ -1139,7 +1139,7 @@ static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walk
 
 static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	struct net *net = skb->sk->sk_net;
+	struct net *net = sock_net(skb->sk);
 	int t;
 	int s_t;
 	struct net_device *dev;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index d29f792e0529..422c98aa9d5c 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1330,7 +1330,7 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
 	}
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
-			  __FUNCTION__, asoc, asoc->pathmtu, asoc->frag_point);
+			  __func__, asoc, asoc->pathmtu, asoc->frag_point);
 }
 
 /* Should we send a SACK to update our peer? */
@@ -1370,7 +1370,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
 	}
 
 	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) "
-			  "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd,
+			  "- %u\n", __func__, asoc, len, asoc->rwnd,
 			  asoc->rwnd_over, asoc->a_rwnd);
 
 	/* Send a window update SACK if the rwnd has increased by at least the
@@ -1381,7 +1381,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len)
 	if (sctp_peer_needs_update(asoc)) {
 		asoc->a_rwnd = asoc->rwnd;
 		SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p "
-				  "rwnd: %u a_rwnd: %u\n", __FUNCTION__,
+				  "rwnd: %u a_rwnd: %u\n", __func__,
 				  asoc, asoc->rwnd, asoc->a_rwnd);
 		sack = sctp_make_sack(asoc);
 		if (!sack)
@@ -1410,7 +1410,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
 		asoc->rwnd = 0;
 	}
 	SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n",
-			  __FUNCTION__, asoc, len, asoc->rwnd,
+			  __func__, asoc, len, asoc->rwnd,
 			  asoc->rwnd_over);
 }
 
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 4d3128f5ccc3..ed857643e3ff 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -136,20 +136,6 @@ void sctp_datamsg_put(struct sctp_datamsg *msg)
 		sctp_datamsg_destroy(msg);
 }
 
-/* Free a message.  Really just give up a reference, the
- * really free happens in sctp_datamsg_destroy().
- */
-void sctp_datamsg_free(struct sctp_datamsg *msg)
-{
-	sctp_datamsg_put(msg);
-}
-
-/* Hold on to all the fragments until all chunks have been sent. */
-void sctp_datamsg_track(struct sctp_chunk *chunk)
-{
-	sctp_chunk_hold(chunk);
-}
-
 /* Assign a chunk to this datamsg. */
 static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
 {
@@ -189,7 +175,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
 				    msecs_to_jiffies(sinfo->sinfo_timetolive);
 		msg->can_abandon = 1;
 		SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n",
-				  __FUNCTION__, msg, msg->expires_at, jiffies);
+				  __func__, msg, msg->expires_at, jiffies);
 	}
 
 	max = asoc->frag_point;
@@ -295,7 +281,7 @@ errout:
 		chunk = list_entry(pos, struct sctp_chunk, frag_list);
 		sctp_chunk_free(chunk);
 	}
-	sctp_datamsg_free(msg);
+	sctp_datamsg_put(msg);
 	return NULL;
 }
 
diff --git a/net/sctp/command.c b/net/sctp/command.c
index bb977330002a..c0044019db9e 100644
--- a/net/sctp/command.c
+++ b/net/sctp/command.c
@@ -52,18 +52,12 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)
 /* Add a command to a sctp_cmd_seq_t.
  * Return 0 if the command sequence is full.
  */
-int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
+void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
 {
-	if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS)
-		goto fail;
+	BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS);
 
 	seq->cmds[seq->next_free_slot].verb = verb;
 	seq->cmds[seq->next_free_slot++].obj = obj;
-
-	return 1;
-
-fail:
-	return 0;
 }
 
 /* Return the next command structure in a sctp_cmd_seq.
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 812ff1756c3e..c1d7e3b5c4b4 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -409,7 +409,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
 			   struct sctp_association *asoc,
 			   struct sctp_transport *t)
 {
-	SCTP_DEBUG_PRINTK("%s\n",  __FUNCTION__);
+	SCTP_DEBUG_PRINTK("%s\n",  __func__);
 
 	sctp_do_sm(SCTP_EVENT_T_OTHER,
 		   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index b1e05d719f9b..036bfcc8d15b 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -225,7 +225,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
 
 	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
 			  "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
-			  __FUNCTION__, skb, skb->len,
+			  __func__, skb, skb->len,
 			  NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
 
 	SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
@@ -250,7 +250,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 
 
 	SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
-			  __FUNCTION__, NIP6(fl.fl6_dst));
+			  __func__, NIP6(fl.fl6_dst));
 
 	if (saddr) {
 		ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
@@ -259,7 +259,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 			NIP6(fl.fl6_src));
 	}
 
-	dst = ip6_route_output(NULL, &fl);
+	dst = ip6_route_output(&init_net, NULL, &fl);
 	if (!dst->error) {
 		struct rt6_info *rt;
 		rt = (struct rt6_info *)dst;
@@ -312,10 +312,13 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
 			  "daddr:" NIP6_FMT " ",
-			  __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+			  __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
-		ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
+		ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+				   &daddr->v6.sin6_addr,
+				   inet6_sk(asoc->base.sk)->srcprefs,
+				   &saddr->v6.sin6_addr);
 		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
 				  NIP6(saddr->v6.sin6_addr));
 		return;
@@ -350,7 +353,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
 	} else {
 		printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
 		       "address for the dest:" NIP6_FMT "\n",
-		       __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
+		       __func__, asoc, NIP6(daddr->v6.sin6_addr));
 	}
 
 	rcu_read_unlock();
@@ -633,7 +636,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
 	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
 	struct sctp6_sock *newsctp6sk;
 
-	newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot);
+	newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot);
 	if (!newsk)
 		goto out;
 
diff --git a/net/sctp/output.c b/net/sctp/output.c
index aa700feea76c..cf4f9fb6819d 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -74,7 +74,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
 {
 	struct sctp_chunk *chunk = NULL;
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__,
+	SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__,
 			  packet, vtag);
 
 	packet->vtag = vtag;
@@ -106,7 +106,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
 	struct sctp_association *asoc = transport->asoc;
 	size_t overhead;
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__,
+	SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __func__,
 			  packet, transport);
 
 	packet->transport = transport;
@@ -138,7 +138,7 @@ void sctp_packet_free(struct sctp_packet *packet)
 {
 	struct sctp_chunk *chunk, *tmp;
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
 
 	list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
 		list_del_init(&chunk->list);
@@ -162,7 +162,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
 	sctp_xmit_t retval;
 	int error = 0;
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__,
+	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__,
 			  packet, chunk);
 
 	switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) {
@@ -264,7 +264,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
 	size_t pmtu;
 	int too_big;
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet,
+	SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet,
 			  chunk);
 
 	/* Try to bundle AUTH chunk */
@@ -372,7 +372,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
 	unsigned char *auth = NULL;	/* pointer to auth in skb data */
 	__u32 cksum_buf_len = sizeof(struct sctphdr);
 
-	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
+	SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet);
 
 	/* Do NOT generate a chunkless packet. */
 	if (list_empty(&packet->chunk_list))
@@ -677,7 +677,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
 				  "transport: %p, cwnd: %d, "
 				  "ssthresh: %d, flight_size: %d, "
 				  "pba: %d\n",
-				  __FUNCTION__, transport,
+				  __func__, transport,
 				  transport->cwnd,
 				  transport->ssthresh,
 				  transport->flight_size,
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 1bb3c5c35d2a..392012f5ab83 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -469,7 +469,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
 
 	SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, "
 			  "cwnd: %d, ssthresh: %d, flight_size: %d, "
-			  "pba: %d\n", __FUNCTION__,
+			  "pba: %d\n", __func__,
 			  transport, reason,
 			  transport->cwnd, transport->ssthresh,
 			  transport->flight_size,
@@ -494,6 +494,8 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
 		 */
 		if (transport == transport->asoc->peer.retran_path)
 			sctp_assoc_update_retran_path(transport->asoc);
+		transport->asoc->rtx_data_chunks +=
+			transport->asoc->unack_data;
 		break;
 	case SCTP_RTXR_FAST_RTX:
 		SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
@@ -504,6 +506,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
 		break;
 	case SCTP_RTXR_T1_RTX:
 		SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+		transport->asoc->init_retries++;
 		break;
 	default:
 		BUG();
@@ -1203,10 +1206,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
 	sctp_generate_fwdtsn(q, sack_ctsn);
 
 	SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
-			  __FUNCTION__, sack_ctsn);
+			  __func__, sack_ctsn);
 	SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, "
 			  "%p is 0x%x. Adv peer ack point: 0x%x\n",
-			  __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point);
+			  __func__, asoc, ctsn, asoc->adv_peer_ack_point);
 
 	/* See if all chunks are acked.
 	 * Make sure the empty queue handler will get run later.
@@ -1441,7 +1444,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
 			if (tchunk->tsn_gap_acked) {
 				SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
 						  "data TSN: 0x%x\n",
-						  __FUNCTION__,
+						  __func__,
 						  tsn);
 				tchunk->tsn_gap_acked = 0;
 
@@ -1558,7 +1561,7 @@ static void sctp_check_transmitted(struct sctp_outq *q,
 			    (sack_ctsn+2 == q->asoc->next_tsn)) {
 				SCTP_DEBUG_PRINTK("%s: SACK received for zero "
 						  "window probe: %u\n",
-						  __FUNCTION__, sack_ctsn);
+						  __func__, sack_ctsn);
 				q->asoc->overall_error_count = 0;
 				transport->error_count = 0;
 			}
@@ -1623,7 +1626,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
 				SCTP_DEBUG_PRINTK(
 					"%s: TSN 0x%x missing counter: %d\n",
-					__FUNCTION__, tsn,
+					__func__, tsn,
 					chunk->tsn_missing_report);
 			}
 		}
@@ -1646,7 +1649,7 @@ static void sctp_mark_missing(struct sctp_outq *q,
 
 		SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
 				  "ssthresh: %d, flight_size: %d, pba: %d\n",
-				  __FUNCTION__, transport, transport->cwnd,
+				  __func__, transport, transport->cwnd,
 				  transport->ssthresh, transport->flight_size,
 				  transport->partial_bytes_acked);
 	}
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 973f1dbc2ec3..ddca90e5e3a5 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -279,8 +279,10 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
 		*pos = 0;
 
 	if (*pos == 0)
-		seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
-				"RPORT LADDRS <-> RADDRS\n");
+		seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT "
+				"ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
+				"RPORT LADDRS <-> RADDRS "
+				"HBINT INS OUTS MAXRT T1X T2X RTXC\n");
 
 	return (void *)pos;
 }
@@ -319,15 +321,21 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
 		assoc = sctp_assoc(epb);
 		sk = epb->sk;
 		seq_printf(seq,
-			   "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
+			   "%8p %8p %-3d %-3d %-2d %-4d "
+			   "%4d %8d %8d %7d %5lu %-5d %5d "
+			   "%8lu %5d %5d %4d %4d %4d %8d ",
 			   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
-			   assoc->state, hash, assoc->assoc_id,
+			   assoc->state, hash,
+			   assoc->assoc_id,
 			   assoc->sndbuf_used,
 			   atomic_read(&assoc->rmem_alloc),
 			   sock_i_uid(sk), sock_i_ino(sk),
 			   epb->bind_addr.port,
-			   assoc->peer.port);
-
+			   assoc->peer.port,
+			   assoc->hbinterval, assoc->c.sinit_max_instreams,
+			   assoc->c.sinit_num_ostreams, assoc->max_retrans,
+			   assoc->init_retries, assoc->shutdown_retries,
+			   assoc->rtx_data_chunks);
 		seq_printf(seq, " ");
 		sctp_seq_dump_local_addrs(seq, epb);
 		seq_printf(seq, "<-> ");
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index f90091a1b9ce..5aea91137fbb 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -363,7 +363,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
 		return 0;
 
 	/* Is this a broadcast address? */
-	if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST)
+	if (skb && skb->rtable->rt_flags & RTCF_BROADCAST)
 		return 0;
 
 	return 1;
@@ -451,7 +451,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
 		fl.fl4_src = saddr->v4.sin_addr.s_addr;
 
 	SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
-			  __FUNCTION__, NIPQUAD(fl.fl4_dst),
+			  __func__, NIPQUAD(fl.fl4_dst),
 			  NIPQUAD(fl.fl4_src));
 
 	if (!ip_route_output_key(&init_net, &rt, &fl)) {
@@ -539,7 +539,7 @@ static void sctp_v4_get_saddr(struct sctp_association *asoc,
 /* What interface did this skb arrive on? */
 static int sctp_v4_skb_iif(const struct sk_buff *skb)
 {
-	return ((struct rtable *)skb->dst)->rt_iif;
+	return skb->rtable->rt_iif;
 }
 
 /* Was this packet marked by Explicit Congestion Notification? */
@@ -554,7 +554,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct inet_sock *newinet;
-	struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL,
+	struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL,
 			sk->sk_prot);
 
 	if (!newsk)
@@ -630,6 +630,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
 	struct sctp_sockaddr_entry *temp;
 	int found = 0;
 
+	if (dev_net(ifa->ifa_dev->dev) != &init_net)
+		return NOTIFY_DONE;
+
 	switch (ev) {
 	case NETDEV_UP:
 		addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
@@ -826,9 +829,9 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
 {
 	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
 			  "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n",
-			  __FUNCTION__, skb, skb->len,
-			  NIPQUAD(((struct rtable *)skb->dst)->rt_src),
-			  NIPQUAD(((struct rtable *)skb->dst)->rt_dst));
+			  __func__, skb, skb->len,
+			  NIPQUAD(skb->rtable->rt_src),
+			  NIPQUAD(skb->rtable->rt_dst));
 
 	SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
 	return ip_queue_xmit(skb, ipfragok);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 578630e8e00d..c8982452580e 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1782,7 +1782,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
 					const struct sctp_chunk *chunk,
 					struct sctp_chunk **errp)
 {
-	char		error[] = "The following parameter had invalid length:";
+	static const char error[] = "The following parameter had invalid length:";
 	size_t		payload_len = WORD_ROUND(sizeof(error)) +
 						sizeof(sctp_paramhdr_t);
 
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 28eb38eb6083..02bf32c30263 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -243,7 +243,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
 
 	sctp_bh_lock_sock(asoc->base.sk);
 	if (sock_owned_by_user(asoc->base.sk)) {
-		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
 
 		/* Try again later.  */
 		if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20)))
@@ -283,7 +283,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
 	sctp_bh_lock_sock(asoc->base.sk);
 	if (sock_owned_by_user(asoc->base.sk)) {
 		SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n",
-				  __FUNCTION__,
+				  __func__,
 				  timeout_type);
 
 		/* Try again later.  */
@@ -361,7 +361,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
 
 	sctp_bh_lock_sock(asoc->base.sk);
 	if (sock_owned_by_user(asoc->base.sk)) {
-		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__);
+		SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__);
 
 		/* Try again later.  */
 		if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20)))
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f2ed6473feef..b534dbef864f 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1124,7 +1124,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
 				printk(KERN_WARNING
 				    "%s association %p could not find address "
 				    NIP6_FMT "\n",
-				    __FUNCTION__,
+				    __func__,
 				    asoc,
 				    NIP6(from_addr.v6.sin6_addr));
 		} else {
@@ -1132,7 +1132,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
 				printk(KERN_WARNING
 				    "%s association %p could not find address "
 				    NIPQUAD_FMT "\n",
-				    __FUNCTION__,
+				    __func__,
 				    asoc,
 				    NIPQUAD(from_addr.v4.sin_addr.s_addr));
 		}
@@ -1150,7 +1150,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
 	    time_after(jiffies, hbinfo->sent_at + max_interval)) {
 		SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp "
 				  "received for transport: %p\n",
-				   __FUNCTION__, link);
+				   __func__, link);
 		return SCTP_DISPOSITION_DISCARD;
 	}
 
@@ -3135,12 +3135,8 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
 		if (!ev)
 			goto nomem;
 
-		if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP,
-				  SCTP_ULPEVENT(ev))) {
-			sctp_ulpevent_free(ev);
-			goto nomem;
-		}
-
+		sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
+				SCTP_ULPEVENT(ev));
 		sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
 				SCTP_CHUNK(chunk));
 	}
@@ -3668,7 +3664,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
 	skb_pull(chunk->skb, len);
 
 	tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
-	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
 
 	/* The TSN is too high--silently discard the chunk and count on it
 	 * getting retransmitted later.
@@ -3728,7 +3724,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
 	skb_pull(chunk->skb, len);
 
 	tsn = ntohl(fwdtsn_hdr->new_cum_tsn);
-	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn);
+	SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn);
 
 	/* The TSN is too high--silently discard the chunk and count on it
 	 * getting retransmitted later.
@@ -4219,7 +4215,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
 {
-	char err_str[]="The following chunk had invalid length:";
+	static const char err_str[]="The following chunk had invalid length:";
 
 	return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
 					sizeof(err_str));
@@ -4236,7 +4232,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
 				     const sctp_subtype_t type,
 				     void *arg,
 				     sctp_cmd_seq_t *commands) {
-	char err_str[] = "The following parameter had invalid length:";
+	static const char err_str[] = "The following parameter had invalid length:";
 
 	return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
 					sizeof(err_str));
@@ -4255,7 +4251,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
 {
-	char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
+	static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
 
 	return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
 					sizeof(err_str));
@@ -4274,7 +4270,7 @@ static sctp_disposition_t sctp_sf_violation_chunk(
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
 {
-	char err_str[]="The following chunk violates protocol:";
+	static const char err_str[]="The following chunk violates protocol:";
 
 	if (!asoc)
 		return sctp_sf_violation(ep, asoc, type, arg, commands);
@@ -5312,6 +5308,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
 	SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
 	SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
 
+	((struct sctp_association *)asoc)->shutdown_retries++;
+
 	if (asoc->overall_error_count >= asoc->max_retrans) {
 		sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
 				SCTP_ERROR(ETIMEDOUT));
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index d994d822900d..00ebd0610be2 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -525,7 +525,7 @@ static int sctp_send_asconf_add_ip(struct sock		*sk,
 	ep = sp->ep;
 
 	SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
-			  __FUNCTION__, sk, addrs, addrcnt);
+			  __func__, sk, addrs, addrcnt);
 
 	list_for_each(pos, &ep->asocs) {
 		asoc = list_entry(pos, struct sctp_association, asocs);
@@ -711,7 +711,7 @@ static int sctp_send_asconf_del_ip(struct sock		*sk,
 	ep = sp->ep;
 
 	SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n",
-			  __FUNCTION__, sk, addrs, addrcnt);
+			  __func__, sk, addrs, addrcnt);
 
 	list_for_each(pos, &ep->asocs) {
 		asoc = list_entry(pos, struct sctp_association, asocs);
@@ -1197,7 +1197,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk,
 	struct sockaddr *kaddrs;
 
 	SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n",
-			  __FUNCTION__, sk, addrs, addrs_size);
+			  __func__, sk, addrs, addrs_size);
 
 	if (unlikely(addrs_size <= 0))
 		return -EINVAL;
@@ -1729,7 +1729,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 	/* Now send the (possibly) fragmented message. */
 	list_for_each(pos, &datamsg->chunks) {
 		chunk = list_entry(pos, struct sctp_chunk, frag_list);
-		sctp_datamsg_track(chunk);
+		sctp_chunk_hold(chunk);
 
 		/* Do accounting for the write space.  */
 		sctp_set_owner_w(chunk);
@@ -1748,7 +1748,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 		SCTP_DEBUG_PRINTK("We sent primitively.\n");
 	}
 
-	sctp_datamsg_free(datamsg);
+	sctp_datamsg_put(datamsg);
 	if (err)
 		goto out_free;
 	else
@@ -3302,7 +3302,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr,
 	sctp_lock_sock(sk);
 
 	SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n",
-			  __FUNCTION__, sk, addr, addr_len);
+			  __func__, sk, addr, addr_len);
 
 	/* Validate addr_len before calling common connect/connectx routine. */
 	af = sctp_get_af_specific(addr->sa_family);
@@ -3823,7 +3823,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
 		goto out;
 	}
 
-	SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
+	SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc);
 
 	retval = sctp_do_peeloff(asoc, &newsock);
 	if (retval < 0)
@@ -3837,7 +3837,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval
 	}
 
 	SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
-			  __FUNCTION__, sk, asoc, newsock->sk, retval);
+			  __func__, sk, asoc, newsock->sk, retval);
 
 	/* Return the fd mapped to the new socket.  */
 	peeloff.sd = retval;
@@ -6233,7 +6233,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
 	long current_timeo = *timeo_p;
 	DEFINE_WAIT(wait);
 
-	SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
+	SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc,
 			  (long)(*timeo_p));
 
 	/* Increment the association's refcnt.  */
@@ -6513,8 +6513,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
 }
 
 
-DEFINE_PROTO_INUSE(sctp)
-
 /* This proto struct describes the ULP interface for SCTP.  */
 struct proto sctp_prot = {
 	.name        =	"SCTP",
@@ -6544,11 +6542,9 @@ struct proto sctp_prot = {
 	.enter_memory_pressure = sctp_enter_memory_pressure,
 	.memory_allocated = &sctp_memory_allocated,
 	.sockets_allocated = &sctp_sockets_allocated,
-	REF_PROTO_INUSE(sctp)
 };
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-DEFINE_PROTO_INUSE(sctpv6)
 
 struct proto sctpv6_prot = {
 	.name		= "SCTPv6",
@@ -6578,6 +6574,5 @@ struct proto sctpv6_prot = {
 	.enter_memory_pressure = sctp_enter_memory_pressure,
 	.memory_allocated = &sctp_memory_allocated,
 	.sockets_allocated = &sctp_sockets_allocated,
-	REF_PROTO_INUSE(sctpv6)
 };
 #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index d9f8af852b56..f4938f6c5abe 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -260,7 +260,7 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu)
 	if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
 		printk(KERN_WARNING "%s: Reported pmtu %d too low, "
 		       "using default minimum of %d\n",
-		       __FUNCTION__, pmtu,
+		       __func__, pmtu,
 		       SCTP_DEFAULT_MINSEGMENT);
 		/* Use default minimum segment size and disable
 		 * pmtu discovery on this transport.
@@ -388,7 +388,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
 	tp->rto_pending = 0;
 
 	SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d "
-			  "rttvar: %d, rto: %ld\n", __FUNCTION__,
+			  "rttvar: %d, rto: %ld\n", __func__,
 			  tp, rtt, tp->srtt, tp->rttvar, tp->rto);
 }
 
@@ -434,7 +434,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
 		SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, "
 				  "bytes_acked: %d, cwnd: %d, ssthresh: %d, "
 				  "flight_size: %d, pba: %d\n",
-				  __FUNCTION__,
+				  __func__,
 				  transport, bytes_acked, cwnd,
 				  ssthresh, flight_size, pba);
 	} else {
@@ -460,7 +460,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
 		SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: "
 				  "transport: %p, bytes_acked: %d, cwnd: %d, "
 				  "ssthresh: %d, flight_size: %d, pba: %d\n",
-				  __FUNCTION__,
+				  __func__,
 				  transport, bytes_acked, cwnd,
 				  ssthresh, flight_size, pba);
 	}
@@ -546,7 +546,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
 
 	transport->partial_bytes_acked = 0;
 	SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: "
-			  "%d ssthresh: %d\n", __FUNCTION__,
+			  "%d ssthresh: %d\n", __func__,
 			  transport, reason,
 			  transport->cwnd, transport->ssthresh);
 }
diff --git a/net/socket.c b/net/socket.c
index 9d3fbfbc8535..9b5c917f8a6b 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -857,7 +857,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 
 	sock = file->private_data;
 	sk = sock->sk;
-	net = sk->sk_net;
+	net = sock_net(sk);
 	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
 		err = dev_ioctl(net, cmd, argp);
 	} else
@@ -1375,7 +1375,7 @@ asmlinkage long sys_listen(int fd, int backlog)
 
 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
 	if (sock) {
-		somaxconn = sock->sk->sk_net->sysctl_somaxconn;
+		somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
 		if ((unsigned)backlog > somaxconn)
 			backlog = somaxconn;
 
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6dac38792288..5828e5c060ca 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -625,7 +625,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 	gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
 	if (!gss_auth->mech) {
 		printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n",
-				__FUNCTION__, flavor);
+				__func__, flavor);
 		goto err_free;
 	}
 	gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 8c6a7f1a25e9..13a3718e7cc9 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -43,7 +43,7 @@
 
 #define dprint_status(t)					\
 	dprintk("RPC: %5u %s (status %d)\n", t->tk_pid,		\
-			__FUNCTION__, t->tk_status)
+			__func__, t->tk_status)
 
 /*
  * All RPC clients are linked into this list
@@ -372,7 +372,7 @@ out_no_path:
 out_no_stats:
 	kfree(new);
 out_no_clnt:
-	dprintk("RPC:       %s: returned error %d\n", __FUNCTION__, err);
+	dprintk("RPC:       %s: returned error %d\n", __func__, err);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(rpc_clone_client);
@@ -756,7 +756,7 @@ call_reserveresult(struct rpc_task *task)
 		}
 
 		printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n",
-				__FUNCTION__, status);
+				__func__, status);
 		rpc_exit(task, -EIO);
 		return;
 	}
@@ -767,7 +767,7 @@ call_reserveresult(struct rpc_task *task)
 	 */
 	if (task->tk_rqstp) {
 		printk(KERN_ERR "%s: status=%d, request allocated anyway\n",
-				__FUNCTION__, status);
+				__func__, status);
 		xprt_release(task);
 	}
 
@@ -779,7 +779,7 @@ call_reserveresult(struct rpc_task *task)
 		break;
 	default:
 		printk(KERN_ERR "%s: unrecognized error %d, exiting\n",
-				__FUNCTION__, status);
+				__func__, status);
 		break;
 	}
 	rpc_exit(task, status);
@@ -1327,7 +1327,7 @@ call_verify(struct rpc_task *task)
 		 *   undefined results
 		 */
 		dprintk("RPC: %5u %s: XDR representation not a multiple of"
-		       " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
+		       " 4 bytes: 0x%x\n", task->tk_pid, __func__,
 		       task->tk_rqstp->rq_rcv_buf.len);
 		goto out_eio;
 	}
@@ -1337,7 +1337,7 @@ call_verify(struct rpc_task *task)
 
 	if ((n = ntohl(*p++)) != RPC_REPLY) {
 		dprintk("RPC: %5u %s: not an RPC reply: %x\n",
-				task->tk_pid, __FUNCTION__, n);
+				task->tk_pid, __func__, n);
 		goto out_garbage;
 	}
 	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
@@ -1349,13 +1349,13 @@ call_verify(struct rpc_task *task)
 			case RPC_MISMATCH:
 				dprintk("RPC: %5u %s: RPC call version "
 						"mismatch!\n",
-						task->tk_pid, __FUNCTION__);
+						task->tk_pid, __func__);
 				error = -EPROTONOSUPPORT;
 				goto out_err;
 			default:
 				dprintk("RPC: %5u %s: RPC call rejected, "
 						"unknown error: %x\n",
-						task->tk_pid, __FUNCTION__, n);
+						task->tk_pid, __func__, n);
 				goto out_eio;
 		}
 		if (--len < 0)
@@ -1369,7 +1369,7 @@ call_verify(struct rpc_task *task)
 				break;
 			task->tk_cred_retry--;
 			dprintk("RPC: %5u %s: retry stale creds\n",
-					task->tk_pid, __FUNCTION__);
+					task->tk_pid, __func__);
 			rpcauth_invalcred(task);
 			/* Ensure we obtain a new XID! */
 			xprt_release(task);
@@ -1382,7 +1382,7 @@ call_verify(struct rpc_task *task)
 				break;
 			task->tk_garb_retry--;
 			dprintk("RPC: %5u %s: retry garbled creds\n",
-					task->tk_pid, __FUNCTION__);
+					task->tk_pid, __func__);
 			task->tk_action = call_bind;
 			goto out_retry;
 		case RPC_AUTH_TOOWEAK:
@@ -1391,16 +1391,16 @@ call_verify(struct rpc_task *task)
 			break;
 		default:
 			dprintk("RPC: %5u %s: unknown auth error: %x\n",
-					task->tk_pid, __FUNCTION__, n);
+					task->tk_pid, __func__, n);
 			error = -EIO;
 		}
 		dprintk("RPC: %5u %s: call rejected %d\n",
-				task->tk_pid, __FUNCTION__, n);
+				task->tk_pid, __func__, n);
 		goto out_err;
 	}
 	if (!(p = rpcauth_checkverf(task, p))) {
 		dprintk("RPC: %5u %s: auth check failed\n",
-				task->tk_pid, __FUNCTION__);
+				task->tk_pid, __func__);
 		goto out_garbage;		/* bad verifier, retry */
 	}
 	len = p - (__be32 *)iov->iov_base - 1;
@@ -1411,14 +1411,14 @@ call_verify(struct rpc_task *task)
 		return p;
 	case RPC_PROG_UNAVAIL:
 		dprintk("RPC: %5u %s: program %u is unsupported by server %s\n",
-				task->tk_pid, __FUNCTION__,
+				task->tk_pid, __func__,
 				(unsigned int)task->tk_client->cl_prog,
 				task->tk_client->cl_server);
 		error = -EPFNOSUPPORT;
 		goto out_err;
 	case RPC_PROG_MISMATCH:
 		dprintk("RPC: %5u %s: program %u, version %u unsupported by "
-				"server %s\n", task->tk_pid, __FUNCTION__,
+				"server %s\n", task->tk_pid, __func__,
 				(unsigned int)task->tk_client->cl_prog,
 				(unsigned int)task->tk_client->cl_vers,
 				task->tk_client->cl_server);
@@ -1427,7 +1427,7 @@ call_verify(struct rpc_task *task)
 	case RPC_PROC_UNAVAIL:
 		dprintk("RPC: %5u %s: proc %p unsupported by program %u, "
 				"version %u on server %s\n",
-				task->tk_pid, __FUNCTION__,
+				task->tk_pid, __func__,
 				task->tk_msg.rpc_proc,
 				task->tk_client->cl_prog,
 				task->tk_client->cl_vers,
@@ -1436,11 +1436,11 @@ call_verify(struct rpc_task *task)
 		goto out_err;
 	case RPC_GARBAGE_ARGS:
 		dprintk("RPC: %5u %s: server saw garbage\n",
-				task->tk_pid, __FUNCTION__);
+				task->tk_pid, __func__);
 		break;			/* retry */
 	default:
 		dprintk("RPC: %5u %s: server accept status: %x\n",
-				task->tk_pid, __FUNCTION__, n);
+				task->tk_pid, __func__, n);
 		/* Also retry */
 	}
 
@@ -1449,7 +1449,7 @@ out_garbage:
 	if (task->tk_garb_retry) {
 		task->tk_garb_retry--;
 		dprintk("RPC: %5u %s: retrying\n",
-				task->tk_pid, __FUNCTION__);
+				task->tk_pid, __func__);
 		task->tk_action = call_bind;
 out_retry:
 		return ERR_PTR(-EAGAIN);
@@ -1459,11 +1459,11 @@ out_eio:
 out_err:
 	rpc_exit(task, error);
 	dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
-			__FUNCTION__, error);
+			__func__, error);
 	return ERR_PTR(error);
 out_overflow:
 	dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
-			__FUNCTION__);
+			__func__);
 	goto out_garbage;
 }
 
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 1b395a41a8b2..5a9b0e7828cd 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -479,13 +479,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd)
 	mnt = rpc_get_mount();
 	if (IS_ERR(mnt)) {
 		printk(KERN_WARNING "%s: %s failed to mount "
-			       "pseudofilesystem \n", __FILE__, __FUNCTION__);
+			       "pseudofilesystem \n", __FILE__, __func__);
 		return PTR_ERR(mnt);
 	}
 
 	if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) {
 		printk(KERN_WARNING "%s: %s failed to find path %s\n",
-				__FILE__, __FUNCTION__, path);
+				__FILE__, __func__, path);
 		rpc_put_mount();
 		return -ENOENT;
 	}
@@ -604,7 +604,7 @@ rpc_populate(struct dentry *parent,
 out_bad:
 	mutex_unlock(&dir->i_mutex);
 	printk(KERN_WARNING "%s: %s failed to populate directory %s\n",
-			__FILE__, __FUNCTION__, parent->d_name.name);
+			__FILE__, __func__, parent->d_name.name);
 	return -ENOMEM;
 }
 
@@ -623,7 +623,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
 	return 0;
 out_err:
 	printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
-			__FILE__, __FUNCTION__, dentry->d_name.name);
+			__FILE__, __func__, dentry->d_name.name);
 	return -ENOMEM;
 }
 
@@ -715,7 +715,7 @@ err_depopulate:
 err_dput:
 	dput(dentry);
 	printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n",
-			__FILE__, __FUNCTION__, path, error);
+			__FILE__, __func__, path, error);
 	dentry = ERR_PTR(error);
 	goto out;
 }
@@ -804,7 +804,7 @@ err_dput:
 	dput(dentry);
 	dentry = ERR_PTR(-ENOMEM);
 	printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n",
-			__FILE__, __FUNCTION__, parent->d_name.name, name,
+			__FILE__, __func__, parent->d_name.name, name,
 			-ENOMEM);
 	goto out;
 }
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 3164a0871cf0..56aa018dce3a 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -224,7 +224,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
 	int status;
 
 	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
-		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+		__func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
 
 	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
 				sizeof(*sin), prot, 2, 0);
@@ -283,7 +283,7 @@ void rpcb_getport_async(struct rpc_task *task)
 	struct rpcb_info *info;
 
 	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
-		task->tk_pid, __FUNCTION__,
+		task->tk_pid, __func__,
 		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
 
 	/* Autobind on cloned rpc clients is discouraged */
@@ -292,7 +292,7 @@ void rpcb_getport_async(struct rpc_task *task)
 	if (xprt_test_and_set_binding(xprt)) {
 		status = -EAGAIN;	/* tell caller to check again */
 		dprintk("RPC: %5u %s: waiting for another binder\n",
-			task->tk_pid, __FUNCTION__);
+			task->tk_pid, __func__);
 		goto bailout_nowake;
 	}
 
@@ -304,7 +304,7 @@ void rpcb_getport_async(struct rpc_task *task)
 	if (xprt_bound(xprt)) {
 		status = 0;
 		dprintk("RPC: %5u %s: already bound\n",
-			task->tk_pid, __FUNCTION__);
+			task->tk_pid, __func__);
 		goto bailout_nofree;
 	}
 
@@ -321,27 +321,27 @@ void rpcb_getport_async(struct rpc_task *task)
 	default:
 		status = -EAFNOSUPPORT;
 		dprintk("RPC: %5u %s: bad address family\n",
-				task->tk_pid, __FUNCTION__);
+				task->tk_pid, __func__);
 		goto bailout_nofree;
 	}
 	if (info[xprt->bind_index].rpc_proc == NULL) {
 		xprt->bind_index = 0;
 		status = -EPFNOSUPPORT;
 		dprintk("RPC: %5u %s: no more getport versions available\n",
-			task->tk_pid, __FUNCTION__);
+			task->tk_pid, __func__);
 		goto bailout_nofree;
 	}
 	bind_version = info[xprt->bind_index].rpc_vers;
 
 	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
-		task->tk_pid, __FUNCTION__, bind_version);
+		task->tk_pid, __func__, bind_version);
 
 	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
 				bind_version, 0);
 	if (IS_ERR(rpcb_clnt)) {
 		status = PTR_ERR(rpcb_clnt);
 		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
-			task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
+			task->tk_pid, __func__, PTR_ERR(rpcb_clnt));
 		goto bailout_nofree;
 	}
 
@@ -349,7 +349,7 @@ void rpcb_getport_async(struct rpc_task *task)
 	if (!map) {
 		status = -ENOMEM;
 		dprintk("RPC: %5u %s: no memory available\n",
-			task->tk_pid, __FUNCTION__);
+			task->tk_pid, __func__);
 		goto bailout_nofree;
 	}
 	map->r_prog = clnt->cl_prog;
@@ -366,7 +366,7 @@ void rpcb_getport_async(struct rpc_task *task)
 	if (IS_ERR(child)) {
 		status = -EIO;
 		dprintk("RPC: %5u %s: rpc_run_task failed\n",
-			task->tk_pid, __FUNCTION__);
+			task->tk_pid, __func__);
 		goto bailout;
 	}
 	rpc_put_task(child);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 30e7ac243a90..613daf8c1ff7 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1359,7 +1359,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock)
 			nloop++;
 	} while (err == -EADDRINUSE && nloop != 2);
 	dprintk("RPC:       %s "NIPQUAD_FMT":%u: %s (%d)\n",
-			__FUNCTION__, NIPQUAD(myaddr.sin_addr),
+			__func__, NIPQUAD(myaddr.sin_addr),
 			port, err ? "failed" : "ok", err);
 	return err;
 }
diff --git a/net/tipc/core.c b/net/tipc/core.c
index d2d7d32c02c7..740aac5cdfb6 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -48,16 +48,8 @@
 #include "subscr.h"
 #include "config.h"
 
-int  tipc_eth_media_start(void);
-void tipc_eth_media_stop(void);
-int  tipc_handler_start(void);
-void tipc_handler_stop(void);
-int  tipc_socket_init(void);
-void tipc_socket_stop(void);
-int  tipc_netlink_start(void);
-void tipc_netlink_stop(void);
 
-#define TIPC_MOD_VER "1.6.2"
+#define TIPC_MOD_VER "1.6.3"
 
 #ifndef CONFIG_TIPC_ZONES
 #define CONFIG_TIPC_ZONES 3
@@ -277,7 +269,6 @@ EXPORT_SYMBOL(tipc_register_media);
 /* TIPC API for external APIs (see tipc_port.h) */
 
 EXPORT_SYMBOL(tipc_createport_raw);
-EXPORT_SYMBOL(tipc_set_msg_option);
 EXPORT_SYMBOL(tipc_reject_msg);
 EXPORT_SYMBOL(tipc_send_buf_fast);
 EXPORT_SYMBOL(tipc_acknowledge);
diff --git a/net/tipc/core.h b/net/tipc/core.h
index feabca580820..3fe9b70331d9 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -180,6 +180,12 @@ extern int  tipc_core_start(void);
 extern void tipc_core_stop(void);
 extern int  tipc_core_start_net(void);
 extern void tipc_core_stop_net(void);
+extern int  tipc_handler_start(void);
+extern void tipc_handler_stop(void);
+extern int  tipc_netlink_start(void);
+extern void tipc_netlink_stop(void);
+extern int  tipc_socket_init(void);
+extern void tipc_socket_stop(void);
 
 static inline int delimit(int val, int min, int max)
 {
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 3bbef2ab22ae..9cd35eec3e7f 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -101,7 +101,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
 	struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv;
 	u32 size;
 
-	if (dev->nd_net != &init_net) {
+	if (dev_net(dev) != &init_net) {
 		kfree_skb(buf);
 		return 0;
 	}
@@ -198,7 +198,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt,
 	struct eth_bearer *eb_ptr = &eth_bearers[0];
 	struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	while ((eb_ptr->dev != dev)) {
diff --git a/net/tipc/link.c b/net/tipc/link.c
index cefa99824c58..a42f43430101 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2832,15 +2832,15 @@ static void link_set_supervision_props(struct link *l_ptr, u32 tolerance)
 void tipc_link_set_queue_limits(struct link *l_ptr, u32 window)
 {
 	/* Data messages from this node, inclusive FIRST_FRAGM */
-	l_ptr->queue_limit[DATA_LOW] = window;
-	l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4;
-	l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5;
-	l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6;
+	l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window;
+	l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4;
+	l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5;
+	l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6;
 	/* Transiting data messages,inclusive FIRST_FRAGM */
-	l_ptr->queue_limit[DATA_LOW + 4] = 300;
-	l_ptr->queue_limit[DATA_MEDIUM + 4] = 600;
-	l_ptr->queue_limit[DATA_HIGH + 4] = 900;
-	l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200;
+	l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300;
+	l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600;
+	l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900;
+	l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200;
 	l_ptr->queue_limit[CONN_MANAGER] = 1200;
 	l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200;
 	l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500;
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 782485468fb2..696a8633df75 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -73,10 +73,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
 		tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg),
 			    msg_fragm_no(msg));
 		break;
-	case DATA_LOW:
-	case DATA_MEDIUM:
-	case DATA_HIGH:
-	case DATA_CRITICAL:
+	case TIPC_LOW_IMPORTANCE:
+	case TIPC_MEDIUM_IMPORTANCE:
+	case TIPC_HIGH_IMPORTANCE:
+	case TIPC_CRITICAL_IMPORTANCE:
 		tipc_printf(buf, "DAT%u:", msg_user(msg));
 		if (msg_short(msg)) {
 			tipc_printf(buf, "CON:");
@@ -229,10 +229,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str
 	switch (usr) {
 	case CONN_MANAGER:
 	case NAME_DISTRIBUTOR:
-	case DATA_LOW:
-	case DATA_MEDIUM:
-	case DATA_HIGH:
-	case DATA_CRITICAL:
+	case TIPC_LOW_IMPORTANCE:
+	case TIPC_MEDIUM_IMPORTANCE:
+	case TIPC_HIGH_IMPORTANCE:
+	case TIPC_CRITICAL_IMPORTANCE:
 		if (msg_short(msg))
 			break;	/* No error */
 		switch (msg_errcode(msg)) {
diff --git a/net/tipc/msg.h b/net/tipc/msg.h
index e9ef6df26562..6ad070d87702 100644
--- a/net/tipc/msg.h
+++ b/net/tipc/msg.h
@@ -40,18 +40,16 @@
 #include "core.h"
 
 #define TIPC_VERSION              2
-#define DATA_LOW                  TIPC_LOW_IMPORTANCE
-#define DATA_MEDIUM               TIPC_MEDIUM_IMPORTANCE
-#define DATA_HIGH                 TIPC_HIGH_IMPORTANCE
-#define DATA_CRITICAL             TIPC_CRITICAL_IMPORTANCE
-#define SHORT_H_SIZE              24	/* Connected,in cluster */
+
+#define SHORT_H_SIZE              24	/* Connected, in-cluster messages */
 #define DIR_MSG_H_SIZE            32	/* Directly addressed messages */
-#define CONN_MSG_H_SIZE           36	/* Routed connected msgs*/
-#define LONG_H_SIZE               40	/* Named Messages */
+#define LONG_H_SIZE               40	/* Named messages */
 #define MCAST_H_SIZE              44	/* Multicast messages */
-#define MAX_H_SIZE                60	/* Inclusive full options */
+#define INT_H_SIZE                40	/* Internal messages */
+#define MIN_H_SIZE                24	/* Smallest legal TIPC header size */
+#define MAX_H_SIZE                60	/* Largest possible TIPC header size */
+
 #define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE)
-#define LINK_CONFIG               13
 
 
 /*
@@ -72,8 +70,10 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w,
 				u32 pos, u32 mask, u32 val)
 {
 	val = (val & mask) << pos;
-	m->hdr[w] &= ~htonl(mask << pos);
-	m->hdr[w] |= htonl(val);
+	val = htonl(val);
+	mask = htonl(mask << pos);
+	m->hdr[w] &= ~mask;
+	m->hdr[w] |= val;
 }
 
 /*
@@ -87,7 +87,7 @@ static inline u32 msg_version(struct tipc_msg *m)
 
 static inline void msg_set_version(struct tipc_msg *m)
 {
-	msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION);
+	msg_set_bits(m, 0, 29, 7, TIPC_VERSION);
 }
 
 static inline u32 msg_user(struct tipc_msg *m)
@@ -97,7 +97,7 @@ static inline u32 msg_user(struct tipc_msg *m)
 
 static inline u32 msg_isdata(struct tipc_msg *m)
 {
-	return (msg_user(m) <= DATA_CRITICAL);
+	return (msg_user(m) <= TIPC_CRITICAL_IMPORTANCE);
 }
 
 static inline void msg_set_user(struct tipc_msg *m, u32 n)
@@ -190,18 +190,6 @@ static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n)
 	msg_set_bits(m, 1, 19, 0x3, n);
 }
 
-static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz)
-{
-	u32 hsz = msg_hdr_sz(m);
-	char *to = (char *)&m->hdr[hsz/4];
-
-	if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE))
-		return;
-	msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4);
-	msg_set_hdr_sz(m, hsz + sz);
-	memcpy(to, opt, sz);
-}
-
 static inline u32 msg_bcast_ack(struct tipc_msg *m)
 {
 	return msg_bits(m, 1, 0, 0xffff);
@@ -330,17 +318,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
 	return (struct tipc_msg *)msg_data(m);
 }
 
-static inline void msg_expand(struct tipc_msg *m, u32 destnode)
-{
-	if (!msg_short(m))
-		return;
-	msg_set_hdr_sz(m, LONG_H_SIZE);
-	msg_set_orignode(m, msg_prevnode(m));
-	msg_set_destnode(m, destnode);
-	memset(&m->hdr[8], 0, 12);
-}
-
-
 
 /*
 		TIPC internal message header format, version 2
@@ -388,7 +365,6 @@ static inline void msg_expand(struct tipc_msg *m, u32 destnode)
 #define  NAME_DISTRIBUTOR     11
 #define  MSG_FRAGMENTER       12
 #define  LINK_CONFIG          13
-#define  INT_H_SIZE           40
 #define  DSC_H_SIZE           40
 
 /*
diff --git a/net/tipc/port.c b/net/tipc/port.c
index f508614ca59b..e2646a96935d 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -242,7 +242,8 @@ u32 tipc_createport_raw(void *usr_handle,
 	p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
 	p_ptr->publ.ref = ref;
 	msg = &p_ptr->publ.phdr;
-	msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
+	msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE,
+		 0);
 	msg_set_orignode(msg, tipc_own_addr);
 	msg_set_prevnode(msg, tipc_own_addr);
 	msg_set_origport(msg, ref);
@@ -413,13 +414,6 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode,
 	return buf;
 }
 
-int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz)
-{
-	msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr));
-	msg_set_options(&tp_ptr->phdr, opt, sz);
-	return TIPC_OK;
-}
-
 int tipc_reject_msg(struct sk_buff *buf, u32 err)
 {
 	struct tipc_msg *msg = buf_msg(buf);
@@ -632,7 +626,7 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf)
 					     msg_orignode(msg),
 					     msg_destport(msg),
 					     tipc_own_addr,
-					     DATA_HIGH,
+					     TIPC_HIGH_IMPORTANCE,
 					     TIPC_CONN_MSG,
 					     err,
 					     0,
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 22909036b9bc..1b5fb6103ded 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -43,7 +43,7 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/fcntl.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/string.h>
 #include <asm/atomic.h>
 #include <net/sock.h>
@@ -63,7 +63,7 @@
 struct tipc_sock {
 	struct sock sk;
 	struct tipc_port *p;
-	struct semaphore sem;
+	struct mutex lock;
 };
 
 #define tipc_sk(sk) ((struct tipc_sock*)sk)
@@ -102,44 +102,6 @@ static void sock_unlock(struct tipc_sock* tsock)
 }
 
 /**
- * pollmask - determine the current set of poll() events for a socket
- * @sock: socket structure
- *
- * TIPC sets the returned events as follows:
- * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
- *    or if a connection-oriented socket is does not have an active connection
- *    (i.e. a read operation will not block).
- * b) POLLOUT is set except when a socket's connection has been terminated
- *    (i.e. a write operation will not block).
- * c) POLLHUP is set when a socket's connection has been terminated.
- *
- * IMPORTANT: The fact that a read or write operation will not block does NOT
- * imply that the operation will succeed!
- *
- * Returns pollmask value
- */
-
-static u32 pollmask(struct socket *sock)
-{
-	u32 mask;
-
-	if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) ||
-	    (sock->state == SS_UNCONNECTED) ||
-	    (sock->state == SS_DISCONNECTING))
-		mask = (POLLRDNORM | POLLIN);
-	else
-		mask = 0;
-
-	if (sock->state == SS_DISCONNECTING)
-		mask |= POLLHUP;
-	else
-		mask |= POLLOUT;
-
-	return mask;
-}
-
-
-/**
  * advance_queue - discard first buffer in queue
  * @tsock: TIPC socket
  */
@@ -217,7 +179,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
 	tsock->p = port;
 	port->usr_handle = tsock;
 
-	init_MUTEX(&tsock->sem);
+	mutex_init(&tsock->lock);
 
 	dbg("sock_create: %x\n",tsock);
 
@@ -253,9 +215,9 @@ static int release(struct socket *sock)
 	dbg("sock_delete: %x\n",tsock);
 	if (!tsock)
 		return 0;
-	down(&tsock->sem);
+	mutex_lock(&tsock->lock);
 	if (!sock->sk) {
-		up(&tsock->sem);
+		mutex_unlock(&tsock->lock);
 		return 0;
 	}
 
@@ -288,7 +250,7 @@ static int release(struct socket *sock)
 		atomic_dec(&tipc_queue_size);
 	}
 
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 
 	sock_put(sk);
 
@@ -315,7 +277,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
 	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
 	int res;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	if (unlikely(!uaddr_len)) {
@@ -346,7 +308,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len)
 		res = tipc_withdraw(tsock->p->ref, -addr->scope,
 				    &addr->addr.nameseq);
 exit:
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
@@ -367,7 +329,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
 	struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr;
 	u32 res;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	*uaddr_len = sizeof(*addr);
@@ -380,7 +342,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
 		res = tipc_ownidentity(tsock->p->ref, &addr->addr.id);
 	addr->addr.name.domain = 0;
 
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
@@ -390,15 +352,47 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr,
  * @sock: socket for which to calculate the poll bits
  * @wait: ???
  *
- * Returns the pollmask
+ * Returns pollmask value
+ *
+ * COMMENTARY:
+ * It appears that the usual socket locking mechanisms are not useful here
+ * since the pollmask info is potentially out-of-date the moment this routine
+ * exits.  TCP and other protocols seem to rely on higher level poll routines
+ * to handle any preventable race conditions, so TIPC will do the same ...
+ *
+ * TIPC sets the returned events as follows:
+ * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty
+ *    or if a connection-oriented socket is does not have an active connection
+ *    (i.e. a read operation will not block).
+ * b) POLLOUT is set except when a socket's connection has been terminated
+ *    (i.e. a write operation will not block).
+ * c) POLLHUP is set when a socket's connection has been terminated.
+ *
+ * IMPORTANT: The fact that a read or write operation will not block does NOT
+ * imply that the operation will succeed!
  */
 
 static unsigned int poll(struct file *file, struct socket *sock,
 			 poll_table *wait)
 {
-	poll_wait(file, sock->sk->sk_sleep, wait);
-	/* NEED LOCK HERE? */
-	return pollmask(sock);
+	struct sock *sk = sock->sk;
+	u32 mask;
+
+	poll_wait(file, sk->sk_sleep, wait);
+
+	if (!skb_queue_empty(&sk->sk_receive_queue) ||
+	    (sock->state == SS_UNCONNECTED) ||
+	    (sock->state == SS_DISCONNECTING))
+		mask = (POLLRDNORM | POLLIN);
+	else
+		mask = 0;
+
+	if (sock->state == SS_DISCONNECTING)
+		mask |= POLLHUP;
+	else
+		mask |= POLLOUT;
+
+	return mask;
 }
 
 /**
@@ -477,7 +471,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
 		}
 	}
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	if (needs_conn) {
@@ -523,7 +517,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock,
 		}
 		if (likely(res != -ELINKCONG)) {
 exit:
-			up(&tsock->sem);
+			mutex_unlock(&tsock->lock);
 			return res;
 		}
 		if (m->msg_flags & MSG_DONTWAIT) {
@@ -562,7 +556,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
 	if (unlikely(dest))
 		return send_msg(iocb, sock, m, total_len);
 
-	if (down_interruptible(&tsock->sem)) {
+	if (mutex_lock_interruptible(&tsock->lock)) {
 		return -ERESTARTSYS;
 	}
 
@@ -578,7 +572,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock,
 		res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov);
 		if (likely(res != -ELINKCONG)) {
 exit:
-			up(&tsock->sem);
+			mutex_unlock(&tsock->lock);
 			return res;
 		}
 		if (m->msg_flags & MSG_DONTWAIT) {
@@ -846,7 +840,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock,
 
 	/* Look for a message in receive queue; wait if necessary */
 
-	if (unlikely(down_interruptible(&tsock->sem)))
+	if (unlikely(mutex_lock_interruptible(&tsock->lock)))
 		return -ERESTARTSYS;
 
 restart:
@@ -930,7 +924,7 @@ restart:
 		advance_queue(tsock);
 	}
 exit:
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
@@ -981,7 +975,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
 
 	/* Look for a message in receive queue; wait if necessary */
 
-	if (unlikely(down_interruptible(&tsock->sem)))
+	if (unlikely(mutex_lock_interruptible(&tsock->lock)))
 		return -ERESTARTSYS;
 
 restart:
@@ -1077,7 +1071,7 @@ restart:
 		goto restart;
 
 exit:
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return sz_copied ? sz_copied : res;
 }
 
@@ -1293,7 +1287,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
 	   return res;
    }
 
-   if (down_interruptible(&tsock->sem))
+   if (mutex_lock_interruptible(&tsock->lock))
 	   return -ERESTARTSYS;
 
    /* Wait for destination's 'ACK' response */
@@ -1317,7 +1311,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen,
 	   sock->state = SS_DISCONNECTING;
    }
 
-   up(&tsock->sem);
+   mutex_unlock(&tsock->lock);
    return res;
 }
 
@@ -1365,7 +1359,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags)
 		     (flags & O_NONBLOCK)))
 		return -EWOULDBLOCK;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	if (wait_event_interruptible(*sock->sk->sk_sleep,
@@ -1375,7 +1369,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags)
 	}
 	buf = skb_peek(&sock->sk->sk_receive_queue);
 
-	res = tipc_create(sock->sk->sk_net, newsock, 0);
+	res = tipc_create(sock_net(sock->sk), newsock, 0);
 	if (!res) {
 		struct tipc_sock *new_tsock = tipc_sk(newsock->sk);
 		struct tipc_portid id;
@@ -1412,14 +1406,14 @@ static int accept(struct socket *sock, struct socket *newsock, int flags)
 		}
 	}
 exit:
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
 /**
  * shutdown - shutdown socket connection
  * @sock: socket structure
- * @how: direction to close (unused; always treated as read + write)
+ * @how: direction to close (must be SHUT_RDWR)
  *
  * Terminates connection (if necessary), then purges socket's receive queue.
  *
@@ -1432,9 +1426,10 @@ static int shutdown(struct socket *sock, int how)
 	struct sk_buff *buf;
 	int res;
 
-	/* Could return -EINVAL for an invalid "how", but why bother? */
+	if (how != SHUT_RDWR)
+		return -EINVAL;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	sock_lock(tsock);
@@ -1484,7 +1479,7 @@ restart:
 
 	sock_unlock(tsock);
 
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
@@ -1518,7 +1513,7 @@ static int setsockopt(struct socket *sock,
 	if ((res = get_user(value, (u32 __user *)ov)))
 		return res;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	switch (opt) {
@@ -1541,7 +1536,7 @@ static int setsockopt(struct socket *sock,
 		res = -EINVAL;
 	}
 
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
@@ -1574,7 +1569,7 @@ static int getsockopt(struct socket *sock,
 	if ((res = get_user(len, ol)))
 		return res;
 
-	if (down_interruptible(&tsock->sem))
+	if (mutex_lock_interruptible(&tsock->lock))
 		return -ERESTARTSYS;
 
 	switch (opt) {
@@ -1607,7 +1602,7 @@ static int getsockopt(struct socket *sock,
 		res = put_user(sizeof(value), ol);
 	}
 
-	up(&tsock->sem);
+	mutex_unlock(&tsock->lock);
 	return res;
 }
 
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index b8788fd5e3c6..50bbf6bb1a22 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -252,7 +252,7 @@ static struct sock *__unix_find_socket_byname(struct net *net,
 	sk_for_each(s, node, &unix_socket_table[hash ^ type]) {
 		struct unix_sock *u = unix_sk(s);
 
-		if (s->sk_net != net)
+		if (!net_eq(sock_net(s), net))
 			continue;
 
 		if (u->addr->len == len &&
@@ -289,7 +289,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i)
 		    &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) {
 		struct dentry *dentry = unix_sk(s)->dentry;
 
-		if (s->sk_net != net)
+		if (!net_eq(sock_net(s), net))
 			continue;
 
 		if(dentry && dentry->d_inode == i)
@@ -654,7 +654,7 @@ static int unix_release(struct socket *sock)
 static int unix_autobind(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
 	static u32 ordernum = 1;
 	struct unix_address * addr;
@@ -758,7 +758,7 @@ fail:
 static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
 	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
 	struct dentry * dentry = NULL;
@@ -899,7 +899,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
 			      int alen, int flags)
 {
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr;
 	struct sock *other;
 	unsigned hash;
@@ -996,7 +996,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 {
 	struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr;
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk), *newu, *otheru;
 	struct sock *newsk = NULL;
 	struct sock *other = NULL;
@@ -1025,7 +1025,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 	err = -ENOMEM;
 
 	/* create new sock for complete connection */
-	newsk = unix_create1(sk->sk_net, NULL);
+	newsk = unix_create1(sock_net(sk), NULL);
 	if (newsk == NULL)
 		goto out;
 
@@ -1312,7 +1312,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
 {
 	struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
 	struct sock *sk = sock->sk;
-	struct net *net = sk->sk_net;
+	struct net *net = sock_net(sk);
 	struct unix_sock *u = unix_sk(sk);
 	struct sockaddr_un *sunaddr=msg->msg_name;
 	struct sock *other = NULL;
@@ -2016,13 +2016,14 @@ struct unix_iter_state {
 	struct seq_net_private p;
 	int i;
 };
-static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos)
+static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos)
 {
+	struct unix_iter_state *iter = seq->private;
 	loff_t off = 0;
 	struct sock *s;
 
 	for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) {
-		if (s->sk_net != iter->p.net)
+		if (sock_net(s) != seq_file_net(seq))
 			continue;
 		if (off == pos)
 			return s;
@@ -2035,9 +2036,8 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos)
 static void *unix_seq_start(struct seq_file *seq, loff_t *pos)
 	__acquires(unix_table_lock)
 {
-	struct unix_iter_state *iter = seq->private;
 	spin_lock(&unix_table_lock);
-	return *pos ? unix_seq_idx(iter, *pos - 1) : ((void *) 1);
+	return *pos ? unix_seq_idx(seq, *pos - 1) : ((void *) 1);
 }
 
 static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -2050,7 +2050,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 		sk = first_unix_socket(&iter->i);
 	else
 		sk = next_unix_socket(&iter->i, sk);
-	while (sk && (sk->sk_net != iter->p.net))
+	while (sk && (sock_net(sk) != seq_file_net(seq)))
 		sk = next_unix_socket(&iter->i, sk);
 	return sk;
 }
@@ -2176,7 +2176,7 @@ static int __init af_unix_init(void)
 	rc = proto_register(&unix_proto, 1);
 	if (rc != 0) {
 		printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n",
-		       __FUNCTION__);
+		       __func__);
 		goto out;
 	}
 
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 65710a42e5a7..b9f943c45f3b 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_WIRELESS_EXT) += wext.o
 obj-$(CONFIG_CFG80211) += cfg80211.o
 
-cfg80211-y += core.o sysfs.o radiotap.o
+cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o
 cfg80211-$(CONFIG_NL80211) += nl80211.o
diff --git a/net/wireless/core.c b/net/wireless/core.c
index cfc5fc5f9e75..80afacdae46c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -232,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy)
 {
 	struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 	int res;
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	bool have_band = false;
+	int i;
+
+	/* sanity check supported bands/channels */
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+		if (!sband)
+			continue;
+
+		sband->band = band;
+
+		if (!sband->n_channels || !sband->n_bitrates) {
+			WARN_ON(1);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < sband->n_channels; i++) {
+			sband->channels[i].orig_flags =
+				sband->channels[i].flags;
+			sband->channels[i].orig_mag =
+				sband->channels[i].max_antenna_gain;
+			sband->channels[i].orig_mpwr =
+				sband->channels[i].max_power;
+			sband->channels[i].band = band;
+		}
+
+		have_band = true;
+	}
+
+	if (!have_band) {
+		WARN_ON(1);
+		return -EINVAL;
+	}
+
+	/* check and set up bitrates */
+	ieee80211_set_bitrate_flags(wiphy);
+
+	/* set up regulatory info */
+	wiphy_update_regulatory(wiphy);
 
 	mutex_lock(&cfg80211_drv_mutex);
 
diff --git a/net/wireless/core.h b/net/wireless/core.h
index eb0f846b40df..7a02c356d63d 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv);
 extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
 			       char *newname);
 
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
+void wiphy_update_regulatory(struct wiphy *wiphy);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index e3a214f63f91..64a7460af734 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -81,7 +81,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
 	[NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 },
 	[NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY,
 					       .len = NL80211_MAX_SUPP_RATES },
+	[NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 },
 	[NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 },
+	[NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED },
+	[NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY,
+				.len = IEEE80211_MAX_MESH_ID_LEN },
+	[NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 },
 };
 
 /* message building helper */
@@ -98,6 +103,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 			      struct cfg80211_registered_device *dev)
 {
 	void *hdr;
+	struct nlattr *nl_bands, *nl_band;
+	struct nlattr *nl_freqs, *nl_freq;
+	struct nlattr *nl_rates, *nl_rate;
+	enum ieee80211_band band;
+	struct ieee80211_channel *chan;
+	struct ieee80211_rate *rate;
+	int i;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY);
 	if (!hdr)
@@ -105,6 +117,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
 	NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
+
+	nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
+	if (!nl_bands)
+		goto nla_put_failure;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		if (!dev->wiphy.bands[band])
+			continue;
+
+		nl_band = nla_nest_start(msg, band);
+		if (!nl_band)
+			goto nla_put_failure;
+
+		/* add frequencies */
+		nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS);
+		if (!nl_freqs)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) {
+			nl_freq = nla_nest_start(msg, i);
+			if (!nl_freq)
+				goto nla_put_failure;
+
+			chan = &dev->wiphy.bands[band]->channels[i];
+			NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ,
+				    chan->center_freq);
+
+			if (chan->flags & IEEE80211_CHAN_DISABLED)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED);
+			if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN);
+			if (chan->flags & IEEE80211_CHAN_NO_IBSS)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS);
+			if (chan->flags & IEEE80211_CHAN_RADAR)
+				NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR);
+
+			nla_nest_end(msg, nl_freq);
+		}
+
+		nla_nest_end(msg, nl_freqs);
+
+		/* add bitrates */
+		nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES);
+		if (!nl_rates)
+			goto nla_put_failure;
+
+		for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) {
+			nl_rate = nla_nest_start(msg, i);
+			if (!nl_rate)
+				goto nla_put_failure;
+
+			rate = &dev->wiphy.bands[band]->bitrates[i];
+			NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE,
+				    rate->bitrate);
+			if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+				NLA_PUT_FLAG(msg,
+					NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE);
+
+			nla_nest_end(msg, nl_rate);
+		}
+
+		nla_nest_end(msg, nl_rates);
+
+		nla_nest_end(msg, nl_band);
+	}
+	nla_nest_end(msg, nl_bands);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -262,12 +341,45 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info)
 	return -ENOBUFS;
 }
 
+static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
+	[NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
+	[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+};
+
+static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
+{
+	struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1];
+	int flag;
+
+	*mntrflags = 0;
+
+	if (!nla)
+		return -EINVAL;
+
+	if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX,
+			     nla, mntr_flags_policy))
+		return -EINVAL;
+
+	for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++)
+		if (flags[flag])
+			*mntrflags |= (1<<flag);
+
+	return 0;
+}
+
 static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *drv;
+	struct vif_params params;
 	int err, ifindex;
 	enum nl80211_iftype type;
 	struct net_device *dev;
+	u32 flags;
+
+	memset(&params, 0, sizeof(params));
 
 	if (info->attrs[NL80211_ATTR_IFTYPE]) {
 		type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]);
@@ -287,8 +399,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 		goto unlock;
 	}
 
+	if (type == NL80211_IFTYPE_MESH_POINT &&
+	    info->attrs[NL80211_ATTR_MESH_ID]) {
+		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+	}
+
 	rtnl_lock();
-	err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type);
+	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+				  &flags);
+	err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex,
+					    type, err ? NULL : &flags, &params);
 	rtnl_unlock();
 
  unlock:
@@ -299,8 +421,12 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *drv;
+	struct vif_params params;
 	int err;
 	enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
+	u32 flags;
+
+	memset(&params, 0, sizeof(params));
 
 	if (!info->attrs[NL80211_ATTR_IFNAME])
 		return -EINVAL;
@@ -320,11 +446,22 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 		goto unlock;
 	}
 
+	if (type == NL80211_IFTYPE_MESH_POINT &&
+	    info->attrs[NL80211_ATTR_MESH_ID]) {
+		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
+		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+	}
+
 	rtnl_lock();
+	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
+				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
+				  &flags);
 	err = drv->ops->add_virtual_intf(&drv->wiphy,
-		nla_data(info->attrs[NL80211_ATTR_IFNAME]), type);
+		nla_data(info->attrs[NL80211_ATTR_IFNAME]),
+		type, err ? NULL : &flags, &params);
 	rtnl_unlock();
 
+
  unlock:
 	cfg80211_put_dev(drv);
 	return err;
@@ -752,10 +889,10 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
 
 static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 				int flags, struct net_device *dev,
-				u8 *mac_addr, struct station_stats *stats)
+				u8 *mac_addr, struct station_info *sinfo)
 {
 	void *hdr;
-	struct nlattr *statsattr;
+	struct nlattr *sinfoattr;
 
 	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
 	if (!hdr)
@@ -764,20 +901,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-	statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS);
-	if (!statsattr)
+	sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
+	if (!sinfoattr)
 		goto nla_put_failure;
-	if (stats->filled & STATION_STAT_INACTIVE_TIME)
-		NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME,
-			    stats->inactive_time);
-	if (stats->filled & STATION_STAT_RX_BYTES)
-		NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES,
-			    stats->rx_bytes);
-	if (stats->filled & STATION_STAT_TX_BYTES)
-		NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES,
-			    stats->tx_bytes);
-
-	nla_nest_end(msg, statsattr);
+	if (sinfo->filled & STATION_INFO_INACTIVE_TIME)
+		NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME,
+			    sinfo->inactive_time);
+	if (sinfo->filled & STATION_INFO_RX_BYTES)
+		NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES,
+			    sinfo->rx_bytes);
+	if (sinfo->filled & STATION_INFO_TX_BYTES)
+		NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES,
+			    sinfo->tx_bytes);
+	if (sinfo->filled & STATION_INFO_LLID)
+		NLA_PUT_U16(msg, NL80211_STA_INFO_LLID,
+			    sinfo->llid);
+	if (sinfo->filled & STATION_INFO_PLID)
+		NLA_PUT_U16(msg, NL80211_STA_INFO_PLID,
+			    sinfo->plid);
+	if (sinfo->filled & STATION_INFO_PLINK_STATE)
+		NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE,
+			    sinfo->plink_state);
+
+	nla_nest_end(msg, sinfoattr);
 
 	return genlmsg_end(msg, hdr);
 
@@ -785,17 +931,80 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 	return genlmsg_cancel(msg, hdr);
 }
 
+static int nl80211_dump_station(struct sk_buff *skb,
+		struct netlink_callback *cb)
+{
+	int wp_idx = 0;
+	int if_idx = 0;
+	int sta_idx = cb->args[2];
+	int wp_start = cb->args[0];
+	int if_start = cb->args[1];
+	struct station_info sinfo;
+	struct cfg80211_registered_device *dev;
+	struct wireless_dev *wdev;
+	u8 mac_addr[ETH_ALEN];
+	int err;
+	int exit = 0;
+
+	/* TODO: filter by device */
+	mutex_lock(&cfg80211_drv_mutex);
+	list_for_each_entry(dev, &cfg80211_drv_list, list) {
+		if (exit)
+			break;
+		if (++wp_idx < wp_start)
+			continue;
+		if_idx = 0;
+
+		mutex_lock(&dev->devlist_mtx);
+		list_for_each_entry(wdev, &dev->netdev_list, list) {
+			if (exit)
+				break;
+			if (++if_idx < if_start)
+				continue;
+			if (!dev->ops->dump_station)
+				continue;
+
+			for (;; ++sta_idx) {
+				rtnl_lock();
+				err = dev->ops->dump_station(&dev->wiphy,
+						wdev->netdev, sta_idx, mac_addr,
+						&sinfo);
+				rtnl_unlock();
+				if (err) {
+					sta_idx = 0;
+					break;
+				}
+				if (nl80211_send_station(skb,
+						NETLINK_CB(cb->skb).pid,
+						cb->nlh->nlmsg_seq, NLM_F_MULTI,
+						wdev->netdev, mac_addr,
+						&sinfo) < 0) {
+					exit = 1;
+					break;
+				}
+			}
+		}
+		mutex_unlock(&dev->devlist_mtx);
+	}
+	mutex_unlock(&cfg80211_drv_mutex);
+
+	cb->args[0] = wp_idx;
+	cb->args[1] = if_idx;
+	cb->args[2] = sta_idx;
+
+	return skb->len;
+}
 
 static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 {
 	struct cfg80211_registered_device *drv;
 	int err;
 	struct net_device *dev;
-	struct station_stats stats;
+	struct station_info sinfo;
 	struct sk_buff *msg;
 	u8 *mac_addr = NULL;
 
-	memset(&stats, 0, sizeof(stats));
+	memset(&sinfo, 0, sizeof(sinfo));
 
 	if (!info->attrs[NL80211_ATTR_MAC])
 		return -EINVAL;
@@ -812,15 +1021,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	rtnl_lock();
-	err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats);
+	err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo);
 	rtnl_unlock();
 
+	if (err)
+		goto out;
+
 	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (!msg)
 		goto out;
 
 	if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0,
-				 dev, mac_addr, &stats) < 0)
+				 dev, mac_addr, &sinfo) < 0)
 		goto out_free;
 
 	err = genlmsg_unicast(msg, info->snd_pid);
@@ -891,6 +1103,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 				&params.station_flags))
 		return -EINVAL;
 
+	if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
+		params.plink_action =
+		    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+
 	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
 	if (err)
 		return err;
@@ -1005,6 +1221,273 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq,
+				int flags, struct net_device *dev,
+				u8 *dst, u8 *next_hop,
+				struct mpath_info *pinfo)
+{
+	void *hdr;
+	struct nlattr *pinfoattr;
+
+	hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION);
+	if (!hdr)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
+	NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop);
+
+	pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO);
+	if (!pinfoattr)
+		goto nla_put_failure;
+	if (pinfo->filled & MPATH_INFO_FRAME_QLEN)
+		NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN,
+			    pinfo->frame_qlen);
+	if (pinfo->filled & MPATH_INFO_DSN)
+		NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN,
+			    pinfo->dsn);
+	if (pinfo->filled & MPATH_INFO_METRIC)
+		NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC,
+			    pinfo->metric);
+	if (pinfo->filled & MPATH_INFO_EXPTIME)
+		NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME,
+			    pinfo->exptime);
+	if (pinfo->filled & MPATH_INFO_FLAGS)
+		NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS,
+			    pinfo->flags);
+	if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT)
+		NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+			    pinfo->discovery_timeout);
+	if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES)
+		NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+			    pinfo->discovery_retries);
+
+	nla_nest_end(msg, pinfoattr);
+
+	return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+	return genlmsg_cancel(msg, hdr);
+}
+
+static int nl80211_dump_mpath(struct sk_buff *skb,
+		struct netlink_callback *cb)
+{
+	int wp_idx = 0;
+	int if_idx = 0;
+	int sta_idx = cb->args[2];
+	int wp_start = cb->args[0];
+	int if_start = cb->args[1];
+	struct mpath_info pinfo;
+	struct cfg80211_registered_device *dev;
+	struct wireless_dev *wdev;
+	u8 dst[ETH_ALEN];
+	u8 next_hop[ETH_ALEN];
+	int err;
+	int exit = 0;
+
+	/* TODO: filter by device */
+	mutex_lock(&cfg80211_drv_mutex);
+	list_for_each_entry(dev, &cfg80211_drv_list, list) {
+		if (exit)
+			break;
+		if (++wp_idx < wp_start)
+			continue;
+		if_idx = 0;
+
+		mutex_lock(&dev->devlist_mtx);
+		list_for_each_entry(wdev, &dev->netdev_list, list) {
+			if (exit)
+				break;
+			if (++if_idx < if_start)
+				continue;
+			if (!dev->ops->dump_mpath)
+				continue;
+
+			for (;; ++sta_idx) {
+				rtnl_lock();
+				err = dev->ops->dump_mpath(&dev->wiphy,
+						wdev->netdev, sta_idx, dst,
+						next_hop, &pinfo);
+				rtnl_unlock();
+				if (err) {
+					sta_idx = 0;
+					break;
+				}
+				if (nl80211_send_mpath(skb,
+						NETLINK_CB(cb->skb).pid,
+						cb->nlh->nlmsg_seq, NLM_F_MULTI,
+						wdev->netdev, dst, next_hop,
+						&pinfo) < 0) {
+					exit = 1;
+					break;
+				}
+			}
+		}
+		mutex_unlock(&dev->devlist_mtx);
+	}
+	mutex_unlock(&cfg80211_drv_mutex);
+
+	cb->args[0] = wp_idx;
+	cb->args[1] = if_idx;
+	cb->args[2] = sta_idx;
+
+	return skb->len;
+}
+
+static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	struct mpath_info pinfo;
+	struct sk_buff *msg;
+	u8 *dst = NULL;
+	u8 next_hop[ETH_ALEN];
+
+	memset(&pinfo, 0, sizeof(pinfo));
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->get_mpath) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo);
+	rtnl_unlock();
+
+	if (err)
+		goto out;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		goto out;
+
+	if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0,
+				 dev, dst, next_hop, &pinfo) < 0)
+		goto out_free;
+
+	err = genlmsg_unicast(msg, info->snd_pid);
+	goto out;
+
+ out_free:
+	nlmsg_free(msg);
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 *dst = NULL;
+	u8 *next_hop = NULL;
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+		return -EINVAL;
+
+	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+	next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->change_mpath) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 *dst = NULL;
+	u8 *next_hop = NULL;
+
+	if (!info->attrs[NL80211_ATTR_MAC])
+		return -EINVAL;
+
+	if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP])
+		return -EINVAL;
+
+	dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+	next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->add_mpath) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
+static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *drv;
+	int err;
+	struct net_device *dev;
+	u8 *dst = NULL;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		dst = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	err = get_drv_dev_by_info_ifindex(info, &drv, &dev);
+	if (err)
+		return err;
+
+	if (!drv->ops->del_mpath) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+
+	rtnl_lock();
+	err = drv->ops->del_mpath(&drv->wiphy, dev, dst);
+	rtnl_unlock();
+
+ out:
+	cfg80211_put_dev(drv);
+	dev_put(dev);
+	return err;
+}
+
 static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_WIPHY,
@@ -1089,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = {
 	{
 		.cmd = NL80211_CMD_GET_STATION,
 		.doit = nl80211_get_station,
-		/* TODO: implement dumpit */
+		.dumpit = nl80211_dump_station,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
@@ -1111,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = {
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
 	},
+	{
+		.cmd = NL80211_CMD_GET_MPATH,
+		.doit = nl80211_get_mpath,
+		.dumpit = nl80211_dump_mpath,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_SET_MPATH,
+		.doit = nl80211_set_mpath,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_NEW_MPATH,
+		.doit = nl80211_new_mpath,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
+	{
+		.cmd = NL80211_CMD_DEL_MPATH,
+		.doit = nl80211_del_mpath,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+	},
 };
 
 /* multicast groups */
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
new file mode 100644
index 000000000000..8cc6037eb2ae
--- /dev/null
+++ b/net/wireless/reg.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * This regulatory domain control implementation is highly incomplete, it
+ * only exists for the purpose of not regressing mac80211.
+ *
+ * For now, drivers can restrict the set of allowed channels by either
+ * not registering those channels or setting the IEEE80211_CHAN_DISABLED
+ * flag; that flag will only be *set* by this code, never *cleared.
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table and finally
+ * registering those channels in the wiphy structure.
+ *
+ * Alternatively, drivers that trust the regulatory domain control here
+ * will register a complete set of capabilities and the control code
+ * will restrict the set by setting the IEEE80211_CHAN_* flags.
+ */
+#include <linux/kernel.h>
+#include <net/wireless.h>
+#include "core.h"
+
+static char *ieee80211_regdom = "US";
+module_param(ieee80211_regdom, charp, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
+
+struct ieee80211_channel_range {
+	short start_freq;
+	short end_freq;
+	int max_power;
+	int max_antenna_gain;
+	u32 flags;
+};
+
+struct ieee80211_regdomain {
+	const char *code;
+	const struct ieee80211_channel_range *ranges;
+	int n_ranges;
+};
+
+#define RANGE_PWR(_start, _end, _pwr, _ag, _flags)	\
+	{ _start, _end, _pwr, _ag, _flags }
+
+
+/*
+ * Ideally, in the future, these definitions will be loaded from a
+ * userspace table via some daemon.
+ */
+static const struct ieee80211_channel_range ieee80211_US_channels[] = {
+	/* IEEE 802.11b/g, channels 1..11 */
+	RANGE_PWR(2412, 2462, 27, 6, 0),
+	/* IEEE 802.11a, channel 36*/
+	RANGE_PWR(5180, 5180, 23, 6, 0),
+	/* IEEE 802.11a, channel 40*/
+	RANGE_PWR(5200, 5200, 23, 6, 0),
+	/* IEEE 802.11a, channel 44*/
+	RANGE_PWR(5220, 5220, 23, 6, 0),
+	/* IEEE 802.11a, channels 48..64 */
+	RANGE_PWR(5240, 5320, 23, 6, 0),
+	/* IEEE 802.11a, channels 149..165, outdoor */
+	RANGE_PWR(5745, 5825, 30, 6, 0),
+};
+
+static const struct ieee80211_channel_range ieee80211_JP_channels[] = {
+	/* IEEE 802.11b/g, channels 1..14 */
+	RANGE_PWR(2412, 2484, 20, 6, 0),
+	/* IEEE 802.11a, channels 34..48 */
+	RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN),
+	/* IEEE 802.11a, channels 52..64 */
+	RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS |
+				     IEEE80211_CHAN_RADAR),
+};
+
+#define REGDOM(_code)							\
+	{								\
+		.code = __stringify(_code),				\
+		.ranges = ieee80211_ ##_code## _channels,		\
+		.n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels),	\
+	}
+
+static const struct ieee80211_regdomain ieee80211_regdoms[] = {
+	REGDOM(US),
+	REGDOM(JP),
+};
+
+
+static const struct ieee80211_regdomain *get_regdom(void)
+{
+	static const struct ieee80211_channel_range
+	ieee80211_world_channels[] = {
+		/* IEEE 802.11b/g, channels 1..11 */
+		RANGE_PWR(2412, 2462, 27, 6, 0),
+	};
+	static const struct ieee80211_regdomain regdom_world = REGDOM(world);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++)
+		if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0)
+			return &ieee80211_regdoms[i];
+
+	return &regdom_world;
+}
+
+
+static void handle_channel(struct ieee80211_channel *chan,
+			   const struct ieee80211_regdomain *rd)
+{
+	int i;
+	u32 flags = chan->orig_flags;
+	const struct ieee80211_channel_range *rg = NULL;
+
+	for (i = 0; i < rd->n_ranges; i++) {
+		if (rd->ranges[i].start_freq <= chan->center_freq &&
+		    chan->center_freq <= rd->ranges[i].end_freq) {
+			rg = &rd->ranges[i];
+			break;
+		}
+	}
+
+	if (!rg) {
+		/* not found */
+		flags |= IEEE80211_CHAN_DISABLED;
+		chan->flags = flags;
+		return;
+	}
+
+	chan->flags = flags;
+	chan->max_antenna_gain = min(chan->orig_mag,
+					 rg->max_antenna_gain);
+	chan->max_power = min(chan->orig_mpwr, rg->max_power);
+}
+
+static void handle_band(struct ieee80211_supported_band *sband,
+			const struct ieee80211_regdomain *rd)
+{
+	int i;
+
+	for (i = 0; i < sband->n_channels; i++)
+		handle_channel(&sband->channels[i], rd);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+	const struct ieee80211_regdomain *rd = get_regdom();
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+		if (wiphy->bands[band])
+			handle_band(wiphy->bands[band], rd);
+}
diff --git a/net/wireless/util.c b/net/wireless/util.c
new file mode 100644
index 000000000000..f54424693a38
--- /dev/null
+++ b/net/wireless/util.c
@@ -0,0 +1,121 @@
+/*
+ * Wireless utility functions
+ *
+ * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
+ */
+#include <net/wireless.h>
+#include <asm/bitops.h>
+#include "core.h"
+
+int ieee80211_channel_to_frequency(int chan)
+{
+	if (chan < 14)
+		return 2407 + chan * 5;
+
+	if (chan == 14)
+		return 2484;
+
+	/* FIXME: 802.11j 17.3.8.3.2 */
+	return (chan + 1000) * 5;
+}
+EXPORT_SYMBOL(ieee80211_channel_to_frequency);
+
+int ieee80211_frequency_to_channel(int freq)
+{
+	if (freq == 2484)
+		return 14;
+
+	if (freq < 2484)
+		return (freq - 2407) / 5;
+
+	/* FIXME: 802.11j 17.3.8.3.2 */
+	return freq/5 - 1000;
+}
+EXPORT_SYMBOL(ieee80211_frequency_to_channel);
+
+struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
+						  int freq)
+{
+	enum ieee80211_band band;
+	struct ieee80211_supported_band *sband;
+	int i;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		sband = wiphy->bands[band];
+
+		if (!sband)
+			continue;
+
+		for (i = 0; i < sband->n_channels; i++) {
+			if (sband->channels[i].center_freq == freq)
+				return &sband->channels[i];
+		}
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_channel);
+
+static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
+				     enum ieee80211_band band)
+{
+	int i, want;
+
+	switch (band) {
+	case IEEE80211_BAND_5GHZ:
+		want = 3;
+		for (i = 0; i < sband->n_bitrates; i++) {
+			if (sband->bitrates[i].bitrate == 60 ||
+			    sband->bitrates[i].bitrate == 120 ||
+			    sband->bitrates[i].bitrate == 240) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_A;
+				want--;
+			}
+		}
+		WARN_ON(want);
+		break;
+	case IEEE80211_BAND_2GHZ:
+		want = 7;
+		for (i = 0; i < sband->n_bitrates; i++) {
+			if (sband->bitrates[i].bitrate == 10) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_B |
+					IEEE80211_RATE_MANDATORY_G;
+				want--;
+			}
+
+			if (sband->bitrates[i].bitrate == 20 ||
+			    sband->bitrates[i].bitrate == 55 ||
+			    sband->bitrates[i].bitrate == 110 ||
+			    sband->bitrates[i].bitrate == 60 ||
+			    sband->bitrates[i].bitrate == 120 ||
+			    sband->bitrates[i].bitrate == 240) {
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_MANDATORY_G;
+				want--;
+			}
+
+			if (sband->bitrates[i].bitrate != 10 &&
+			    sband->bitrates[i].bitrate != 20 &&
+			    sband->bitrates[i].bitrate != 55 &&
+			    sband->bitrates[i].bitrate != 110)
+				sband->bitrates[i].flags |=
+					IEEE80211_RATE_ERP_G;
+		}
+		WARN_ON(want != 0 && want != 3 && want != 6);
+		break;
+	case IEEE80211_NUM_BANDS:
+		WARN_ON(1);
+		break;
+	}
+}
+
+void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
+{
+	enum ieee80211_band band;
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+		if (wiphy->bands[band])
+			set_mandatory_flags_band(wiphy->bands[band], band);
+}
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index 2c569b63e7d8..947188a5b937 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -1157,7 +1157,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len)
 	struct sk_buff *skb;
 	int err;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return;
 
 	skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 339ca4a8e89e..6ba67c523c16 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -191,7 +191,7 @@ static int x25_device_event(struct notifier_block *this, unsigned long event,
 	struct net_device *dev = ptr;
 	struct x25_neigh *nb;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	if (dev->type == ARPHRD_X25
@@ -549,7 +549,7 @@ static struct sock *x25_make_new(struct sock *osk)
 	if (osk->sk_type != SOCK_SEQPACKET)
 		goto out;
 
-	if ((sk = x25_alloc_socket(osk->sk_net)) == NULL)
+	if ((sk = x25_alloc_socket(sock_net(osk))) == NULL)
 		goto out;
 
 	x25 = x25_sk(sk);
diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c
index f0679d283110..3ff206c0ae94 100644
--- a/net/x25/x25_dev.c
+++ b/net/x25/x25_dev.c
@@ -95,7 +95,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev,
 	struct sk_buff *nskb;
 	struct x25_neigh *nb;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		goto drop;
 
 	nskb = skb_copy(skb, GFP_ATOMIC);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9fc4c315f6cd..15d73e47cc2c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
 
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
+static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
 unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
 EXPORT_SYMBOL(xfrm_policy_count);
 
@@ -96,25 +97,52 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
 	return 0;
 }
 
+static inline struct dst_entry *__xfrm_dst_lookup(int tos,
+						  xfrm_address_t *saddr,
+						  xfrm_address_t *daddr,
+						  int family)
+{
+	struct xfrm_policy_afinfo *afinfo;
+	struct dst_entry *dst;
+
+	afinfo = xfrm_policy_get_afinfo(family);
+	if (unlikely(afinfo == NULL))
+		return ERR_PTR(-EAFNOSUPPORT);
+
+	dst = afinfo->dst_lookup(tos, saddr, daddr);
+
+	xfrm_policy_put_afinfo(afinfo);
+
+	return dst;
+}
+
 static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+						xfrm_address_t *prev_saddr,
+						xfrm_address_t *prev_daddr,
 						int family)
 {
 	xfrm_address_t *saddr = &x->props.saddr;
 	xfrm_address_t *daddr = &x->id.daddr;
-	struct xfrm_policy_afinfo *afinfo;
 	struct dst_entry *dst;
 
-	if (x->type->flags & XFRM_TYPE_LOCAL_COADDR)
+	if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
 		saddr = x->coaddr;
-	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
+		daddr = prev_daddr;
+	}
+	if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
+		saddr = prev_saddr;
 		daddr = x->coaddr;
+	}
 
-	afinfo = xfrm_policy_get_afinfo(family);
-	if (unlikely(afinfo == NULL))
-		return ERR_PTR(-EAFNOSUPPORT);
+	dst = __xfrm_dst_lookup(tos, saddr, daddr, family);
+
+	if (!IS_ERR(dst)) {
+		if (prev_saddr != saddr)
+			memcpy(prev_saddr, saddr,  sizeof(*prev_saddr));
+		if (prev_daddr != daddr)
+			memcpy(prev_daddr, daddr,  sizeof(*prev_daddr));
+	}
 
-	dst = afinfo->dst_lookup(tos, saddr, daddr);
-	xfrm_policy_put_afinfo(afinfo);
 	return dst;
 }
 
@@ -208,6 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
 	policy = kzalloc(sizeof(struct xfrm_policy), gfp);
 
 	if (policy) {
+		INIT_LIST_HEAD(&policy->bytype);
 		INIT_HLIST_NODE(&policy->bydst);
 		INIT_HLIST_NODE(&policy->byidx);
 		rwlock_init(&policy->lock);
@@ -230,6 +259,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
 	if (del_timer(&policy->timer))
 		BUG();
 
+	write_lock_bh(&xfrm_policy_lock);
+	list_del(&policy->bytype);
+	write_unlock_bh(&xfrm_policy_lock);
+
 	security_xfrm_policy_free(policy);
 	kfree(policy);
 }
@@ -584,6 +617,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 	policy->curlft.use_time = 0;
 	if (!mod_timer(&policy->timer, jiffies + HZ))
 		xfrm_pol_hold(policy);
+	list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (delpol)
@@ -822,57 +856,60 @@ out:
 }
 EXPORT_SYMBOL(xfrm_policy_flush);
 
-int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),
+int xfrm_policy_walk(struct xfrm_policy_walk *walk,
+		     int (*func)(struct xfrm_policy *, int, int, void*),
 		     void *data)
 {
-	struct xfrm_policy *pol, *last = NULL;
-	struct hlist_node *entry;
-	int dir, last_dir = 0, count, error;
+	struct xfrm_policy *old, *pol, *last = NULL;
+	int error = 0;
 
+	if (walk->type >= XFRM_POLICY_TYPE_MAX &&
+	    walk->type != XFRM_POLICY_TYPE_ANY)
+		return -EINVAL;
+
+	if (walk->policy == NULL && walk->count != 0)
+		return 0;
+
+	old = pol = walk->policy;
+	walk->policy = NULL;
 	read_lock_bh(&xfrm_policy_lock);
-	count = 0;
 
-	for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {
-		struct hlist_head *table = xfrm_policy_bydst[dir].table;
-		int i;
+	for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
+		if (walk->type != walk->cur_type &&
+		    walk->type != XFRM_POLICY_TYPE_ANY)
+			continue;
 
-		hlist_for_each_entry(pol, entry,
-				     &xfrm_policy_inexact[dir], bydst) {
-			if (pol->type != type)
+		if (pol == NULL) {
+			pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
+					       struct xfrm_policy, bytype);
+		}
+		list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
+			if (pol->dead)
 				continue;
 			if (last) {
-				error = func(last, last_dir % XFRM_POLICY_MAX,
-					     count, data);
-				if (error)
+				error = func(last, xfrm_policy_id2dir(last->index),
+					     walk->count, data);
+				if (error) {
+					xfrm_pol_hold(last);
+					walk->policy = last;
 					goto out;
-			}
-			last = pol;
-			last_dir = dir;
-			count++;
-		}
-		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
-			hlist_for_each_entry(pol, entry, table + i, bydst) {
-				if (pol->type != type)
-					continue;
-				if (last) {
-					error = func(last, last_dir % XFRM_POLICY_MAX,
-						     count, data);
-					if (error)
-						goto out;
 				}
-				last = pol;
-				last_dir = dir;
-				count++;
 			}
+			last = pol;
+			walk->count++;
 		}
+		pol = NULL;
 	}
-	if (count == 0) {
+	if (walk->count == 0) {
 		error = -ENOENT;
 		goto out;
 	}
-	error = func(last, last_dir % XFRM_POLICY_MAX, 0, data);
+	if (last)
+		error = func(last, xfrm_policy_id2dir(last->index), 0, data);
 out:
 	read_unlock_bh(&xfrm_policy_lock);
+	if (old != NULL)
+		xfrm_pol_put(old);
 	return error;
 }
 EXPORT_SYMBOL(xfrm_policy_walk);
@@ -1344,6 +1381,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
 	int trailer_len = 0;
 	int tos;
 	int family = policy->selector.family;
+	xfrm_address_t saddr, daddr;
+
+	xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
 
 	tos = xfrm_get_tos(fl, family);
 	err = tos;
@@ -1374,7 +1414,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
 
 		if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
 			family = xfrm[i]->props.family;
-			dst = xfrm_dst_lookup(xfrm[i], tos, family);
+			dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
+					      family);
 			err = PTR_ERR(dst);
 			if (IS_ERR(dst))
 				goto put_states;
@@ -2038,7 +2079,7 @@ static int stale_bundle(struct dst_entry *dst)
 void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
 {
 	while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
-		dst->dev = dev->nd_net->loopback_dev;
+		dst->dev = dev_net(dev)->loopback_dev;
 		dev_hold(dst->dev);
 		dev_put(dev);
 	}
@@ -2309,7 +2350,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
 {
 	struct net_device *dev = ptr;
 
-	if (dev->nd_net != &init_net)
+	if (dev_net(dev) != &init_net)
 		return NOTIFY_DONE;
 
 	switch (event) {
@@ -2365,6 +2406,9 @@ static void __init xfrm_policy_init(void)
 			panic("XFRM: failed to allocate bydst hash\n");
 	}
 
+	for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
+		INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
+
 	INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
 	register_netdevice_notifier(&xfrm_dev_notifier);
 }
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 58f1f9347b54..5dcc10b93c86 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock);
  * Main use is finding SA after policy selected tunnel or transport mode.
  * Also, it can be used by ah/esp icmp error handler to find offending SA.
  */
+static LIST_HEAD(xfrm_state_all);
 static struct hlist_head *xfrm_state_bydst __read_mostly;
 static struct hlist_head *xfrm_state_bysrc __read_mostly;
 static struct hlist_head *xfrm_state_byspi __read_mostly;
@@ -512,6 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void)
 	if (x) {
 		atomic_set(&x->refcnt, 1);
 		atomic_set(&x->tunnel_users, 0);
+		INIT_LIST_HEAD(&x->all);
 		INIT_HLIST_NODE(&x->bydst);
 		INIT_HLIST_NODE(&x->bysrc);
 		INIT_HLIST_NODE(&x->byspi);
@@ -537,6 +539,10 @@ void __xfrm_state_destroy(struct xfrm_state *x)
 {
 	BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
 
+	spin_lock_bh(&xfrm_state_lock);
+	list_del(&x->all);
+	spin_unlock_bh(&xfrm_state_lock);
+
 	spin_lock_bh(&xfrm_state_gc_lock);
 	hlist_add_head(&x->bydst, &xfrm_state_gc_list);
 	spin_unlock_bh(&xfrm_state_gc_lock);
@@ -913,6 +919,8 @@ static void __xfrm_state_insert(struct xfrm_state *x)
 
 	x->genid = ++xfrm_state_genid;
 
+	list_add_tail(&x->all, &xfrm_state_all);
+
 	h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
 			  x->props.reqid, x->props.family);
 	hlist_add_head(&x->bydst, xfrm_state_bydst+h);
@@ -1522,36 +1530,47 @@ unlock:
 }
 EXPORT_SYMBOL(xfrm_alloc_spi);
 
-int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
+int xfrm_state_walk(struct xfrm_state_walk *walk,
+		    int (*func)(struct xfrm_state *, int, void*),
 		    void *data)
 {
-	int i;
-	struct xfrm_state *x, *last = NULL;
-	struct hlist_node *entry;
-	int count = 0;
+	struct xfrm_state *old, *x, *last = NULL;
 	int err = 0;
 
+	if (walk->state == NULL && walk->count != 0)
+		return 0;
+
+	old = x = walk->state;
+	walk->state = NULL;
 	spin_lock_bh(&xfrm_state_lock);
-	for (i = 0; i <= xfrm_state_hmask; i++) {
-		hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) {
-			if (!xfrm_id_proto_match(x->id.proto, proto))
-				continue;
-			if (last) {
-				err = func(last, count, data);
-				if (err)
-					goto out;
+	if (x == NULL)
+		x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
+	list_for_each_entry_from(x, &xfrm_state_all, all) {
+		if (x->km.state == XFRM_STATE_DEAD)
+			continue;
+		if (!xfrm_id_proto_match(x->id.proto, walk->proto))
+			continue;
+		if (last) {
+			err = func(last, walk->count, data);
+			if (err) {
+				xfrm_state_hold(last);
+				walk->state = last;
+				goto out;
 			}
-			last = x;
-			count++;
 		}
+		last = x;
+		walk->count++;
 	}
-	if (count == 0) {
+	if (walk->count == 0) {
 		err = -ENOENT;
 		goto out;
 	}
-	err = func(last, 0, data);
+	if (last)
+		err = func(last, 0, data);
 out:
 	spin_unlock_bh(&xfrm_state_lock);
+	if (old != NULL)
+		xfrm_state_put(old);
 	return err;
 }
 EXPORT_SYMBOL(xfrm_state_walk);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 5d96f2728dc6..5578c909fcf6 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -529,8 +529,6 @@ struct xfrm_dump_info {
 	struct sk_buff *out_skb;
 	u32 nlmsg_seq;
 	u16 nlmsg_flags;
-	int start_idx;
-	int this_idx;
 };
 
 static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
@@ -597,9 +595,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
 	struct nlmsghdr *nlh;
 	int err;
 
-	if (sp->this_idx < sp->start_idx)
-		goto out;
-
 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
 			XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
 	if (nlh == NULL)
@@ -612,8 +607,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
 		goto nla_put_failure;
 
 	nlmsg_end(skb, nlh);
-out:
-	sp->this_idx++;
 	return 0;
 
 nla_put_failure:
@@ -621,18 +614,32 @@ nla_put_failure:
 	return err;
 }
 
+static int xfrm_dump_sa_done(struct netlink_callback *cb)
+{
+	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
+	xfrm_state_walk_done(walk);
+	return 0;
+}
+
 static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
+	BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
+		     sizeof(cb->args) - sizeof(cb->args[0]));
+
 	info.in_skb = cb->skb;
 	info.out_skb = skb;
 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
 	info.nlmsg_flags = NLM_F_MULTI;
-	info.this_idx = 0;
-	info.start_idx = cb->args[0];
-	(void) xfrm_state_walk(0, dump_one_state, &info);
-	cb->args[0] = info.this_idx;
+
+	if (!cb->args[0]) {
+		cb->args[0] = 1;
+		xfrm_state_walk_init(walk, 0);
+	}
+
+	(void) xfrm_state_walk(walk, dump_one_state, &info);
 
 	return skb->len;
 }
@@ -651,7 +658,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
 	info.out_skb = skb;
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
-	info.this_idx = info.start_idx = 0;
 
 	if (dump_one_state(x, 0, &info)) {
 		kfree_skb(skb);
@@ -1229,9 +1235,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
 	struct sk_buff *skb = sp->out_skb;
 	struct nlmsghdr *nlh;
 
-	if (sp->this_idx < sp->start_idx)
-		goto out;
-
 	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
 			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
 	if (nlh == NULL)
@@ -1247,8 +1250,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
 		goto nlmsg_failure;
 
 	nlmsg_end(skb, nlh);
-out:
-	sp->this_idx++;
 	return 0;
 
 nlmsg_failure:
@@ -1256,21 +1257,33 @@ nlmsg_failure:
 	return -EMSGSIZE;
 }
 
+static int xfrm_dump_policy_done(struct netlink_callback *cb)
+{
+	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
+
+	xfrm_policy_walk_done(walk);
+	return 0;
+}
+
 static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
 {
+	struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
 	struct xfrm_dump_info info;
 
+	BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
+		     sizeof(cb->args) - sizeof(cb->args[0]));
+
 	info.in_skb = cb->skb;
 	info.out_skb = skb;
 	info.nlmsg_seq = cb->nlh->nlmsg_seq;
 	info.nlmsg_flags = NLM_F_MULTI;
-	info.this_idx = 0;
-	info.start_idx = cb->args[0];
-	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);
-#ifdef CONFIG_XFRM_SUB_POLICY
-	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);
-#endif
-	cb->args[0] = info.this_idx;
+
+	if (!cb->args[0]) {
+		cb->args[0] = 1;
+		xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
+	}
+
+	(void) xfrm_policy_walk(walk, dump_one_policy, &info);
 
 	return skb->len;
 }
@@ -1290,7 +1303,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
 	info.out_skb = skb;
 	info.nlmsg_seq = seq;
 	info.nlmsg_flags = 0;
-	info.this_idx = info.start_idx = 0;
 
 	if (dump_one_policy(xp, dir, 0, &info) < 0) {
 		kfree_skb(skb);
@@ -1888,15 +1900,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
 static struct xfrm_link {
 	int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
 	int (*dump)(struct sk_buff *, struct netlink_callback *);
+	int (*done)(struct netlink_callback *);
 } xfrm_dispatch[XFRM_NR_MSGTYPES] = {
 	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        },
 	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        },
 	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
-						   .dump = xfrm_dump_sa       },
+						   .dump = xfrm_dump_sa,
+						   .done = xfrm_dump_sa_done  },
 	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    },
 	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    },
 	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
-						   .dump = xfrm_dump_policy   },
+						   .dump = xfrm_dump_policy,
+						   .done = xfrm_dump_policy_done },
 	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
 	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire   },
 	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
@@ -1935,7 +1950,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 		if (link->dump == NULL)
 			return -EINVAL;
 
-		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL);
+		return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
 	}
 
 	err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,