aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/appletalk/ddp.c2
-rw-r--r--net/atm/common.c2
-rw-r--r--net/atm/pvc.c2
-rw-r--r--net/atm/svc.c2
-rw-r--r--net/ax25/af_ax25.c2
-rw-r--r--net/bluetooth/af_bluetooth.c6
-rw-r--r--net/bluetooth/bnep/sock.c2
-rw-r--r--net/bluetooth/cmtp/sock.c2
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/hidp/sock.c2
-rw-r--r--net/bluetooth/l2cap.c2
-rw-r--r--net/bluetooth/rfcomm/sock.c4
-rw-r--r--net/bluetooth/sco.c2
-rw-r--r--net/bridge/br_device.c1
-rw-r--r--net/can/af_can.c2
-rw-r--r--net/can/bcm.c2
-rw-r--r--net/can/raw.c2
-rw-r--r--net/compat.c33
-rw-r--r--net/core/dev.c21
-rw-r--r--net/core/ethtool.c81
-rw-r--r--net/core/gen_stats.c8
-rw-r--r--net/core/net-sysfs.c46
-rw-r--r--net/core/pktgen.c11
-rw-r--r--net/core/sock.c17
-rw-r--r--net/dccp/ccids/ccid2.c327
-rw-r--r--net/dccp/ccids/ccid2.h46
-rw-r--r--net/dccp/ccids/ccid3.c400
-rw-r--r--net/dccp/ccids/ccid3.h120
-rw-r--r--net/dccp/ipv6.c12
-rw-r--r--net/dccp/probe.c16
-rw-r--r--net/dccp/proto.c13
-rw-r--r--net/decnet/af_decnet.c2
-rw-r--r--net/econet/af_econet.c10
-rw-r--r--net/ieee802154/af_ieee802154.c2
-rw-r--r--net/ieee802154/dgram.c2
-rw-r--r--net/ieee802154/raw.c2
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/fib_frontend.c26
-rw-r--r--net/ipv4/fib_hash.c25
-rw-r--r--net/ipv4/fib_rules.c2
-rw-r--r--net/ipv4/fib_trie.c26
-rw-r--r--net/ipv4/icmp.c4
-rw-r--r--net/ipv4/inet_connection_sock.c1
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c2
-rw-r--r--net/ipv4/ip_gre.c5
-rw-r--r--net/ipv4/ipip.c5
-rw-r--r--net/ipv4/ipmr.c12
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/syncookies.c3
-rw-r--r--net/ipv4/tcp.c11
-rw-r--r--net/ipv4/tcp_ipv4.c6
-rw-r--r--net/ipv4/udp.c93
-rw-r--r--net/ipv4/udplite.c4
-rw-r--r--net/ipv6/Kconfig19
-rw-r--r--net/ipv6/addrconf.c9
-rw-r--r--net/ipv6/af_inet6.c3
-rw-r--r--net/ipv6/datagram.c25
-rw-r--r--net/ipv6/inet6_connection_sock.c1
-rw-r--r--net/ipv6/inet6_hashtables.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c1
-rw-r--r--net/ipv6/ndisc.c1
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/route.c3
-rw-r--r--net/ipv6/sit.c134
-rw-r--r--net/ipv6/syncookies.c1
-rw-r--r--net/ipv6/tcp_ipv6.c16
-rw-r--r--net/ipv6/udp.c14
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/irda/af_irda.c2
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/mac80211/iface.c10
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/packet/af_packet.c14
-rw-r--r--net/phonet/af_phonet.c2
-rw-r--r--net/rds/af_rds.c2
-rw-r--r--net/rfkill/core.c1
-rw-r--r--net/rose/af_rose.c2
-rw-r--r--net/rxrpc/af_rxrpc.c2
-rw-r--r--net/rxrpc/ar-recvmsg.c2
-rw-r--r--net/sched/act_api.c3
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sched/sch_drr.c2
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sched/sch_htb.c2
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/socket.c247
-rw-r--r--net/sunrpc/svcauth_unix.c3
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--net/wireless/Kconfig50
-rw-r--r--net/wireless/Makefile10
-rw-r--r--net/wireless/core.c24
-rw-r--r--net/wireless/ethtool.c45
-rw-r--r--net/wireless/ethtool.h6
-rw-r--r--net/wireless/ibss.c10
-rw-r--r--net/wireless/mlme.c2
-rw-r--r--net/wireless/nl80211.c6
-rw-r--r--net/wireless/scan.c6
-rw-r--r--net/wireless/sme.c12
-rw-r--r--net/wireless/wext-core.c (renamed from net/wireless/wext.c)1456
-rw-r--r--net/wireless/wext-priv.c248
-rw-r--r--net/wireless/wext-proc.c155
-rw-r--r--net/wireless/wext-spy.c231
-rw-r--r--net/x25/af_x25.c4
110 files changed, 2335 insertions, 1922 deletions
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index b1a4290996b..abe38014b7f 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1821,7 +1821,7 @@ static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned lo
#endif
-static struct net_proto_family atalk_family_ops = {
+static const struct net_proto_family atalk_family_ops = {
.family = PF_APPLETALK,
.create = atalk_create,
.owner = THIS_MODULE,
diff --git a/net/atm/common.c b/net/atm/common.c
index 950bd16d238..d61e051e0a3 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -496,7 +496,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (error)
return error;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
atm_return(vcc, skb->truesize);
skb_free_datagram(sk, skb);
diff --git a/net/atm/pvc.c b/net/atm/pvc.c
index d4c024504f9..a6e1fdbae87 100644
--- a/net/atm/pvc.c
+++ b/net/atm/pvc.c
@@ -137,7 +137,7 @@ static int pvc_create(struct net *net, struct socket *sock,int protocol)
}
-static struct net_proto_family pvc_family_ops = {
+static const struct net_proto_family pvc_family_ops = {
.family = PF_ATMPVC,
.create = pvc_create,
.owner = THIS_MODULE,
diff --git a/net/atm/svc.c b/net/atm/svc.c
index f90d143c4b2..81935423331 100644
--- a/net/atm/svc.c
+++ b/net/atm/svc.c
@@ -666,7 +666,7 @@ static int svc_create(struct net *net, struct socket *sock,int protocol)
}
-static struct net_proto_family svc_family_ops = {
+static const struct net_proto_family svc_family_ops = {
.family = PF_ATMSVC,
.create = svc_create,
.owner = THIS_MODULE,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index f4546073037..f05306f168f 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1961,7 +1961,7 @@ static const struct file_operations ax25_info_fops = {
#endif
-static struct net_proto_family ax25_family_ops = {
+static const struct net_proto_family ax25_family_ops = {
.family = PF_AX25,
.create = ax25_create,
.owner = THIS_MODULE,
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8cfb5a84984..399e59c9c6c 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -45,7 +45,7 @@
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
-static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static const struct net_proto_family *bt_proto[BT_MAX_PROTO];
static DEFINE_RWLOCK(bt_proto_lock);
static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
@@ -86,7 +86,7 @@ static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
bt_key_strings[proto], &bt_lock_key[proto]);
}
-int bt_sock_register(int proto, struct net_proto_family *ops)
+int bt_sock_register(int proto, const struct net_proto_family *ops)
{
int err = 0;
@@ -257,7 +257,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb_reset_transport_header(skb);
err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
if (err == 0)
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
skb_free_datagram(sk, skb);
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index e857628b0b2..0a2c5460bb4 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -222,7 +222,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family bnep_sock_family_ops = {
+static const struct net_proto_family bnep_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = bnep_sock_create
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 16b0fad74f6..de7c8040bc5 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -217,7 +217,7 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family cmtp_sock_family_ops = {
+static const struct net_proto_family cmtp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = cmtp_sock_create
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 75302a98606..e7395f23198 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -687,7 +687,7 @@ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event,
return NOTIFY_DONE;
}
-static struct net_proto_family hci_sock_family_ops = {
+static const struct net_proto_family hci_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = hci_sock_create,
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 37c9d7d2e68..4beb6a7a295 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -268,7 +268,7 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
-static struct net_proto_family hidp_sock_family_ops = {
+static const struct net_proto_family hidp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = hidp_sock_create
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 555d9da1869..4b66bd579f4 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3916,7 +3916,7 @@ static const struct proto_ops l2cap_sock_ops = {
.getsockopt = l2cap_sock_getsockopt
};
-static struct net_proto_family l2cap_sock_family_ops = {
+static const struct net_proto_family l2cap_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = l2cap_sock_create,
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 8a20aaf1f23..d3bfc1b0afb 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -703,7 +703,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied += chunk;
size -= chunk;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (!(flags & MSG_PEEK)) {
atomic_sub(chunk, &sk->sk_rmem_alloc);
@@ -1101,7 +1101,7 @@ static const struct proto_ops rfcomm_sock_ops = {
.mmap = sock_no_mmap
};
-static struct net_proto_family rfcomm_sock_family_ops = {
+static const struct net_proto_family rfcomm_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = rfcomm_sock_create
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 77f4153bdb5..694a65541b7 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -993,7 +993,7 @@ static const struct proto_ops sco_sock_ops = {
.getsockopt = sco_sock_getsockopt
};
-static struct net_proto_family sco_sock_family_ops = {
+static const struct net_proto_family sco_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = sco_sock_create,
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 07a07770c8b..1a99c4e04e8 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -157,6 +157,7 @@ static const struct ethtool_ops br_ethtool_ops = {
.get_tso = ethtool_op_get_tso,
.set_tso = br_set_tso,
.get_ufo = ethtool_op_get_ufo,
+ .set_ufo = ethtool_op_set_ufo,
.get_flags = ethtool_op_get_flags,
};
diff --git a/net/can/af_can.c b/net/can/af_can.c
index 60683211567..3f2eb27e1ff 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -842,7 +842,7 @@ static struct packet_type can_packet __read_mostly = {
.func = can_rcv,
};
-static struct net_proto_family can_family_ops __read_mostly = {
+static const struct net_proto_family can_family_ops = {
.family = PF_CAN,
.create = can_create,
.owner = THIS_MODULE,
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 597da4f8f88..2f47039c79d 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1534,7 +1534,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/can/raw.c b/net/can/raw.c
index b5e897922d3..962fc9f1d0c 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -702,7 +702,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name) {
msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/compat.c b/net/compat.c
index a407c3addba..e13f5256fd2 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -727,10 +727,10 @@ EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[19]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)};
+ AL(4),AL(5)};
#undef AL
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -755,13 +755,36 @@ asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, size_t len,
return sys_recvfrom(fd, buf, len, flags | MSG_CMSG_COMPAT, addr, addrlen);
}
+asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
+ unsigned vlen, unsigned int flags,
+ struct timespec __user *timeout)
+{
+ int datagrams;
+ struct timespec ktspec;
+ struct compat_timespec __user *utspec =
+ (struct compat_timespec __user *)timeout;
+
+ if (get_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ get_user(ktspec.tv_nsec, &utspec->tv_nsec))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
+ flags | MSG_CMSG_COMPAT, &ktspec);
+ if (datagrams > 0 &&
+ (put_user(ktspec.tv_sec, &utspec->tv_sec) ||
+ put_user(ktspec.tv_nsec, &utspec->tv_nsec)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
{
int ret;
u32 a[6];
u32 a0, a1;
- if (call < SYS_SOCKET || call > SYS_ACCEPT4)
+ if (call < SYS_SOCKET || call > SYS_RECVMMSG)
return -EINVAL;
if (copy_from_user(a, args, nas[call]))
return -EFAULT;
@@ -823,6 +846,10 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
case SYS_RECVMSG:
ret = compat_sys_recvmsg(a0, compat_ptr(a1), a[2]);
break;
+ case SYS_RECVMMSG:
+ ret = compat_sys_recvmmsg(a0, compat_ptr(a1), a[2], a[3],
+ compat_ptr(a[4]));
+ break;
case SYS_ACCEPT4:
ret = sys_accept4(a0, compat_ptr(a1), compat_ptr(a[2]), a[3]);
break;
diff --git a/net/core/dev.c b/net/core/dev.c
index b8f74cfb1bf..28b0b9e992a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2604,20 +2604,13 @@ EXPORT_SYMBOL(napi_reuse_skb);
struct sk_buff *napi_get_frags(struct napi_struct *napi)
{
- struct net_device *dev = napi->dev;
struct sk_buff *skb = napi->skb;
if (!skb) {
- skb = netdev_alloc_skb(dev, GRO_MAX_HEAD + NET_IP_ALIGN);
- if (!skb)
- goto out;
-
- skb_reserve(skb, NET_IP_ALIGN);
-
- napi->skb = skb;
+ skb = netdev_alloc_skb_ip_align(napi->dev, GRO_MAX_HEAD);
+ if (skb)
+ napi->skb = skb;
}
-
-out:
return skb;
}
EXPORT_SYMBOL(napi_get_frags);
@@ -4836,6 +4829,12 @@ int register_netdevice(struct net_device *dev)
dev->features |= NETIF_F_GSO;
netdev_initialize_kobject(dev);
+
+ ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
+ ret = notifier_to_errno(ret);
+ if (ret)
+ goto err_uninit;
+
ret = netdev_register_kobject(dev);
if (ret)
goto err_uninit;
@@ -5483,7 +5482,7 @@ unsigned long netdev_increment_features(unsigned long all, unsigned long one,
one |= NETIF_F_ALL_CSUM;
one |= all & NETIF_F_ONE_FOR_ALL;
- all &= one | NETIF_F_LLTX | NETIF_F_GSO;
+ all &= one | NETIF_F_LLTX | NETIF_F_GSO | NETIF_F_UFO;
all |= one & mask & NETIF_F_ONE_FOR_ALL;
return all;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 4c12ddb5f5e..d8aee584e8d 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -198,13 +198,6 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
if (rc >= 0)
info.n_priv_flags = rc;
- } else {
- /* code path for obsolete hooks */
-
- if (ops->self_test_count)
- info.testinfo_len = ops->self_test_count(dev);
- if (ops->get_stats_count)
- info.n_stats = ops->get_stats_count(dev);
}
if (ops->get_regs_len)
info.regdump_len = ops->get_regs_len(dev);
@@ -309,6 +302,26 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
return ret;
}
+static int ethtool_reset(struct net_device *dev, char __user *useraddr)
+{
+ struct ethtool_value reset;
+ int ret;
+
+ if (!dev->ethtool_ops->reset)
+ return -EOPNOTSUPP;
+
+ if (copy_from_user(&reset, useraddr, sizeof(reset)))
+ return -EFAULT;
+
+ ret = dev->ethtool_ops->reset(dev, &reset.data);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(useraddr, &reset, sizeof(reset)))
+ return -EFAULT;
+ return 0;
+}
+
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
@@ -684,16 +697,10 @@ static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
u64 *data;
int ret, test_len;
- if (!ops->self_test)
- return -EOPNOTSUPP;
- if (!ops->get_sset_count && !ops->self_test_count)
+ if (!ops->self_test || !ops->get_sset_count)
return -EOPNOTSUPP;
- if (ops->get_sset_count)
- test_len = ops->get_sset_count(dev, ETH_SS_TEST);
- else
- /* code path for obsolete hook */
- test_len = ops->self_test_count(dev);
+ test_len = ops->get_sset_count(dev, ETH_SS_TEST);
if (test_len < 0)
return test_len;
WARN_ON(test_len == 0);
@@ -728,36 +735,17 @@ static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
u8 *data;
int ret;
- if (!ops->get_strings)
+ if (!ops->get_strings || !ops->get_sset_count)
return -EOPNOTSUPP;
if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
return -EFAULT;
- if (ops->get_sset_count) {
- ret = ops->get_sset_count(dev, gstrings.string_set);
- if (ret < 0)
- return ret;
-
- gstrings.len = ret;
- } else {
- /* code path for obsolete hooks */
-
- switch (gstrings.string_set) {
- case ETH_SS_TEST:
- if (!ops->self_test_count)
- return -EOPNOTSUPP;
- gstrings.len = ops->self_test_count(dev);
- break;
- case ETH_SS_STATS:
- if (!ops->get_stats_count)
- return -EOPNOTSUPP;
- gstrings.len = ops->get_stats_count(dev);
- break;
- default:
- return -EINVAL;
- }
- }
+ ret = ops->get_sset_count(dev, gstrings.string_set);
+ if (ret < 0)
+ return ret;
+
+ gstrings.len = ret;
data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
if (!data)
@@ -798,16 +786,10 @@ static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)
u64 *data;
int ret, n_stats;
- if (!ops->get_ethtool_stats)
- return -EOPNOTSUPP;
- if (!ops->get_sset_count && !ops->get_stats_count)
+ if (!ops->get_ethtool_stats || !ops->get_sset_count)
return -EOPNOTSUPP;
- if (ops->get_sset_count)
- n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
- else
- /* code path for obsolete hook */
- n_stats = ops->get_stats_count(dev);
+ n_stats = ops->get_sset_count(dev, ETH_SS_STATS);
if (n_stats < 0)
return n_stats;
WARN_ON(n_stats == 0);
@@ -1127,6 +1109,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_FLASHDEV:
rc = ethtool_flash_device(dev, useraddr);
break;
+ case ETHTOOL_RESET:
+ rc = ethtool_reset(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
diff --git a/net/core/gen_stats.c b/net/core/gen_stats.c
index 8569310268a..393b1d8618e 100644
--- a/net/core/gen_stats.c
+++ b/net/core/gen_stats.c
@@ -127,6 +127,7 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
/**
* gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV
* @d: dumping handle
+ * @b: basic statistics
* @r: rate estimator statistics
*
* Appends the rate estimator statistics to the top level TLV created by
@@ -136,8 +137,13 @@ gnet_stats_copy_basic(struct gnet_dump *d, struct gnet_stats_basic_packed *b)
* if the room in the socket buffer was not sufficient.
*/
int
-gnet_stats_copy_rate_est(struct gnet_dump *d, struct gnet_stats_rate_est *r)
+gnet_stats_copy_rate_est(struct gnet_dump *d,
+ const struct gnet_stats_basic_packed *b,
+ struct gnet_stats_rate_est *r)
{
+ if (b && !gen_estimator_active(b, r))
+ return 0;
+
if (d->compat_tc_stats) {
d->tc_stats.bps = r->bps;
d->tc_stats.pps = r->pps;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 427ded84122..753c420060d 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -130,6 +130,44 @@ static ssize_t show_carrier(struct device *dev,
return -EINVAL;
}
+static ssize_t show_speed(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (netif_running(netdev) && netdev->ethtool_ops->get_settings) {
+ struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+ if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
+ ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd));
+ }
+ rtnl_unlock();
+ return ret;
+}
+
+static ssize_t show_duplex(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ int ret = -EINVAL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ if (netif_running(netdev) && netdev->ethtool_ops->get_settings) {
+ struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+ if (!netdev->ethtool_ops->get_settings(netdev, &cmd))
+ ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half");
+ }
+ rtnl_unlock();
+ return ret;
+}
+
static ssize_t show_dormant(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -259,6 +297,8 @@ static struct device_attribute net_class_attributes[] = {
__ATTR(address, S_IRUGO, show_address, NULL),
__ATTR(broadcast, S_IRUGO, show_broadcast, NULL),
__ATTR(carrier, S_IRUGO, show_carrier, NULL),
+ __ATTR(speed, S_IRUGO, show_speed, NULL),
+ __ATTR(duplex, S_IRUGO, show_duplex, NULL),
__ATTR(dormant, S_IRUGO, show_dormant, NULL),
__ATTR(operstate, S_IRUGO, show_operstate, NULL),
__ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu),
@@ -503,9 +543,13 @@ int netdev_register_kobject(struct net_device *net)
*groups++ = &netstat_group;
#ifdef CONFIG_WIRELESS_EXT_SYSFS
- if (net->wireless_handlers || net->ieee80211_ptr)
+ if (net->ieee80211_ptr)
+ *groups++ = &wireless_group;
+#ifdef CONFIG_WIRELESS_EXT
+ else if (net->wireless_handlers)
*groups++ = &wireless_group;
#endif
+#endif
#endif /* CONFIG_SYSFS */
if (dev_net(net) != &init_net)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 86acdba0a97..1da0e038df7 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3441,12 +3441,14 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
txq = netdev_get_tx_queue(odev, queue_map);
__netif_tx_lock_bh(txq);
- atomic_inc(&(pkt_dev->skb->users));
- if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq)))
+ if (unlikely(netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq))) {
ret = NETDEV_TX_BUSY;
- else
- ret = (*xmit)(pkt_dev->skb, odev);
+ pkt_dev->last_ok = 0;
+ goto unlock;
+ }
+ atomic_inc(&(pkt_dev->skb->users));
+ ret = (*xmit)(pkt_dev->skb, odev);
switch (ret) {
case NETDEV_TX_OK:
@@ -3468,6 +3470,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
atomic_dec(&(pkt_dev->skb->users));
pkt_dev->last_ok = 0;
}
+unlock:
__netif_tx_unlock_bh(txq);
/* If pkt_dev->count is zero, then run forever */
diff --git a/net/core/sock.c b/net/core/sock.c
index 7626b6aacd6..43ca2c99539 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -276,6 +276,8 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
int err = 0;
int skb_len;
+ unsigned long flags;
+ struct sk_buff_head *list = &sk->sk_receive_queue;
/* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
number of warnings when compiling with -W --ANK
@@ -305,7 +307,10 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
*/
skb_len = skb->len;
- skb_queue_tail(&sk->sk_receive_queue, skb);
+ spin_lock_irqsave(&list->lock, flags);
+ skb->dropcount = atomic_read(&sk->sk_drops);
+ __skb_queue_tail(list, skb);
+ spin_unlock_irqrestore(&list->lock, flags);
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk, skb_len);
@@ -702,6 +707,12 @@ set_rcvbuf:
/* We implement the SO_SNDLOWAT etc to
not be settable (1003.1g 5.3) */
+ case SO_RXQ_OVFL:
+ if (valbool)
+ sock_set_flag(sk, SOCK_RXQ_OVFL);
+ else
+ sock_reset_flag(sk, SOCK_RXQ_OVFL);
+ break;
default:
ret = -ENOPROTOOPT;
break;
@@ -901,6 +912,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sk->sk_mark;
break;
+ case SO_RXQ_OVFL:
+ v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
+ break;
+
default:
return -ENOPROTOOPT;
}
diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c
index e8cf99e880b..a47a8c918ee 100644
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -33,20 +33,20 @@
static int ccid2_debug;
#define ccid2_pr_debug(format, a...) DCCP_PR_DEBUG(ccid2_debug, format, ##a)
-static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
+static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hc)
{
int len = 0;
int pipe = 0;
- struct ccid2_seq *seqp = hctx->ccid2hctx_seqh;
+ struct ccid2_seq *seqp = hc->tx_seqh;
/* there is data in the chain */
- if (seqp != hctx->ccid2hctx_seqt) {
+ if (seqp != hc->tx_seqt) {
seqp = seqp->ccid2s_prev;
len++;
if (!seqp->ccid2s_acked)
pipe++;
- while (seqp != hctx->ccid2hctx_seqt) {
+ while (seqp != hc->tx_seqt) {
struct ccid2_seq *prev = seqp->ccid2s_prev;
len++;
@@ -63,30 +63,30 @@ static void ccid2_hc_tx_check_sanity(const struct ccid2_hc_tx_sock *hctx)
}
}
- BUG_ON(pipe != hctx->ccid2hctx_pipe);
+ BUG_ON(pipe != hc->tx_pipe);
ccid2_pr_debug("len of chain=%d\n", len);
do {
seqp = seqp->ccid2s_prev;
len++;
- } while (seqp != hctx->ccid2hctx_seqh);
+ } while (seqp != hc->tx_seqh);
ccid2_pr_debug("total len=%d\n", len);
- BUG_ON(len != hctx->ccid2hctx_seqbufc * CCID2_SEQBUF_LEN);
+ BUG_ON(len != hc->tx_seqbufc * CCID2_SEQBUF_LEN);
}
#else
#define ccid2_pr_debug(format, a...)
-#define ccid2_hc_tx_check_sanity(hctx)
+#define ccid2_hc_tx_check_sanity(hc)
#endif
-static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx)
+static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hc)
{
struct ccid2_seq *seqp;
int i;
/* check if we have space to preserve the pointer to the buffer */
- if (hctx->ccid2hctx_seqbufc >= (sizeof(hctx->ccid2hctx_seqbuf) /
- sizeof(struct ccid2_seq*)))
+ if (hc->tx_seqbufc >= (sizeof(hc->tx_seqbuf) /
+ sizeof(struct ccid2_seq *)))
return -ENOMEM;
/* allocate buffer and initialize linked list */
@@ -102,29 +102,29 @@ static int ccid2_hc_tx_alloc_seq(struct ccid2_hc_tx_sock *hctx)
seqp->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
/* This is the first allocation. Initiate the head and tail. */
- if (hctx->ccid2hctx_seqbufc == 0)
- hctx->ccid2hctx_seqh = hctx->ccid2hctx_seqt = seqp;
+ if (hc->tx_seqbufc == 0)
+ hc->tx_seqh = hc->tx_seqt = seqp;
else {
/* link the existing list with the one we just created */
- hctx->ccid2hctx_seqh->ccid2s_next = seqp;
- seqp->ccid2s_prev = hctx->ccid2hctx_seqh;
+ hc->tx_seqh->ccid2s_next = seqp;
+ seqp->ccid2s_prev = hc->tx_seqh;
- hctx->ccid2hctx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
- seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hctx->ccid2hctx_seqt;
+ hc->tx_seqt->ccid2s_prev = &seqp[CCID2_SEQBUF_LEN - 1];
+ seqp[CCID2_SEQBUF_LEN - 1].ccid2s_next = hc->tx_seqt;
}
/* store the original pointer to the buffer so we can free it */
- hctx->ccid2hctx_seqbuf[hctx->ccid2hctx_seqbufc] = seqp;
- hctx->ccid2hctx_seqbufc++;
+ hc->tx_seqbuf[hc->tx_seqbufc] = seqp;
+ hc->tx_seqbufc++;
return 0;
}
static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_pipe < hctx->ccid2hctx_cwnd)
+ if (hc->tx_pipe < hc->tx_cwnd)
return 0;
return 1; /* XXX CCID should dequeue when ready instead of polling */
@@ -133,7 +133,7 @@ static int ccid2_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
{
struct dccp_sock *dp = dccp_sk(sk);
- u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->ccid2hctx_cwnd, 2);
+ u32 max_ratio = DIV_ROUND_UP(ccid2_hc_tx_sk(sk)->tx_cwnd, 2);
/*
* Ensure that Ack Ratio does not exceed ceil(cwnd/2), which is (2) from
@@ -155,10 +155,10 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val)
dp->dccps_l_ack_ratio = val;
}
-static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hctx, long val)
+static void ccid2_change_srtt(struct ccid2_hc_tx_sock *hc, long val)
{
ccid2_pr_debug("change SRTT to %ld\n", val);
- hctx->ccid2hctx_srtt = val;
+ hc->tx_srtt = val;
}
static void ccid2_start_rto_timer(struct sock *sk);
@@ -166,45 +166,44 @@ static void ccid2_start_rto_timer(struct sock *sk);
static void ccid2_hc_tx_rto_expire(unsigned long data)
{
struct sock *sk = (struct sock *)data;
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
long s;
bh_lock_sock(sk);
if (sock_owned_by_user(sk)) {
- sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
- jiffies + HZ / 5);
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5);
goto out;
}
ccid2_pr_debug("RTO_EXPIRE\n");
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
/* back-off timer */
- hctx->ccid2hctx_rto <<= 1;
+ hc->tx_rto <<= 1;
- s = hctx->ccid2hctx_rto / HZ;
+ s = hc->tx_rto / HZ;
if (s > 60)
- hctx->ccid2hctx_rto = 60 * HZ;
+ hc->tx_rto = 60 * HZ;
ccid2_start_rto_timer(sk);
/* adjust pipe, cwnd etc */
- hctx->ccid2hctx_ssthresh = hctx->ccid2hctx_cwnd / 2;
- if (hctx->ccid2hctx_ssthresh < 2)
- hctx->ccid2hctx_ssthresh = 2;
- hctx->ccid2hctx_cwnd = 1;
- hctx->ccid2hctx_pipe = 0;
+ hc->tx_ssthresh = hc->tx_cwnd / 2;
+ if (hc->tx_ssthresh < 2)
+ hc->tx_ssthresh = 2;
+ hc->tx_cwnd = 1;
+ hc->tx_pipe = 0;
/* clear state about stuff we sent */
- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqh;
- hctx->ccid2hctx_packets_acked = 0;
+ hc->tx_seqt = hc->tx_seqh;
+ hc->tx_packets_acked = 0;
/* clear ack ratio state. */
- hctx->ccid2hctx_rpseq = 0;
- hctx->ccid2hctx_rpdupack = -1;
+ hc->tx_rpseq = 0;
+ hc->tx_rpdupack = -1;
ccid2_change_l_ack_ratio(sk, 1);
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
out:
bh_unlock_sock(sk);
sock_put(sk);
@@ -212,42 +211,40 @@ out:
static void ccid2_start_rto_timer(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- ccid2_pr_debug("setting RTO timeout=%ld\n", hctx->ccid2hctx_rto);
+ ccid2_pr_debug("setting RTO timeout=%ld\n", hc->tx_rto);
- BUG_ON(timer_pending(&hctx->ccid2hctx_rtotimer));
- sk_reset_timer(sk, &hctx->ccid2hctx_rtotimer,
- jiffies + hctx->ccid2hctx_rto);
+ BUG_ON(timer_pending(&hc->tx_rtotimer));
+ sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto);
}
static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
struct ccid2_seq *next;
- hctx->ccid2hctx_pipe++;
+ hc->tx_pipe++;
- hctx->ccid2hctx_seqh->ccid2s_seq = dp->dccps_gss;
- hctx->ccid2hctx_seqh->ccid2s_acked = 0;
- hctx->ccid2hctx_seqh->ccid2s_sent = jiffies;
+ hc->tx_seqh->ccid2s_seq = dp->dccps_gss;
+ hc->tx_seqh->ccid2s_acked = 0;
+ hc->tx_seqh->ccid2s_sent = jiffies;
- next = hctx->ccid2hctx_seqh->ccid2s_next;
+ next = hc->tx_seqh->ccid2s_next;
/* check if we need to alloc more space */
- if (next == hctx->ccid2hctx_seqt) {
- if (ccid2_hc_tx_alloc_seq(hctx)) {
+ if (next == hc->tx_seqt) {
+ if (ccid2_hc_tx_alloc_seq(hc)) {
DCCP_CRIT("packet history - out of memory!");
/* FIXME: find a more graceful way to bail out */
return;
}
- next = hctx->ccid2hctx_seqh->ccid2s_next;
- BUG_ON(next == hctx->ccid2hctx_seqt);
+ next = hc->tx_seqh->ccid2s_next;
+ BUG_ON(next == hc->tx_seqt);
}
- hctx->ccid2hctx_seqh = next;
+ hc->tx_seqh = next;
- ccid2_pr_debug("cwnd=%d pipe=%d\n", hctx->ccid2hctx_cwnd,
- hctx->ccid2hctx_pipe);
+ ccid2_pr_debug("cwnd=%d pipe=%d\n", hc->tx_cwnd, hc->tx_pipe);
/*
* FIXME: The code below is broken and the variables have been removed
@@ -270,12 +267,12 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
*/
#if 0
/* Ack Ratio. Need to maintain a concept of how many windows we sent */
- hctx->ccid2hctx_arsent++;
+ hc->tx_arsent++;
/* We had an ack loss in this window... */
- if (hctx->ccid2hctx_ackloss) {
- if (hctx->ccid2hctx_arsent >= hctx->ccid2hctx_cwnd) {
- hctx->ccid2hctx_arsent = 0;
- hctx->ccid2hctx_ackloss = 0;
+ if (hc->tx_ackloss) {
+ if (hc->tx_arsent >= hc->tx_cwnd) {
+ hc->tx_arsent = 0;
+ hc->tx_ackloss = 0;
}
} else {
/* No acks lost up to now... */
@@ -285,28 +282,28 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
int denom = dp->dccps_l_ack_ratio * dp->dccps_l_ack_ratio -
dp->dccps_l_ack_ratio;
- denom = hctx->ccid2hctx_cwnd * hctx->ccid2hctx_cwnd / denom;
+ denom = hc->tx_cwnd * hc->tx_cwnd / denom;
- if (hctx->ccid2hctx_arsent >= denom) {
+ if (hc->tx_arsent >= denom) {
ccid2_change_l_ack_ratio(sk, dp->dccps_l_ack_ratio - 1);
- hctx->ccid2hctx_arsent = 0;
+ hc->tx_arsent = 0;
}
} else {
/* we can't increase ack ratio further [1] */
- hctx->ccid2hctx_arsent = 0; /* or maybe set it to cwnd*/
+ hc->tx_arsent = 0; /* or maybe set it to cwnd*/
}
}
#endif
/* setup RTO timer */
- if (!timer_pending(&hctx->ccid2hctx_rtotimer))
+ if (!timer_pending(&hc->tx_rtotimer))
ccid2_start_rto_timer(sk);
#ifdef CONFIG_IP_DCCP_CCID2_DEBUG
do {
- struct ccid2_seq *seqp = hctx->ccid2hctx_seqt;
+ struct ccid2_seq *seqp = hc->tx_seqt;
- while (seqp != hctx->ccid2hctx_seqh) {
+ while (seqp != hc->tx_seqh) {
ccid2_pr_debug("out seq=%llu acked=%d time=%lu\n",
(unsigned long long)seqp->ccid2s_seq,
seqp->ccid2s_acked, seqp->ccid2s_sent);
@@ -314,7 +311,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, int more, unsigned int len)
}
} while (0);
ccid2_pr_debug("=========\n");
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
#endif
}
@@ -382,9 +379,9 @@ out_invalid_option:
static void ccid2_hc_tx_kill_rto_timer(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- sk_stop_timer(sk, &hctx->ccid2hctx_rtotimer);
+ sk_stop_timer(sk, &hc->tx_rtotimer);
ccid2_pr_debug("deleted RTO timer\n");
}
@@ -392,75 +389,75 @@ static inline void ccid2_new_ack(struct sock *sk,
struct ccid2_seq *seqp,
unsigned int *maxincr)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh) {
- if (*maxincr > 0 && ++hctx->ccid2hctx_packets_acked == 2) {
- hctx->ccid2hctx_cwnd += 1;
- *maxincr -= 1;
- hctx->ccid2hctx_packets_acked = 0;
+ if (hc->tx_cwnd < hc->tx_ssthresh) {
+ if (*maxincr > 0 && ++hc->tx_packets_acked == 2) {
+ hc->tx_cwnd += 1;
+ *maxincr -= 1;
+ hc->tx_packets_acked = 0;
}
- } else if (++hctx->ccid2hctx_packets_acked >= hctx->ccid2hctx_cwnd) {
- hctx->ccid2hctx_cwnd += 1;
- hctx->ccid2hctx_packets_acked = 0;
+ } else if (++hc->tx_packets_acked >= hc->tx_cwnd) {
+ hc->tx_cwnd += 1;
+ hc->tx_packets_acked = 0;
}
/* update RTO */
- if (hctx->ccid2hctx_srtt == -1 ||
- time_after(jiffies, hctx->ccid2hctx_lastrtt + hctx->ccid2hctx_srtt)) {
+ if (hc->tx_srtt == -1 ||
+ time_after(jiffies, hc->tx_lastrtt + hc->tx_srtt)) {
unsigned long r = (long)jiffies - (long)seqp->ccid2s_sent;
int s;
/* first measurement */
- if (hctx->ccid2hctx_srtt == -1) {
+ if (hc->tx_srtt == -1) {
ccid2_pr_debug("R: %lu Time=%lu seq=%llu\n",
r, jiffies,
(unsigned long long)seqp->ccid2s_seq);
- ccid2_change_srtt(hctx, r);
- hctx->ccid2hctx_rttvar = r >> 1;
+ ccid2_change_srtt(hc, r);
+ hc->tx_rttvar = r >> 1;
} else {
/* RTTVAR */
- long tmp = hctx->ccid2hctx_srtt - r;
+ long tmp = hc->tx_srtt - r;
long srtt;
if (tmp < 0)
tmp *= -1;
tmp >>= 2;
- hctx->ccid2hctx_rttvar *= 3;
- hctx->ccid2hctx_rttvar >>= 2;
- hctx->ccid2hctx_rttvar += tmp;
+ hc->tx_rttvar *= 3;
+ hc->tx_rttvar >>= 2;
+ hc->tx_rttvar += tmp;
/* SRTT */
- srtt = hctx->ccid2hctx_srtt;
+ srtt = hc->tx_srtt;
srtt *= 7;
srtt >>= 3;
tmp = r >> 3;
srtt += tmp;
- ccid2_change_srtt(hctx, srtt);
+ ccid2_change_srtt(hc, srtt);
}
- s = hctx->ccid2hctx_rttvar << 2;
+ s = hc->tx_rttvar << 2;
/* clock granularity is 1 when based on jiffies */
if (!s)
s = 1;
- hctx->ccid2hctx_rto = hctx->ccid2hctx_srtt + s;
+ hc->tx_rto = hc->tx_srtt + s;
/* must be at least a second */
- s = hctx->ccid2hctx_rto / HZ;
+ s = hc->tx_rto / HZ;
/* DCCP doesn't require this [but I like it cuz my code sux] */
#if 1
if (s < 1)
- hctx->ccid2hctx_rto = HZ;
+ hc->tx_rto = HZ;
#endif
/* max 60 seconds */
if (s > 60)
- hctx->ccid2hctx_rto = HZ * 60;
+ hc->tx_rto = HZ * 60;
- hctx->ccid2hctx_lastrtt = jiffies;
+ hc->tx_lastrtt = jiffies;
ccid2_pr_debug("srtt: %ld rttvar: %ld rto: %ld (HZ=%d) R=%lu\n",
- hctx->ccid2hctx_srtt, hctx->ccid2hctx_rttvar,
- hctx->ccid2hctx_rto, HZ, r);
+ hc->tx_srtt, hc->tx_rttvar,
+ hc->tx_rto, HZ, r);
}
/* we got a new ack, so re-start RTO timer */
@@ -470,40 +467,40 @@ static inline void ccid2_new_ack(struct sock *sk,
static void ccid2_hc_tx_dec_pipe(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (hctx->ccid2hctx_pipe == 0)
+ if (hc->tx_pipe == 0)
DCCP_BUG("pipe == 0");
else
- hctx->ccid2hctx_pipe--;
+ hc->tx_pipe--;
- if (hctx->ccid2hctx_pipe == 0)
+ if (hc->tx_pipe == 0)
ccid2_hc_tx_kill_rto_timer(sk);
}
static void ccid2_congestion_event(struct sock *sk, struct ccid2_seq *seqp)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
- if (time_before(seqp->ccid2s_sent, hctx->ccid2hctx_last_cong)) {
+ if (time_before(seqp->ccid2s_sent, hc->tx_last_cong)) {
ccid2_pr_debug("Multiple losses in an RTT---treating as one\n");
return;
}
- hctx->ccid2hctx_last_cong = jiffies;
+ hc->tx_last_cong = jiffies;
- hctx->ccid2hctx_cwnd = hctx->ccid2hctx_cwnd / 2 ? : 1U;
- hctx->ccid2hctx_ssthresh = max(hctx->ccid2hctx_cwnd, 2U);
+ hc->tx_cwnd = hc->tx_cwnd / 2 ? : 1U;
+ hc->tx_ssthresh = max(hc->tx_cwnd, 2U);
/* Avoid spurious timeouts resulting from Ack Ratio > cwnd */
- if (dccp_sk(sk)->dccps_l_ack_ratio > hctx->ccid2hctx_cwnd)
- ccid2_change_l_ack_ratio(sk, hctx->ccid2hctx_cwnd);
+ if (dccp_sk(sk)->dccps_l_ack_ratio > hc->tx_cwnd)
+ ccid2_change_l_ack_ratio(sk, hc->tx_cwnd);
}
static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
u64 ackno, seqno;
struct ccid2_seq *seqp;
unsigned char *vector;
@@ -512,7 +509,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
int done = 0;
unsigned int maxincr = 0;
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
/* check reverse path congestion */
seqno = DCCP_SKB_CB(skb)->dccpd_seq;
@@ -521,21 +518,21 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* -sorbo.
*/
/* need to bootstrap */
- if (hctx->ccid2hctx_rpdupack == -1) {
- hctx->ccid2hctx_rpdupack = 0;
- hctx->ccid2hctx_rpseq = seqno;
+ if (hc->tx_rpdupack == -1) {
+ hc->tx_rpdupack = 0;
+ hc->tx_rpseq = seqno;
} else {
/* check if packet is consecutive */
- if (dccp_delta_seqno(hctx->ccid2hctx_rpseq, seqno) == 1)
- hctx->ccid2hctx_rpseq = seqno;
+ if (dccp_delta_seqno(hc->tx_rpseq, seqno) == 1)
+ hc->tx_rpseq = seqno;
/* it's a later packet */
- else if (after48(seqno, hctx->ccid2hctx_rpseq)) {
- hctx->ccid2hctx_rpdupack++;
+ else if (after48(seqno, hc->tx_rpseq)) {
+ hc->tx_rpdupack++;
/* check if we got enough dupacks */
- if (hctx->ccid2hctx_rpdupack >= NUMDUPACK) {
- hctx->ccid2hctx_rpdupack = -1; /* XXX lame */
- hctx->ccid2hctx_rpseq = 0;
+ if (hc->tx_rpdupack >= NUMDUPACK) {
+ hc->tx_rpdupack = -1; /* XXX lame */
+ hc->tx_rpseq = 0;
ccid2_change_l_ack_ratio(sk, 2 * dp->dccps_l_ack_ratio);
}
@@ -544,7 +541,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* check forward path congestion */
/* still didn't send out new data packets */
- if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
+ if (hc->tx_seqh == hc->tx_seqt)
return;
switch (DCCP_SKB_CB(skb)->dccpd_type) {
@@ -556,14 +553,14 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
- if (after48(ackno, hctx->ccid2hctx_high_ack))
- hctx->ccid2hctx_high_ack = ackno;
+ if (after48(ackno, hc->tx_high_ack))
+ hc->tx_high_ack = ackno;
- seqp = hctx->ccid2hctx_seqt;
+ seqp = hc->tx_seqt;
while (before48(seqp->ccid2s_seq, ackno)) {
seqp = seqp->ccid2s_next;
- if (seqp == hctx->ccid2hctx_seqh) {
- seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+ if (seqp == hc->tx_seqh) {
+ seqp = hc->tx_seqh->ccid2s_prev;
break;
}
}
@@ -573,7 +570,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* packets per acknowledgement. Rounding up avoids that cwnd is not
* advanced when Ack Ratio is 1 and gives a slight edge otherwise.
*/
- if (hctx->ccid2hctx_cwnd < hctx->ccid2hctx_ssthresh)
+ if (hc->tx_cwnd < hc->tx_ssthresh)
maxincr = DIV_ROUND_UP(dp->dccps_l_ack_ratio, 2);
/* go through all ack vectors */
@@ -592,7 +589,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* seqnos.
*/
while (after48(seqp->ccid2s_seq, ackno)) {
- if (seqp == hctx->ccid2hctx_seqt) {
+ if (seqp == hc->tx_seqt) {
done = 1;
break;
}
@@ -624,7 +621,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
(unsigned long long)seqp->ccid2s_seq);
ccid2_hc_tx_dec_pipe(sk);
}
- if (seqp == hctx->ccid2hctx_seqt) {
+ if (seqp == hc->tx_seqt) {
done = 1;
break;
}
@@ -643,11 +640,11 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
/* The state about what is acked should be correct now
* Check for NUMDUPACK
*/
- seqp = hctx->ccid2hctx_seqt;
- while (before48(seqp->ccid2s_seq, hctx->ccid2hctx_high_ack)) {
+ seqp = hc->tx_seqt;
+ while (before48(seqp->ccid2s_seq, hc->tx_high_ack)) {
seqp = seqp->ccid2s_next;
- if (seqp == hctx->ccid2hctx_seqh) {
- seqp = hctx->ccid2hctx_seqh->ccid2s_prev;
+ if (seqp == hc->tx_seqh) {
+ seqp = hc->tx_seqh->ccid2s_prev;
break;
}
}
@@ -658,7 +655,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (done == NUMDUPACK)
break;
}
- if (seqp == hctx->ccid2hctx_seqt)
+ if (seqp == hc->tx_seqt)
break;
seqp = seqp->ccid2s_prev;
}
@@ -681,86 +678,86 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
ccid2_congestion_event(sk, seqp);
ccid2_hc_tx_dec_pipe(sk);
}
- if (seqp == hctx->ccid2hctx_seqt)
+ if (seqp == hc->tx_seqt)
break;
seqp = seqp->ccid2s_prev;
}
- hctx->ccid2hctx_seqt = last_acked;
+ hc->tx_seqt = last_acked;
}
/* trim acked packets in tail */
- while (hctx->ccid2hctx_seqt != hctx->ccid2hctx_seqh) {
- if (!hctx->ccid2hctx_seqt->ccid2s_acked)
+ while (hc->tx_seqt != hc->tx_seqh) {
+ if (!hc->tx_seqt->ccid2s_acked)
break;
- hctx->ccid2hctx_seqt = hctx->ccid2hctx_seqt->ccid2s_next;
+ hc->tx_seqt = hc->tx_seqt->ccid2s_next;
}
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
}
static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid_priv(ccid);
+ struct ccid2_hc_tx_sock *hc = ccid_priv(ccid);
struct dccp_sock *dp = dccp_sk(sk);
u32 max_ratio;
/* RFC 4341, 5: initialise ssthresh to arbitrarily high (max) value */
- hctx->ccid2hctx_ssthresh = ~0U;
+ hc->tx_ssthresh = ~0U;
/*
* RFC 4341, 5: "The cwnd parameter is initialized to at most four
* packets for new connections, following the rules from [RFC3390]".
* We need to convert the bytes of RFC3390 into the packets of RFC 4341.
*/
- hctx->ccid2hctx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
+ hc->tx_cwnd = clamp(4380U / dp->dccps_mss_cache, 2U, 4U);
/* Make sure that Ack Ratio is enabled and within bounds. */
- max_ratio = DIV_ROUND_UP(hctx->ccid2hctx_cwnd, 2);
+ max_ratio = DIV_ROUND_UP(hc->tx_cwnd, 2);
if (dp->dccps_l_ack_ratio == 0 || dp->dccps_l_ack_ratio > max_ratio)
dp->dccps_l_ack_ratio = max_ratio;
/* XXX init ~ to window size... */
- if (ccid2_hc_tx_alloc_seq(hctx))
+ if (ccid2_hc_tx_alloc_seq(hc))
return -ENOMEM;
- hctx->ccid2hctx_rto = 3 * HZ;
- ccid2_change_srtt(hctx, -1);
- hctx->ccid2hctx_rttvar = -1;
- hctx->ccid2hctx_rpdupack = -1;
- hctx->ccid2hctx_last_cong = jiffies;
- setup_timer(&hctx->ccid2hctx_rtotimer, ccid2_hc_tx_rto_expire,
+ hc->tx_rto = 3 * HZ;
+ ccid2_change_srtt(hc, -1);
+ hc->tx_rttvar = -1;
+ hc->tx_rpdupack = -1;
+ hc->tx_last_cong = jiffies;
+ setup_timer(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire,
(unsigned long)sk);
- ccid2_hc_tx_check_sanity(hctx);
+ ccid2_hc_tx_check_sanity(hc);
return 0;
}
static void ccid2_hc_tx_exit(struct sock *sk)
{
- struct ccid2_hc_tx_sock *hctx = ccid2_hc_tx_sk(sk);
+ struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk);
int i;
ccid2_hc_tx_kill_rto_timer(sk);
- for (i = 0; i < hctx->ccid2hctx_seqbufc; i++)
- kfree(hctx->ccid2hctx_seqbuf[i]);
- hctx->ccid2hctx_seqbufc = 0;
+ for (i = 0; i < hc->tx_seqbufc; i++)
+ kfree(hc->tx_seqbuf[i]);
+ hc->tx_seqbufc = 0;
}
static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
const struct dccp_sock *dp = dccp_sk(sk);
- struct ccid2_hc_rx_sock *hcrx = ccid2_hc_rx_sk(sk);
+ struct ccid2_hc_rx_sock *hc = ccid2_hc_rx_sk(sk);
switch (DCCP_SKB_CB(skb)->dccpd_type) {
case DCCP_PKT_DATA:
case DCCP_PKT_DATAACK:
- hcrx->ccid2hcrx_data++;
- if (hcrx->ccid2hcrx_data >= dp->dccps_r_ack_ratio) {
+ hc->rx_data++;
+ if (hc->rx_data >= dp->dccps_r_ack_ratio) {
dccp_send_ack(sk);
- hcrx->ccid2hcrx_data = 0;
+ hc->rx_data = 0;
}
break;
}
diff --git a/net/dccp/ccids/ccid2.h b/net/dccp/ccids/ccid2.h
index 326ac90fb90..1ec6a30103b 100644
--- a/net/dccp/ccids/ccid2.h
+++ b/net/dccp/ccids/ccid2.h
@@ -40,34 +40,34 @@ struct ccid2_seq {
/**
* struct ccid2_hc_tx_sock - CCID2 TX half connection
- * @ccid2hctx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
- * @ccid2hctx_packets_acked - Ack counter for deriving cwnd growth (RFC 3465)
- * @ccid2hctx_lastrtt -time RTT was last measured
- * @ccid2hctx_rpseq - last consecutive seqno
- * @ccid2hctx_rpdupack - dupacks since rpseq
+ * @tx_{cwnd,ssthresh,pipe}: as per RFC 4341, section 5
+ * @tx_packets_acked: Ack counter for deriving cwnd growth (RFC 3465)
+ * @tx_lastrtt: time RTT was last measured
+ * @tx_rpseq: last consecutive seqno
+ * @tx_rpdupack: dupacks since rpseq
*/
struct ccid2_hc_tx_sock {
- u32 ccid2hctx_cwnd;
- u32 ccid2hctx_ssthresh;
- u32 ccid2hctx_pipe;
- u32 ccid2hctx_packets_acked;
- struct ccid2_seq *ccid2hctx_seqbuf[CCID2_SEQBUF_MAX];
- int ccid2hctx_seqbufc;
- struct ccid2_seq *ccid2hctx_seqh;
- struct ccid2_seq *ccid2hctx_seqt;
- long ccid2hctx_rto;
- long ccid2hctx_srtt;
- long ccid2hctx_rttvar;
- unsigned long ccid2hctx_lastrtt;
- struct timer_list ccid2hctx_rtotimer;
- u64 ccid2hctx_rpseq;
- int ccid2hctx_rpdupack;
- unsigned long ccid2hctx_last_cong;
- u64 ccid2hctx_high_ack;
+ u32 tx_cwnd;
+ u32 tx_ssthresh;
+ u32 tx_pipe;
+ u32 tx_packets_acked;
+ struct ccid2_seq *tx_seqbuf[CCID2_SEQBUF_MAX];
+ int tx_seqbufc;
+ struct ccid2_seq *tx_seqh;
+ struct ccid2_seq *tx_seqt;
+ long tx_rto;
+ long tx_srtt;
+ long tx_rttvar;
+ unsigned long tx_lastrtt;
+ struct timer_list tx_rtotimer;
+ u64 tx_rpseq;
+ int tx_rpdupack;
+ unsigned long tx_last_cong;
+ u64 tx_high_ack;
};
struct ccid2_hc_rx_sock {
- int ccid2hcrx_data;
+ int rx_data;
};
static inline struct ccid2_hc_tx_sock *ccid2_hc_tx_sk(const struct sock *sk)
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 34dcc798c45..bcd7632299f 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -64,14 +64,14 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
static void ccid3_hc_tx_set_state(struct sock *sk,
enum ccid3_hc_tx_states state)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- enum ccid3_hc_tx_states oldstate = hctx->ccid3hctx_state;
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ enum ccid3_hc_tx_states oldstate = hc->tx_state;
ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
dccp_role(sk), sk, ccid3_tx_state_name(oldstate),
ccid3_tx_state_name(state));
WARN_ON(state == oldstate);
- hctx->ccid3hctx_state = state;
+ hc->tx_state = state;
}
/*
@@ -85,37 +85,32 @@ static void ccid3_hc_tx_set_state(struct sock *sk,
*/
static inline u64 rfc3390_initial_rate(struct sock *sk)
{
- const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- const __u32 w_init = clamp_t(__u32, 4380U,
- 2 * hctx->ccid3hctx_s, 4 * hctx->ccid3hctx_s);
+ const struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ const __u32 w_init = clamp_t(__u32, 4380U, 2 * hc->tx_s, 4 * hc->tx_s);
- return scaled_div(w_init << 6, hctx->ccid3hctx_rtt);
+ return scaled_div(w_init << 6, hc->tx_rtt);
}
/*
* Recalculate t_ipi and delta (should be called whenever X changes)
*/
-static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hctx)
+static void ccid3_update_send_interval(struct ccid3_hc_tx_sock *hc)
{
/* Calculate new t_ipi = s / X_inst (X_inst is in 64 * bytes/second) */
- hctx->ccid3hctx_t_ipi = scaled_div32(((u64)hctx->ccid3hctx_s) << 6,
- hctx->ccid3hctx_x);
+ hc->tx_t_ipi = scaled_div32(((u64)hc->tx_s) << 6, hc->tx_x);
/* Calculate new delta by delta = min(t_ipi / 2, t_gran / 2) */
- hctx->ccid3hctx_delta = min_t(u32, hctx->ccid3hctx_t_ipi / 2,
- TFRC_OPSYS_HALF_TIME_GRAN);
-
- ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n",
- hctx->ccid3hctx_t_ipi, hctx->ccid3hctx_delta,
- hctx->ccid3hctx_s, (unsigned)(hctx->ccid3hctx_x >> 6));
+ hc->tx_delta = min_t(u32, hc->tx_t_ipi / 2, TFRC_OPSYS_HALF_TIME_GRAN);
+ ccid3_pr_debug("t_ipi=%u, delta=%u, s=%u, X=%u\n", hc->tx_t_ipi,
+ hc->tx_delta, hc->tx_s, (unsigned)(hc->tx_x >> 6));
}
-static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hctx, ktime_t now)
+static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hc, ktime_t now)
{
- u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count);
+ u32 delta = ktime_us_delta(now, hc->tx_t_last_win_count);
- return delta / hctx->ccid3hctx_rtt;
+ return delta / hc->tx_rtt;
}
/**
@@ -130,9 +125,9 @@ static u32 ccid3_hc_tx_idle_rtt(struct ccid3_hc_tx_sock *hctx, ktime_t now)
*/
static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- __u64 min_rate = 2 * hctx->ccid3hctx_x_recv;
- const __u64 old_x = hctx->ccid3hctx_x;
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
+ __u64 min_rate = 2 * hc->tx_x_recv;
+ const __u64 old_x = hc->tx_x;
ktime_t now = stamp ? *stamp : ktime_get_real();
/*
@@ -141,37 +136,31 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
* a sender is idle if it has not sent anything over a 2-RTT-period.
* For consistency with X and X_recv, min_rate is also scaled by 2^6.
*/
- if (ccid3_hc_tx_idle_rtt(hctx, now) >= 2) {
+ if (ccid3_hc_tx_idle_rtt(hc, now) >= 2) {
min_rate = rfc3390_initial_rate(sk);
- min_rate = max(min_rate, 2 * hctx->ccid3hctx_x_recv);
+ min_rate = max(min_rate, 2 * hc->tx_x_recv);
}
- if (hctx->ccid3hctx_p > 0) {
+ if (hc->tx_p > 0) {
- hctx->ccid3hctx_x = min(((__u64)hctx->ccid3hctx_x_calc) << 6,
- min_rate);
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- TFRC_T_MBI);
+ hc->tx_x = min(((__u64)hc->tx_x_calc) << 6, min_rate);
+ hc->tx_x = max(hc->tx_x, (((__u64)hc->tx_s) << 6) / TFRC_T_MBI);
- } else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld)
- - (s64)hctx->ccid3hctx_rtt >= 0) {
+ } else if (ktime_us_delta(now, hc->tx_t_ld) - (s64)hc->tx_rtt >= 0) {
- hctx->ccid3hctx_x = min(2 * hctx->ccid3hctx_x, min_rate);
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x,
- scaled_div(((__u64)hctx->ccid3hctx_s) << 6,
- hctx->ccid3hctx_rtt));
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_x = min(2 * hc->tx_x, min_rate);
+ hc->tx_x = max(hc->tx_x,
+ scaled_div(((__u64)hc->tx_s) << 6, hc->tx_rtt));
+ hc->tx_t_ld = now;
}
- if (hctx->ccid3hctx_x != old_x) {
+ if (hc->tx_x != old_x) {
ccid3_pr_debug("X_prev=%u, X_now=%u, X_calc=%u, "
"X_recv=%u\n", (unsigned)(old_x >> 6),
- (unsigned)(hctx->ccid3hctx_x >> 6),
- hctx->ccid3hctx_x_calc,
- (unsigned)(hctx->ccid3hctx_x_recv >> 6));
+ (unsigned)(hc->tx_x >> 6), hc->tx_x_calc,
+ (unsigned)(hc->tx_x_recv >> 6));
- ccid3_update_send_interval(hctx);
+ ccid3_update_send_interval(hc);
}
}
@@ -179,37 +168,37 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp)
* Track the mean packet size `s' (cf. RFC 4342, 5.3 and RFC 3448, 4.1)
* @len: DCCP packet payload size in bytes
*/
-static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
+static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hc, int len)
{
- const u16 old_s = hctx->ccid3hctx_s;
+ const u16 old_s = hc->tx_s;
- hctx->ccid3hctx_s = tfrc_ewma(hctx->ccid3hctx_s, len, 9);
+ hc->tx_s = tfrc_ewma(hc->tx_s, len, 9);
- if (hctx->ccid3hctx_s != old_s)
- ccid3_update_send_interval(hctx);
+ if (hc->tx_s != old_s)
+ ccid3_update_send_interval(hc);
}
/*
* Update Window Counter using the algorithm from [RFC 4342, 8.1].
* As elsewhere, RTT > 0 is assumed by using dccp_sample_rtt().
*/
-static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
+static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc,
ktime_t now)
{
- u32 delta = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count),
- quarter_rtts = (4 * delta) / hctx->ccid3hctx_rtt;
+ u32 delta = ktime_us_delta(now, hc->tx_t_last_win_count),
+ quarter_rtts = (4 * delta) / hc->tx_rtt;
if (quarter_rtts > 0) {
- hctx->ccid3hctx_t_last_win_count = now;
- hctx->ccid3hctx_last_win_count += min(quarter_rtts, 5U);
- hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */
+ hc->tx_t_last_win_count = now;
+ hc->tx_last_win_count += min(quarter_rtts, 5U);
+ hc->tx_last_win_count &= 0xF; /* mod 16 */
}
}
static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
{
struct sock *sk = (struct sock *)data;
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
unsigned long t_nfb = USEC_PER_SEC / 5;
bh_lock_sock(sk);
@@ -220,24 +209,23 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
}
ccid3_pr_debug("%s(%p, state=%s) - entry \n", dccp_role(sk), sk,
- ccid3_tx_state_name(hctx->ccid3hctx_state));
+ ccid3_tx_state_name(hc->tx_state));
- if (hctx->ccid3hctx_state == TFRC_SSTATE_FBACK)
+ if (hc->tx_state == TFRC_SSTATE_FBACK)
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
- else if (hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)
+ else if (hc->tx_state != TFRC_SSTATE_NO_FBACK)
goto out;
/*
* Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
*/
- if (hctx->ccid3hctx_t_rto == 0 || /* no feedback received yet */
- hctx->ccid3hctx_p == 0) {
+ if (hc->tx_t_rto == 0 || /* no feedback received yet */
+ hc->tx_p == 0) {
/* halve send rate directly */
- hctx->ccid3hctx_x = max(hctx->ccid3hctx_x / 2,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- TFRC_T_MBI);
- ccid3_update_send_interval(hctx);
+ hc->tx_x = max(hc->tx_x / 2,
+ (((__u64)hc->tx_s) << 6) / TFRC_T_MBI);
+ ccid3_update_send_interval(hc);
} else {
/*
* Modify the cached value of X_recv
@@ -249,33 +237,32 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
*
* Note that X_recv is scaled by 2^6 while X_calc is not
*/
- BUG_ON(hctx->ccid3hctx_p && !hctx->ccid3hctx_x_calc);
+ BUG_ON(hc->tx_p && !hc->tx_x_calc);
- if (hctx->ccid3hctx_x_calc > (hctx->ccid3hctx_x_recv >> 5))
- hctx->ccid3hctx_x_recv =
- max(hctx->ccid3hctx_x_recv / 2,
- (((__u64)hctx->ccid3hctx_s) << 6) /
- (2 * TFRC_T_MBI));
+ if (hc->tx_x_calc > (hc->tx_x_recv >> 5))
+ hc->tx_x_recv =
+ max(hc->tx_x_recv / 2,
+ (((__u64)hc->tx_s) << 6) / (2*TFRC_T_MBI));
else {
- hctx->ccid3hctx_x_recv = hctx->ccid3hctx_x_calc;
- hctx->ccid3hctx_x_recv <<= 4;
+ hc->tx_x_recv = hc->tx_x_calc;
+ hc->tx_x_recv <<= 4;
}
ccid3_hc_tx_update_x(sk, NULL);
}
ccid3_pr_debug("Reduced X to %llu/64 bytes/sec\n",
- (unsigned long long)hctx->ccid3hctx_x);
+ (unsigned long long)hc->tx_x);
/*
* Set new timeout for the nofeedback timer.
* See comments in packet_recv() regarding the value of t_RTO.
*/
- if (unlikely(hctx->ccid3hctx_t_rto == 0)) /* no feedback yet */
+ if (unlikely(hc->tx_t_rto == 0)) /* no feedback yet */
t_nfb = TFRC_INITIAL_TIMEOUT;
else
- t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
+ t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
restart_timer:
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer,
jiffies + usecs_to_jiffies(t_nfb));
out:
bh_unlock_sock(sk);
@@ -291,7 +278,7 @@ out:
static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
ktime_t now = ktime_get_real();
s64 delay;
@@ -303,18 +290,17 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
if (unlikely(skb->len == 0))
return -EBADMSG;
- switch (hctx->ccid3hctx_state) {
+ switch (hc->tx_state) {
case TFRC_SSTATE_NO_SENT:
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
- (jiffies +
- usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
- hctx->ccid3hctx_last_win_count = 0;
- hctx->ccid3hctx_t_last_win_count = now;
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
+ usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
+ hc->tx_last_win_count = 0;
+ hc->tx_t_last_win_count = now;
/* Set t_0 for initial packet */
- hctx->ccid3hctx_t_nom = now;
+ hc->tx_t_nom = now;
- hctx->ccid3hctx_s = skb->len;
+ hc->tx_s = skb->len;
/*
* Use initial RTT sample when available: recommended by erratum
@@ -323,9 +309,9 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
*/
if (dp->dccps_syn_rtt) {
ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt);
- hctx->ccid3hctx_rtt = dp->dccps_syn_rtt;
- hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_rtt = dp->dccps_syn_rtt;
+ hc->tx_x = rfc3390_initial_rate(sk);
+ hc->tx_t_ld = now;
} else {
/*
* Sender does not have RTT sample:
@@ -333,17 +319,17 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
* is needed in several parts (e.g. window counter);
* - set sending rate X_pps = 1pps as per RFC 3448, 4.2.
*/
- hctx->ccid3hctx_rtt = DCCP_FALLBACK_RTT;
- hctx->ccid3hctx_x = hctx->ccid3hctx_s;
- hctx->ccid3hctx_x <<= 6;
+ hc->tx_rtt = DCCP_FALLBACK_RTT;
+ hc->tx_x = hc->tx_s;
+ hc->tx_x <<= 6;
}
- ccid3_update_send_interval(hctx);
+ ccid3_update_send_interval(hc);
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
break;
case TFRC_SSTATE_NO_FBACK:
case TFRC_SSTATE_FBACK:
- delay = ktime_us_delta(hctx->ccid3hctx_t_nom, now);
+ delay = ktime_us_delta(hc->tx_t_nom, now);
ccid3_pr_debug("delay=%ld\n", (long)delay);
/*
* Scheduling of packet transmissions [RFC 3448, 4.6]
@@ -353,10 +339,10 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
* else
* // send the packet in (t_nom - t_now) milliseconds.
*/
- if (delay - (s64)hctx->ccid3hctx_delta >= 1000)
+ if (delay - (s64)hc->tx_delta >= 1000)
return (u32)delay / 1000L;
- ccid3_hc_tx_update_win_count(hctx, now);
+ ccid3_hc_tx_update_win_count(hc, now);
break;
case TFRC_SSTATE_TERM:
DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
@@ -365,28 +351,27 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
/* prepare to send now (add options etc.) */
dp->dccps_hc_tx_insert_options = 1;
- DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
+ DCCP_SKB_CB(skb)->dccpd_ccval = hc->tx_last_win_count;
/* set the nominal send time for the next following packet */
- hctx->ccid3hctx_t_nom = ktime_add_us(hctx->ccid3hctx_t_nom,
- hctx->ccid3hctx_t_ipi);
+ hc->tx_t_nom = ktime_add_us(hc->tx_t_nom, hc->tx_t_ipi);
return 0;
}
static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
unsigned int len)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
- ccid3_hc_tx_update_s(hctx, len);
+ ccid3_hc_tx_update_s(hc, len);
- if (tfrc_tx_hist_add(&hctx->ccid3hctx_hist, dccp_sk(sk)->dccps_gss))
+ if (tfrc_tx_hist_add(&hc->tx_hist, dccp_sk(sk)->dccps_gss))
DCCP_CRIT("packet history - out of memory!");
}
static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
struct ccid3_options_received *opt_recv;
ktime_t now;
unsigned long t_nfb;
@@ -397,15 +382,15 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
return;
/* ... and only in the established state */
- if (hctx->ccid3hctx_state != TFRC_SSTATE_FBACK &&
- hctx->ccid3hctx_state != TFRC_SSTATE_NO_FBACK)
+ if (hc->tx_state != TFRC_SSTATE_FBACK &&
+ hc->tx_state != TFRC_SSTATE_NO_FBACK)
return;
- opt_recv = &hctx->ccid3hctx_options_received;
+ opt_recv = &hc->tx_options_received;
now = ktime_get_real();
/* Estimate RTT from history if ACK number is valid */
- r_sample = tfrc_tx_hist_rtt(hctx->ccid3hctx_hist,
+ r_sample = tfrc_tx_hist_rtt(hc->tx_hist,
DCCP_SKB_CB(skb)->dccpd_ack_seq, now);
if (r_sample == 0) {
DCCP_WARN("%s(%p): %s with bogus ACK-%llu\n", dccp_role(sk), sk,
@@ -415,37 +400,37 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
/* Update receive rate in units of 64 * bytes/second */
- hctx->ccid3hctx_x_recv = opt_recv->ccid3or_receive_rate;
- hctx->ccid3hctx_x_recv <<= 6;
+ hc->tx_x_recv = opt_recv->ccid3or_receive_rate;
+ hc->tx_x_recv <<= 6;
/* Update loss event rate (which is scaled by 1e6) */
pinv = opt_recv->ccid3or_loss_event_rate;
if (pinv == ~0U || pinv == 0) /* see RFC 4342, 8.5 */
- hctx->ccid3hctx_p = 0;
+ hc->tx_p = 0;
else /* can not exceed 100% */
- hctx->ccid3hctx_p = scaled_div(1, pinv);
+ hc->tx_p = scaled_div(1, pinv);
/*
* Validate new RTT sample and update moving average
*/
r_sample = dccp_sample_rtt(sk, r_sample);
- hctx->ccid3hctx_rtt = tfrc_ewma(hctx->ccid3hctx_rtt, r_sample, 9);
+ hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9);
/*
* Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3
*/
- if (hctx->ccid3hctx_state == TFRC_SSTATE_NO_FBACK) {
+ if (hc->tx_state == TFRC_SSTATE_NO_FBACK) {
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_FBACK);
- if (hctx->ccid3hctx_t_rto == 0) {
+ if (hc->tx_t_rto == 0) {
/*
* Initial feedback packet: Larger Initial Windows (4.2)
*/
- hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
- hctx->ccid3hctx_t_ld = now;
+ hc->tx_x = rfc3390_initial_rate(sk);
+ hc->tx_t_ld = now;
- ccid3_update_send_interval(hctx);
+ ccid3_update_send_interval(hc);
goto done_computing_x;
- } else if (hctx->ccid3hctx_p == 0) {
+ } else if (hc->tx_p == 0) {
/*
* First feedback after nofeedback timer expiry (4.3)
*/
@@ -454,25 +439,20 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
/* Update sending rate (step 4 of [RFC 3448, 4.3]) */
- if (hctx->ccid3hctx_p > 0)
- hctx->ccid3hctx_x_calc =
- tfrc_calc_x(hctx->ccid3hctx_s,
- hctx->ccid3hctx_rtt,
- hctx->ccid3hctx_p);
+ if (hc->tx_p > 0)
+ hc->tx_x_calc = tfrc_calc_x(hc->tx_s, hc->tx_rtt, hc->tx_p);
ccid3_hc_tx_update_x(sk, &now);
done_computing_x:
ccid3_pr_debug("%s(%p), RTT=%uus (sample=%uus), s=%u, "
"p=%u, X_calc=%u, X_recv=%u, X=%u\n",
- dccp_role(sk),
- sk, hctx->ccid3hctx_rtt, r_sample,
- hctx->ccid3hctx_s, hctx->ccid3hctx_p,
- hctx->ccid3hctx_x_calc,
- (unsigned)(hctx->ccid3hctx_x_recv >> 6),
- (unsigned)(hctx->ccid3hctx_x >> 6));
+ dccp_role(sk), sk, hc->tx_rtt, r_sample,
+ hc->tx_s, hc->tx_p, hc->tx_x_calc,
+ (unsigned)(hc->tx_x_recv >> 6),
+ (unsigned)(hc->tx_x >> 6));
/* unschedule no feedback timer */
- sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
+ sk_stop_timer(sk, &hc->tx_no_feedback_timer);
/*
* As we have calculated new ipi, delta, t_nom it is possible
@@ -486,21 +466,19 @@ done_computing_x:
* This can help avoid triggering the nofeedback timer too
* often ('spinning') on LANs with small RTTs.
*/
- hctx->ccid3hctx_t_rto = max_t(u32, 4 * hctx->ccid3hctx_rtt,
- (CONFIG_IP_DCCP_CCID3_RTO *
- (USEC_PER_SEC / 1000)));
+ hc->tx_t_rto = max_t(u32, 4 * hc->tx_rtt, (CONFIG_IP_DCCP_CCID3_RTO *
+ (USEC_PER_SEC / 1000)));
/*
* Schedule no feedback timer to expire in
* max(t_RTO, 2 * s/X) = max(t_RTO, 2 * t_ipi)
*/
- t_nfb = max(hctx->ccid3hctx_t_rto, 2 * hctx->ccid3hctx_t_ipi);
+ t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);
ccid3_pr_debug("%s(%p), Scheduled no feedback timer to "
"expire in %lu jiffies (%luus)\n",
- dccp_role(sk),
- sk, usecs_to_jiffies(t_nfb), t_nfb);
+ dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb);
- sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
+ sk_reset_timer(sk, &hc->tx_no_feedback_timer,
jiffies + usecs_to_jiffies(t_nfb));
}
@@ -510,11 +488,11 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
{
int rc = 0;
const struct dccp_sock *dp = dccp_sk(sk);
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
struct ccid3_options_received *opt_recv;
__be32 opt_val;
- opt_recv = &hctx->ccid3hctx_options_received;
+ opt_recv = &hc->tx_options_received;
if (opt_recv->ccid3or_seqno != dp->dccps_gsr) {
opt_recv->ccid3or_seqno = dp->dccps_gsr;
@@ -568,56 +546,55 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid3_hc_tx_sock *hctx = ccid_priv(ccid);
+ struct ccid3_hc_tx_sock *hc = ccid_priv(ccid);
- hctx->ccid3hctx_state = TFRC_SSTATE_NO_SENT;
- hctx->ccid3hctx_hist = NULL;
- setup_timer(&hctx->ccid3hctx_no_feedback_timer,
+ hc->tx_state = TFRC_SSTATE_NO_SENT;
+ hc->tx_hist = NULL;
+ setup_timer(&hc->tx_no_feedback_timer,
ccid3_hc_tx_no_feedback_timer, (unsigned long)sk);
-
return 0;
}
static void ccid3_hc_tx_exit(struct sock *sk)
{
- struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
+ struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
- sk_stop_timer(sk, &hctx->ccid3hctx_no_feedback_timer);
+ sk_stop_timer(sk, &hc->tx_no_feedback_timer);
- tfrc_tx_hist_purge(&hctx->ccid3hctx_hist);
+ tfrc_tx_hist_purge(&hc->tx_hist);
}
static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
{
- struct ccid3_hc_tx_sock *hctx;
+ struct ccid3_hc_tx_sock *hc;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return;
- hctx = ccid3_hc_tx_sk(sk);
- info->tcpi_rto = hctx->ccid3hctx_t_rto;
- info->tcpi_rtt = hctx->ccid3hctx_rtt;
+ hc = ccid3_hc_tx_sk(sk);
+ info->tcpi_rto = hc->tx_t_rto;
+ info->tcpi_rtt = hc->tx_rtt;
}
static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_tx_sock *hctx;
+ const struct ccid3_hc_tx_sock *hc;
const void *val;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
- hctx = ccid3_hc_tx_sk(sk);
+ hc = ccid3_hc_tx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_TX_INFO:
- if (len < sizeof(hctx->ccid3hctx_tfrc))
+ if (len < sizeof(hc->tx_tfrc))
return -EINVAL;
- len = sizeof(hctx->ccid3hctx_tfrc);
- val = &hctx->ccid3hctx_tfrc;
+ len = sizeof(hc->tx_tfrc);
+ val = &hc->tx_tfrc;
break;
default:
return -ENOPROTOOPT;
@@ -657,34 +634,34 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
static void ccid3_hc_rx_set_state(struct sock *sk,
enum ccid3_hc_rx_states state)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- enum ccid3_hc_rx_states oldstate = hcrx->ccid3hcrx_state;
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
+ enum ccid3_hc_rx_states oldstate = hc->rx_state;
ccid3_pr_debug("%s(%p) %-8.8s -> %s\n",
dccp_role(sk), sk, ccid3_rx_state_name(oldstate),
ccid3_rx_state_name(state));
WARN_ON(state == oldstate);
- hcrx->ccid3hcrx_state = state;
+ hc->rx_state = state;
}
static void ccid3_hc_rx_send_feedback(struct sock *sk,
const struct sk_buff *skb,
enum ccid3_fback_type fbtype)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
ktime_t now;
s64 delta = 0;
- if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_TERM))
+ if (unlikely(hc->rx_state == TFRC_RSTATE_TERM))
return;
now = ktime_get_real();
switch (fbtype) {
case CCID3_FBACK_INITIAL:
- hcrx->ccid3hcrx_x_recv = 0;
- hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */
+ hc->rx_x_recv = 0;
+ hc->rx_pinv = ~0U; /* see RFC 4342, 8.5 */
break;
case CCID3_FBACK_PARAM_CHANGE:
/*
@@ -697,27 +674,26 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
* the number of bytes since last feedback.
* This is a safe fallback, since X is bounded above by X_calc.
*/
- if (hcrx->ccid3hcrx_x_recv > 0)
+ if (hc->rx_x_recv > 0)
break;
/* fall through */
case CCID3_FBACK_PERIODIC:
- delta = ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_feedback);
+ delta = ktime_us_delta(now, hc->rx_tstamp_last_feedback);
if (delta <= 0)
DCCP_BUG("delta (%ld) <= 0", (long)delta);
else
- hcrx->ccid3hcrx_x_recv =
- scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ hc->rx_x_recv = scaled_div32(hc->rx_bytes_recv, delta);
break;
default:
return;
}
ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta,
- hcrx->ccid3hcrx_x_recv, hcrx->ccid3hcrx_pinv);
+ hc->rx_x_recv, hc->rx_pinv);
- hcrx->ccid3hcrx_tstamp_last_feedback = now;
- hcrx->ccid3hcrx_last_counter = dccp_hdr(skb)->dccph_ccval;
- hcrx->ccid3hcrx_bytes_recv = 0;
+ hc->rx_tstamp_last_feedback = now;
+ hc->rx_last_counter = dccp_hdr(skb)->dccph_ccval;
+ hc->rx_bytes_recv = 0;
dp->dccps_hc_rx_insert_options = 1;
dccp_send_ack(sk);
@@ -725,19 +701,19 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
- const struct ccid3_hc_rx_sock *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
__be32 x_recv, pinv;
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return 0;
- hcrx = ccid3_hc_rx_sk(sk);
+ hc = ccid3_hc_rx_sk(sk);
if (dccp_packet_without_ack(skb))
return 0;
- x_recv = htonl(hcrx->ccid3hcrx_x_recv);
- pinv = htonl(hcrx->ccid3hcrx_pinv);
+ x_recv = htonl(hc->rx_x_recv);
+ pinv = htonl(hc->rx_pinv);
if (dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv)) ||
@@ -760,26 +736,26 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
*/
static u32 ccid3_first_li(struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
u32 x_recv, p, delta;
u64 fval;
- if (hcrx->ccid3hcrx_rtt == 0) {
+ if (hc->rx_rtt == 0) {
DCCP_WARN("No RTT estimate available, using fallback RTT\n");
- hcrx->ccid3hcrx_rtt = DCCP_FALLBACK_RTT;
+ hc->rx_rtt = DCCP_FALLBACK_RTT;
}
- delta = ktime_to_us(net_timedelta(hcrx->ccid3hcrx_tstamp_last_feedback));
- x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ delta = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback));
+ x_recv = scaled_div32(hc->rx_bytes_recv, delta);
if (x_recv == 0) { /* would also trigger divide-by-zero */
DCCP_WARN("X_recv==0\n");
- if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) {
+ if ((x_recv = hc->rx_x_recv) == 0) {
DCCP_BUG("stored value of X_recv is zero");
return ~0U;
}
}
- fval = scaled_div(hcrx->ccid3hcrx_s, hcrx->ccid3hcrx_rtt);
+ fval = scaled_div(hc->rx_s, hc->rx_rtt);
fval = scaled_div32(fval, x_recv);
p = tfrc_calc_x_reverse_lookup(fval);
@@ -791,19 +767,19 @@ static u32 ccid3_first_li(struct sock *sk)
static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
enum ccid3_fback_type do_feedback = CCID3_FBACK_NONE;
const u64 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
const bool is_data_packet = dccp_data_packet(skb);
- if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) {
+ if (unlikely(hc->rx_state == TFRC_RSTATE_NO_DATA)) {
if (is_data_packet) {
const u32 payload = skb->len - dccp_hdr(skb)->dccph_doff * 4;
do_feedback = CCID3_FBACK_INITIAL;
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
- hcrx->ccid3hcrx_s = payload;
+ hc->rx_s = payload;
/*
- * Not necessary to update ccid3hcrx_bytes_recv here,
+ * Not necessary to update rx_bytes_recv here,
* since X_recv = 0 for the first feedback packet (cf.
* RFC 3448, 6.3) -- gerrit
*/
@@ -811,7 +787,7 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
goto update_records;
}
- if (tfrc_rx_hist_duplicate(&hcrx->ccid3hcrx_hist, skb))
+ if (tfrc_rx_hist_duplicate(&hc->rx_hist, skb))
return; /* done receiving */
if (is_data_packet) {
@@ -819,20 +795,20 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
/*
* Update moving-average of s and the sum of received payload bytes
*/
- hcrx->ccid3hcrx_s = tfrc_ewma(hcrx->ccid3hcrx_s, payload, 9);
- hcrx->ccid3hcrx_bytes_recv += payload;
+ hc->rx_s = tfrc_ewma(hc->rx_s, payload, 9);
+ hc->rx_bytes_recv += payload;
}
/*
* Perform loss detection and handle pending losses
*/
- if (tfrc_rx_handle_loss(&hcrx->ccid3hcrx_hist, &hcrx->ccid3hcrx_li_hist,
+ if (tfrc_rx_handle_loss(&hc->rx_hist, &hc->rx_li_hist,
skb, ndp, ccid3_first_li, sk)) {
do_feedback = CCID3_FBACK_PARAM_CHANGE;
goto done_receiving;
}
- if (tfrc_rx_hist_loss_pending(&hcrx->ccid3hcrx_hist))
+ if (tfrc_rx_hist_loss_pending(&hc->rx_hist))
return; /* done receiving */
/*
@@ -841,17 +817,17 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely(!is_data_packet))
goto update_records;
- if (!tfrc_lh_is_initialised(&hcrx->ccid3hcrx_li_hist)) {
- const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->ccid3hcrx_hist, skb);
+ if (!tfrc_lh_is_initialised(&hc->rx_li_hist)) {
+ const u32 sample = tfrc_rx_hist_sample_rtt(&hc->rx_hist, skb);
/*
* Empty loss history: no loss so far, hence p stays 0.
* Sample RTT values, since an RTT estimate is required for the
* computation of p when the first loss occurs; RFC 3448, 6.3.1.
*/
if (sample != 0)
- hcrx->ccid3hcrx_rtt = tfrc_ewma(hcrx->ccid3hcrx_rtt, sample, 9);
+ hc->rx_rtt = tfrc_ewma(hc->rx_rtt, sample, 9);
- } else if (tfrc_lh_update_i_mean(&hcrx->ccid3hcrx_li_hist, skb)) {
+ } else if (tfrc_lh_update_i_mean(&hc->rx_li_hist, skb)) {
/*
* Step (3) of [RFC 3448, 6.1]: Recompute I_mean and, if I_mean
* has decreased (resp. p has increased), send feedback now.
@@ -862,11 +838,11 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
/*
* Check if the periodic once-per-RTT feedback is due; RFC 4342, 10.3
*/
- if (SUB16(dccp_hdr(skb)->dccph_ccval, hcrx->ccid3hcrx_last_counter) > 3)
+ if (SUB16(dccp_hdr(skb)->dccph_ccval, hc->rx_last_counter) > 3)
do_feedback = CCID3_FBACK_PERIODIC;
update_records:
- tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist, skb, ndp);
+ tfrc_rx_hist_add_packet(&hc->rx_hist, skb, ndp);
done_receiving:
if (do_feedback)
@@ -875,41 +851,41 @@ done_receiving:
static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid_priv(ccid);
+ struct ccid3_hc_rx_sock *hc = ccid_priv(ccid);
- hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
- tfrc_lh_init(&hcrx->ccid3hcrx_li_hist);
- return tfrc_rx_hist_alloc(&hcrx->ccid3hcrx_hist);
+ hc->rx_state = TFRC_RSTATE_NO_DATA;
+ tfrc_lh_init(&hc->rx_li_hist);
+ return tfrc_rx_hist_alloc(&hc->rx_hist);
}
static void ccid3_hc_rx_exit(struct sock *sk)
{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
+ struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
- tfrc_rx_hist_purge(&hcrx->ccid3hcrx_hist);
- tfrc_lh_cleanup(&hcrx->ccid3hcrx_li_hist);
+ tfrc_rx_hist_purge(&hc->rx_hist);
+ tfrc_lh_cleanup(&hc->rx_li_hist);
}
static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
{
- const struct ccid3_hc_rx_sock *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
/* Listen socks doesn't have a private CCID block */
if (sk->sk_state == DCCP_LISTEN)
return;
- hcrx = ccid3_hc_rx_sk(sk);
- info->tcpi_ca_state = hcrx->ccid3hcrx_state;
+ hc = ccid3_hc_rx_sk(sk);
+ info->tcpi_ca_state = hc->rx_state;
info->tcpi_options |= TCPI_OPT_TIMESTAMPS;
- info->tcpi_rcv_rtt = hcrx->ccid3hcrx_rtt;
+ info->tcpi_rcv_rtt = hc->rx_rtt;
}
static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
u32 __user *optval, int __user *optlen)
{
- const struct ccid3_hc_rx_sock *hcrx;
+ const struct ccid3_hc_rx_sock *hc;
struct tfrc_rx_info rx_info;
const void *val;
@@ -917,15 +893,15 @@ static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
if (sk->sk_state == DCCP_LISTEN)
return -EINVAL;
- hcrx = ccid3_hc_rx_sk(sk);
+ hc = ccid3_hc_rx_sk(sk);
switch (optname) {
case DCCP_SOCKOPT_CCID_RX_INFO:
if (len < sizeof(rx_info))
return -EINVAL;
- rx_info.tfrcrx_x_recv = hcrx->ccid3hcrx_x_recv;
- rx_info.tfrcrx_rtt = hcrx->ccid3hcrx_rtt;
- rx_info.tfrcrx_p = hcrx->ccid3hcrx_pinv == 0 ? ~0U :
- scaled_div(1, hcrx->ccid3hcrx_pinv);
+ rx_info.tfrcrx_x_recv = hc->rx_x_recv;
+ rx_info.tfrcrx_rtt = hc->rx_rtt;
+ rx_info.tfrcrx_p = hc->rx_pinv == 0 ? ~0U :
+ scaled_div(1, hc->rx_pinv);
len = sizeof(rx_info);
val = &rx_info;
break;
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index e5a24414384..03263577665 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -75,44 +75,44 @@ enum ccid3_hc_tx_states {
/**
* struct ccid3_hc_tx_sock - CCID3 sender half-connection socket
- * @ccid3hctx_x - Current sending rate in 64 * bytes per second
- * @ccid3hctx_x_recv - Receive rate in 64 * bytes per second
- * @ccid3hctx_x_calc - Calculated rate in bytes per second
- * @ccid3hctx_rtt - Estimate of current round trip time in usecs
- * @ccid3hctx_p - Current loss event rate (0-1) scaled by 1000000
- * @ccid3hctx_s - Packet size in bytes
- * @ccid3hctx_t_rto - Nofeedback Timer setting in usecs
- * @ccid3hctx_t_ipi - Interpacket (send) interval (RFC 3448, 4.6) in usecs
- * @ccid3hctx_state - Sender state, one of %ccid3_hc_tx_states
- * @ccid3hctx_last_win_count - Last window counter sent
- * @ccid3hctx_t_last_win_count - Timestamp of earliest packet
- * with last_win_count value sent
- * @ccid3hctx_no_feedback_timer - Handle to no feedback timer
- * @ccid3hctx_t_ld - Time last doubled during slow start
- * @ccid3hctx_t_nom - Nominal send time of next packet
- * @ccid3hctx_delta - Send timer delta (RFC 3448, 4.6) in usecs
- * @ccid3hctx_hist - Packet history
- * @ccid3hctx_options_received - Parsed set of retrieved options
+ * @tx_x: Current sending rate in 64 * bytes per second
+ * @tx_x_recv: Receive rate in 64 * bytes per second
+ * @tx_x_calc: Calculated rate in bytes per second
+ * @tx_rtt: Estimate of current round trip time in usecs
+ * @tx_p: Current loss event rate (0-1) scaled by 1000000
+ * @tx_s: Packet size in bytes
+ * @tx_t_rto: Nofeedback Timer setting in usecs
+ * @tx_t_ipi: Interpacket (send) interval (RFC 3448, 4.6) in usecs
+ * @tx_state: Sender state, one of %ccid3_hc_tx_states
+ * @tx_last_win_count: Last window counter sent
+ * @tx_t_last_win_count: Timestamp of earliest packet
+ * with last_win_count value sent
+ * @tx_no_feedback_timer: Handle to no feedback timer
+ * @tx_t_ld: Time last doubled during slow start
+ * @tx_t_nom: Nominal send time of next packet
+ * @tx_delta: Send timer delta (RFC 3448, 4.6) in usecs
+ * @tx_hist: Packet history
+ * @tx_options_received: Parsed set of retrieved options
*/
struct ccid3_hc_tx_sock {
- struct tfrc_tx_info ccid3hctx_tfrc;
-#define ccid3hctx_x ccid3hctx_tfrc.tfrctx_x
-#define ccid3hctx_x_recv ccid3hctx_tfrc.tfrctx_x_recv
-#define ccid3hctx_x_calc ccid3hctx_tfrc.tfrctx_x_calc
-#define ccid3hctx_rtt ccid3hctx_tfrc.tfrctx_rtt
-#define ccid3hctx_p ccid3hctx_tfrc.tfrctx_p
-#define ccid3hctx_t_rto ccid3hctx_tfrc.tfrctx_rto
-#define ccid3hctx_t_ipi ccid3hctx_tfrc.tfrctx_ipi
- u16 ccid3hctx_s;
- enum ccid3_hc_tx_states ccid3hctx_state:8;
- u8 ccid3hctx_last_win_count;
- ktime_t ccid3hctx_t_last_win_count;
- struct timer_list ccid3hctx_no_feedback_timer;
- ktime_t ccid3hctx_t_ld;
- ktime_t ccid3hctx_t_nom;
- u32 ccid3hctx_delta;
- struct tfrc_tx_hist_entry *ccid3hctx_hist;
- struct ccid3_options_received ccid3hctx_options_received;
+ struct tfrc_tx_info tx_tfrc;
+#define tx_x tx_tfrc.tfrctx_x
+#define tx_x_recv tx_tfrc.tfrctx_x_recv
+#define tx_x_calc tx_tfrc.tfrctx_x_calc
+#define tx_rtt tx_tfrc.tfrctx_rtt
+#define tx_p tx_tfrc.tfrctx_p
+#define tx_t_rto tx_tfrc.tfrctx_rto
+#define tx_t_ipi tx_tfrc.tfrctx_ipi
+ u16 tx_s;
+ enum ccid3_hc_tx_states tx_state:8;
+ u8 tx_last_win_count;
+ ktime_t tx_t_last_win_count;
+ struct timer_list tx_no_feedback_timer;
+ ktime_t tx_t_ld;
+ ktime_t tx_t_nom;
+ u32 tx_delta;
+ struct tfrc_tx_hist_entry *tx_hist;
+ struct ccid3_options_received tx_options_received;
};
static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
@@ -131,32 +131,32 @@ enum ccid3_hc_rx_states {
/**
* struct ccid3_hc_rx_sock - CCID3 receiver half-connection socket
- * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448 4.3)
- * @ccid3hcrx_rtt - Receiver estimate of rtt (non-standard)
- * @ccid3hcrx_p - Current loss event rate (RFC 3448 5.4)
- * @ccid3hcrx_last_counter - Tracks window counter (RFC 4342, 8.1)
- * @ccid3hcrx_state - Receiver state, one of %ccid3_hc_rx_states
- * @ccid3hcrx_bytes_recv - Total sum of DCCP payload bytes
- * @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448, sec. 4.3)
- * @ccid3hcrx_rtt - Receiver estimate of RTT
- * @ccid3hcrx_tstamp_last_feedback - Time at which last feedback was sent
- * @ccid3hcrx_tstamp_last_ack - Time at which last feedback was sent
- * @ccid3hcrx_hist - Packet history (loss detection + RTT sampling)
- * @ccid3hcrx_li_hist - Loss Interval database
- * @ccid3hcrx_s - Received packet size in bytes
- * @ccid3hcrx_pinv - Inverse of Loss Event Rate (RFC 4342, sec. 8.5)
+ * @rx_x_recv: Receiver estimate of send rate (RFC 3448 4.3)
+ * @rx_rtt: Receiver estimate of rtt (non-standard)
+ * @rx_p: Current loss event rate (RFC 3448 5.4)
+ * @rx_last_counter: Tracks window counter (RFC 4342, 8.1)
+ * @rx_state: Receiver state, one of %ccid3_hc_rx_states
+ * @rx_bytes_recv: Total sum of DCCP payload bytes
+ * @rx_x_recv: Receiver estimate of send rate (RFC 3448, sec. 4.3)
+ * @rx_rtt: Receiver estimate of RTT
+ * @rx_tstamp_last_feedback: Time at which last feedback was sent
+ * @rx_tstamp_last_ack: Time at which last feedback was sent
+ * @rx_hist: Packet history (loss detection + RTT sampling)
+ * @rx_li_hist: Loss Interval database
+ * @rx_s: Received packet size in bytes
+ * @rx_pinv: Inverse of Loss Event Rate (RFC 4342, sec. 8.5)
*/
struct ccid3_hc_rx_sock {
- u8 ccid3hcrx_last_counter:4;
- enum ccid3_hc_rx_states ccid3hcrx_state:8;
- u32 ccid3hcrx_bytes_recv;
- u32 ccid3hcrx_x_recv;
- u32 ccid3hcrx_rtt;
- ktime_t ccid3hcrx_tstamp_last_feedback;
- struct tfrc_rx_hist ccid3hcrx_hist;
- struct tfrc_loss_hist ccid3hcrx_li_hist;
- u16 ccid3hcrx_s;
-#define ccid3hcrx_pinv ccid3hcrx_li_hist.i_mean
+ u8 rx_last_counter:4;
+ enum ccid3_hc_rx_states rx_state:8;
+ u32 rx_bytes_recv;
+ u32 rx_x_recv;
+ u32 rx_rtt;
+ ktime_t rx_tstamp_last_feedback;
+ struct tfrc_rx_hist rx_hist;
+ struct tfrc_loss_hist rx_li_hist;
+ u16 rx_s;
+#define rx_pinv rx_li_hist.i_mean
};
static inline struct ccid3_hc_rx_sock *ccid3_hc_rx_sk(const struct sock *sk)
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index e48ca5d4565..a2afb553d8b 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -510,11 +510,9 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
- ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
- newinet->daddr);
+ ipv6_addr_set_v4mapped(newinet->daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -971,10 +969,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
sk->sk_backlog_rcv = dccp_v6_do_rcv;
goto failure;
} else {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
- inet->saddr);
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
- inet->rcv_saddr);
+ ipv6_addr_set_v4mapped(inet->saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr);
}
return err;
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 37731da4148..5e6ec8b9b7b 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -75,22 +75,20 @@ static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t size)
{
const struct inet_sock *inet = inet_sk(sk);
- struct ccid3_hc_tx_sock *hctx = NULL;
+ struct ccid3_hc_tx_sock *hc = NULL;
if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3)
- hctx = ccid3_hc_tx_sk(sk);
+ hc = ccid3_hc_tx_sk(sk);
if (port == 0 || ntohs(inet->dport) == port ||
ntohs(inet->sport) == port) {
- if (hctx)
- printl("%pI4:%u %pI4:%u %d %d %d %d %u "
- "%llu %llu %d\n",
+ if (hc)
+ printl("%pI4:%u %pI4:%u %d %d %d %d %u %llu %llu %d\n",
&inet->saddr, ntohs(inet->sport),
&inet->daddr, ntohs(inet->dport), size,
- hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
- hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc,
- hctx->ccid3hctx_x_recv >> 6,
- hctx->ccid3hctx_x >> 6, hctx->ccid3hctx_t_ipi);
+ hc->tx_s, hc->tx_rtt, hc->tx_p,
+ hc->tx_x_calc, hc->tx_x_recv >> 6,
+ hc->tx_x >> 6, hc->tx_t_ipi);
else
printl("%pI4:%u %pI4:%u %d\n",
&inet->saddr, ntohs(inet->sport),
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index a156319fd0a..ecb203fff50 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1060,11 +1060,12 @@ static int __init dccp_init(void)
for (ehash_order = 0; (1UL << ehash_order) < goal; ehash_order++)
;
do {
- dccp_hashinfo.ehash_size = (1UL << ehash_order) * PAGE_SIZE /
+ unsigned long hash_size = (1UL << ehash_order) * PAGE_SIZE /
sizeof(struct inet_ehash_bucket);
- while (dccp_hashinfo.ehash_size &
- (dccp_hashinfo.ehash_size - 1))
- dccp_hashinfo.ehash_size--;
+
+ while (hash_size & (hash_size - 1))
+ hash_size--;
+ dccp_hashinfo.ehash_mask = hash_size - 1;
dccp_hashinfo.ehash = (struct inet_ehash_bucket *)
__get_free_pages(GFP_ATOMIC|__GFP_NOWARN, ehash_order);
} while (!dccp_hashinfo.ehash && --ehash_order > 0);
@@ -1074,7 +1075,7 @@ static int __init dccp_init(void)
goto out_free_bind_bucket_cachep;
}
- for (i = 0; i < dccp_hashinfo.ehash_size; i++) {
+ for (i = 0; i <= dccp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i);
INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i);
}
@@ -1153,7 +1154,7 @@ static void __exit dccp_fini(void)
get_order(dccp_hashinfo.bhash_size *
sizeof(struct inet_bind_hashbucket)));
free_pages((unsigned long)dccp_hashinfo.ehash,
- get_order(dccp_hashinfo.ehash_size *
+ get_order((dccp_hashinfo.ehash_mask + 1) *
sizeof(struct inet_ehash_bucket)));
inet_ehash_locks_free(&dccp_hashinfo);
kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep);
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 7a58c87baf1..4d3060660a1 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -2325,7 +2325,7 @@ static const struct file_operations dn_socket_seq_fops = {
};
#endif
-static struct net_proto_family dn_family_ops = {
+static const struct net_proto_family dn_family_ops = {
.family = AF_DECnet,
.create = dn_create,
.owner = THIS_MODULE,
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 0e0254fd767..5e9426a11c3 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -457,15 +457,15 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
iov[0].iov_len = size;
for (i = 0; i < msg->msg_iovlen; i++) {
void __user *base = msg->msg_iov[i].iov_base;
- size_t len = msg->msg_iov[i].iov_len;
+ size_t iov_len = msg->msg_iov[i].iov_len;
/* Check it now since we switch to KERNEL_DS later. */
- if (!access_ok(VERIFY_READ, base, len)) {
+ if (!access_ok(VERIFY_READ, base, iov_len)) {
mutex_unlock(&econet_mutex);
return -EFAULT;
}
iov[i+1].iov_base = base;
- iov[i+1].iov_len = len;
- size += len;
+ iov[i+1].iov_len = iov_len;
+ size += iov_len;
}
/* Get a skbuff (no data, just holds our cb information) */
@@ -742,7 +742,7 @@ static int econet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
return 0;
}
-static struct net_proto_family econet_family_ops = {
+static const struct net_proto_family econet_family_ops = {
.family = PF_ECONET,
.create = econet_create,
.owner = THIS_MODULE,
diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c
index cd949d5e451..309348fba72 100644
--- a/net/ieee802154/af_ieee802154.c
+++ b/net/ieee802154/af_ieee802154.c
@@ -285,7 +285,7 @@ out:
return rc;
}
-static struct net_proto_family ieee802154_family_ops = {
+static const struct net_proto_family ieee802154_family_ops = {
.family = PF_IEEE802154,
.create = ieee802154_create,
.owner = THIS_MODULE,
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index a413b1bf446..25ad956a39d 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -303,7 +303,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index 30e74eee07d..769c8d138fc 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -191,7 +191,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (flags & MSG_TRUNC)
copied = skb->len;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 57737b8d171..1deff48b122 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -931,7 +931,7 @@ static const struct proto_ops inet_sockraw_ops = {
#endif
};
-static struct net_proto_family inet_family_ops = {
+static const struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner = THIS_MODULE,
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index 039cc1ffe97..1e029dc7545 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -2017,7 +2017,7 @@ req_setattr_failure:
* values on failure.
*
*/
-int cipso_v4_delopt(struct ip_options **opt_ptr)
+static int cipso_v4_delopt(struct ip_options **opt_ptr)
{
int hdr_delta = 0;
struct ip_options *opt = *opt_ptr;
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index e2f95059256..f73dbed0f0d 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -125,7 +125,7 @@ void fib_select_default(struct net *net,
#endif
tb = fib_get_table(net, table);
if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
- tb->tb_select_default(tb, flp, res);
+ fib_table_select_default(tb, flp, res);
}
static void fib_flush(struct net *net)
@@ -139,7 +139,7 @@ static void fib_flush(struct net *net)
for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
head = &net->ipv4.fib_table_hash[h];
hlist_for_each_entry(tb, node, head, tb_hlist)
- flushed += tb->tb_flush(tb);
+ flushed += fib_table_flush(tb);
}
if (flushed)
@@ -162,7 +162,7 @@ struct net_device * ip_dev_find(struct net *net, __be32 addr)
#endif
local_table = fib_get_table(net, RT_TABLE_LOCAL);
- if (!local_table || local_table->tb_lookup(local_table, &fl, &res))
+ if (!local_table || fib_table_lookup(local_table, &fl, &res))
return NULL;
if (res.type != RTN_LOCAL)
goto out;
@@ -200,7 +200,7 @@ static inline unsigned __inet_dev_addr_type(struct net *net,
local_table = fib_get_table(net, RT_TABLE_LOCAL);
if (local_table) {
ret = RTN_UNICAST;
- if (!local_table->tb_lookup(local_table, &fl, &res)) {
+ if (!fib_table_lookup(local_table, &fl, &res)) {
if (!dev || dev == res.fi->fib_dev)
ret = res.type;
fib_res_put(&res);
@@ -473,13 +473,13 @@ int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
if (cmd == SIOCDELRT) {
tb = fib_get_table(net, cfg.fc_table);
if (tb)
- err = tb->tb_delete(tb, &cfg);
+ err = fib_table_delete(tb, &cfg);
else
err = -ESRCH;
} else {
tb = fib_new_table(net, cfg.fc_table);
if (tb)
- err = tb->tb_insert(tb, &cfg);
+ err = fib_table_insert(tb, &cfg);
else
err = -ENOBUFS;
}
@@ -594,7 +594,7 @@ static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar
goto errout;
}
- err = tb->tb_delete(tb, &cfg);
+ err = fib_table_delete(tb, &cfg);
errout:
return err;
}
@@ -616,7 +616,7 @@ static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *ar
goto errout;
}
- err = tb->tb_insert(tb, &cfg);
+ err = fib_table_insert(tb, &cfg);
errout:
return err;
}
@@ -647,7 +647,7 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
if (dumped)
memset(&cb->args[2], 0, sizeof(cb->args) -
2 * sizeof(cb->args[0]));
- if (tb->tb_dump(tb, skb, cb) < 0)
+ if (fib_table_dump(tb, skb, cb) < 0)
goto out;
dumped = 1;
next:
@@ -701,9 +701,9 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
cfg.fc_scope = RT_SCOPE_HOST;
if (cmd == RTM_NEWROUTE)
- tb->tb_insert(tb, &cfg);
+ fib_table_insert(tb, &cfg);
else
- tb->tb_delete(tb, &cfg);
+ fib_table_delete(tb, &cfg);
}
void fib_add_ifaddr(struct in_ifaddr *ifa)
@@ -832,7 +832,7 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
local_bh_disable();
frn->tb_id = tb->tb_id;
- frn->err = tb->tb_lookup(tb, &fl, &res);
+ frn->err = fib_table_lookup(tb, &fl, &res);
if (!frn->err) {
frn->prefixlen = res.prefixlen;
@@ -1009,7 +1009,7 @@ static void __net_exit ip_fib_net_exit(struct net *net)
head = &net->ipv4.fib_table_hash[i];
hlist_for_each_entry_safe(tb, node, tmp, head, tb_hlist) {
hlist_del(node);
- tb->tb_flush(tb);
+ fib_table_flush(tb);
kfree(tb);
}
}
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index ecd39454235..14972017b9c 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -242,8 +242,8 @@ fn_new_zone(struct fn_hash *table, int z)
return fz;
}
-static int
-fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+int fib_table_lookup(struct fib_table *tb,
+ const struct flowi *flp, struct fib_result *res)
{
int err;
struct fn_zone *fz;
@@ -274,8 +274,8 @@ out:
return err;
}
-static void
-fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
+void fib_table_select_default(struct fib_table *tb,
+ const struct flowi *flp, struct fib_result *res)
{
int order, last_idx;
struct hlist_node *node;
@@ -366,7 +366,7 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
return NULL;
}
-static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
struct fib_node *new_f = NULL;
@@ -544,8 +544,7 @@ out:
return err;
}
-
-static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
{
struct fn_hash *table = (struct fn_hash *)tb->tb_data;
struct fib_node *f;
@@ -662,7 +661,7 @@ static int fn_flush_list(struct fn_zone *fz, int idx)
return found;
}
-static int fn_hash_flush(struct fib_table *tb)
+int fib_table_flush(struct fib_table *tb)
{
struct fn_hash *table = (struct fn_hash *) tb->tb_data;
struct fn_zone *fz;
@@ -743,7 +742,8 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
return skb->len;
}
-static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
+int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
+ struct netlink_callback *cb)
{
int m, s_m;
struct fn_zone *fz;
@@ -787,12 +787,7 @@ struct fib_table *fib_hash_table(u32 id)
tb->tb_id = id;
tb->tb_default = -1;
- tb->tb_lookup = fn_hash_lookup;
- tb->tb_insert = fn_hash_insert;
- tb->tb_delete = fn_hash_delete;
- tb->tb_flush = fn_hash_flush;
- tb->tb_select_default = fn_hash_select_default;
- tb->tb_dump = fn_hash_dump;
+
memset(tb->tb_data, 0, sizeof(struct fn_hash));
return tb;
}
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 92d9d97ec5e..835262c2b86 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -94,7 +94,7 @@ static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
if ((tbl = fib_get_table(rule->fr_net, rule->table)) == NULL)
goto errout;
- err = tbl->tb_lookup(tbl, flp, (struct fib_result *) arg->result);
+ err = fib_table_lookup(tbl, flp, (struct fib_result *) arg->result);
if (err > 0)
err = -EAGAIN;
errout:
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 291bdf50a21..af5d8979286 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1174,7 +1174,7 @@ done:
/*
* Caller must hold RTNL.
*/
-static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_insert(struct fib_table *tb, struct fib_config *cfg)
{
struct trie *t = (struct trie *) tb->tb_data;
struct fib_alias *fa, *new_fa;
@@ -1373,8 +1373,8 @@ static int check_leaf(struct trie *t, struct leaf *l,
return 1;
}
-static int fn_trie_lookup(struct fib_table *tb, const struct flowi *flp,
- struct fib_result *res)
+int fib_table_lookup(struct fib_table *tb, const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int ret;
@@ -1595,7 +1595,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l)
/*
* Caller must hold RTNL.
*/
-static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
+int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
{
struct trie *t = (struct trie *) tb->tb_data;
u32 key, mask;
@@ -1786,7 +1786,7 @@ static struct leaf *trie_leafindex(struct trie *t, int index)
/*
* Caller must hold RTNL.
*/
-static int fn_trie_flush(struct fib_table *tb)
+int fib_table_flush(struct fib_table *tb)
{
struct trie *t = (struct trie *) tb->tb_data;
struct leaf *l, *ll = NULL;
@@ -1807,9 +1807,9 @@ static int fn_trie_flush(struct fib_table *tb)
return found;
}
-static void fn_trie_select_default(struct fib_table *tb,
- const struct flowi *flp,
- struct fib_result *res)
+void fib_table_select_default(struct fib_table *tb,
+ const struct flowi *flp,
+ struct fib_result *res)
{
struct trie *t = (struct trie *) tb->tb_data;
int order, last_idx;
@@ -1952,8 +1952,8 @@ static int fn_trie_dump_leaf(struct leaf *l, struct fib_table *tb,
return skb->len;
}
-static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb,
- struct netlink_callback *cb)
+int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
+ struct netlink_callback *cb)
{
struct leaf *l;
struct trie *t = (struct trie *) tb->tb_data;
@@ -2020,12 +2020,6 @@ struct fib_table *fib_hash_table(u32 id)
tb->tb_id = id;
tb->tb_default = -1;
- tb->tb_lookup = fn_trie_lookup;
- tb->tb_insert = fn_trie_insert;
- tb->tb_delete = fn_trie_delete;
- tb->tb_flush = fn_trie_flush;
- tb->tb_select_default = fn_trie_select_default;
- tb->tb_dump = fn_trie_dump;
t = (struct trie *) tb->tb_data;
memset(t, 0, sizeof(*t));
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 5bc13fe816d..84adb5754c9 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1165,6 +1165,10 @@ static int __net_init icmp_sk_init(struct net *net)
sk->sk_sndbuf =
(2 * ((64 * 1024) + sizeof(struct sk_buff)));
+ /*
+ * Speedup sock_wfree()
+ */
+ sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 4351ca2cf0b..9139e8f6fdb 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -358,6 +358,7 @@ struct dst_entry *inet_csk_route_req(struct sock *sk,
const struct inet_request_sock *ireq = inet_rsk(req);
struct ip_options *opt = inet_rsk(req)->opt;
struct flowi fl = { .oif = sk->sk_bound_dev_if,
+ .mark = sk->sk_mark,
.nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index a706a47f4db..cb73fdefba9 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -774,7 +774,7 @@ skip_listen_ht:
if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
goto unlock;
- for (i = s_i; i < hashinfo->ehash_size; i++) {
+ for (i = s_i; i <= hashinfo->ehash_mask; i++) {
struct inet_ehash_bucket *head = &hashinfo->ehash[i];
spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
struct sock *sk;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 625cc5f64c9..a45aaf3d48b 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -209,7 +209,7 @@ struct sock * __inet_lookup_established(struct net *net,
* have wildcards anyways.
*/
unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport);
- unsigned int slot = hash & (hashinfo->ehash_size - 1);
+ unsigned int slot = hash & hashinfo->ehash_mask;
struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
rcu_read_lock();
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 13f0781f35c..2fe571155b2 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -430,7 +430,7 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo,
int h;
local_bh_disable();
- for (h = 0; h < (hashinfo->ehash_size); h++) {
+ for (h = 0; h <= hashinfo->ehash_mask; h++) {
struct inet_ehash_bucket *head =
inet_ehash_bucket(hashinfo, h);
spinlock_t *lock = inet_ehash_lockp(hashinfo, h);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 41ada9904d3..89ff9d5b150 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -662,7 +662,8 @@ drop_nolock:
static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *old_iph = ip_hdr(skb);
struct iphdr *tiph;
u8 tos;
@@ -810,7 +811,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 08ccd344de7..6a5539236ab 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -390,7 +390,8 @@ static int ipip_rcv(struct sk_buff *skb)
static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *tiph = &tunnel->parms.iph;
u8 tos = tunnel->parms.iph.tos;
__be16 df = tiph->frag_off;
@@ -478,7 +479,7 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 630a56df7b4..c757f0b4b74 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -469,8 +469,18 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
return err;
}
break;
+
+ case VIFF_USE_IFINDEX:
case 0:
- dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+ if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
+ dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
+ if (dev && dev->ip_ptr == NULL) {
+ dev_put(dev);
+ return -EADDRNOTAVAIL;
+ }
+ } else
+ dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+
if (!dev)
return -EADDRNOTAVAIL;
err = dev_set_allmulti(dev, 1);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 757c9171e7c..f18172b0761 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -682,7 +682,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
if (err)
goto done;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (sin) {
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index a6e0e077ac3..5ec678ad70e 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -333,7 +333,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
* no easy way to do this.
*/
{
- struct flowi fl = { .nl_u = { .ip4_u =
+ struct flowi fl = { .mark = sk->sk_mark,
+ .nl_u = { .ip4_u =
{ .daddr = ((opt && opt->srr) ?
opt->faddr :
ireq->rmt_addr),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 64d0af67582..cf13726259c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2865,11 +2865,10 @@ void __init tcp_init(void)
(totalram_pages >= 128 * 1024) ?
13 : 15,
0,
- &tcp_hashinfo.ehash_size,
NULL,
+ &tcp_hashinfo.ehash_mask,
thash_entries ? 0 : 512 * 1024);
- tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
- for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
+ for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i);
}
@@ -2878,7 +2877,7 @@ void __init tcp_init(void)
tcp_hashinfo.bhash =
alloc_large_system_hash("TCP bind",
sizeof(struct inet_bind_hashbucket),
- tcp_hashinfo.ehash_size,
+ tcp_hashinfo.ehash_mask + 1,
(totalram_pages >= 128 * 1024) ?
13 : 15,
0,
@@ -2933,8 +2932,8 @@ void __init tcp_init(void)
sysctl_tcp_rmem[2] = max(87380, max_share);
printk(KERN_INFO "TCP: Hash tables configured "
- "(established %d bind %d)\n",
- tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);
+ "(established %u bind %u)\n",
+ tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size);
tcp_register_congestion_control(&tcp_reno);
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7cda24b53f6..99718703d04 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2000,7 +2000,7 @@ static void *established_get_first(struct seq_file *seq)
struct net *net = seq_file_net(seq);
void *rc = NULL;
- for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
+ for (st->bucket = 0; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) {
struct sock *sk;
struct hlist_nulls_node *node;
struct inet_timewait_sock *tw;
@@ -2061,10 +2061,10 @@ get_tw:
st->state = TCP_SEQ_STATE_ESTABLISHED;
/* Look for next non empty bucket */
- while (++st->bucket < tcp_hashinfo.ehash_size &&
+ while (++st->bucket <= tcp_hashinfo.ehash_mask &&
empty_bucket(st))
;
- if (st->bucket >= tcp_hashinfo.ehash_size)
+ if (st->bucket > tcp_hashinfo.ehash_mask)
return NULL;
spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket));
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index d0d436d6216..ee61b3fc4ca 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -106,7 +106,7 @@
#include <net/xfrm.h>
#include "udp_impl.h"
-struct udp_table udp_table;
+struct udp_table udp_table __read_mostly;
EXPORT_SYMBOL(udp_table);
int sysctl_udp_mem[3] __read_mostly;
@@ -121,14 +121,16 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated);
-#define PORTS_PER_CHAIN (65536 / UDP_HTABLE_SIZE)
+#define MAX_UDP_PORTS 65536
+#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN)
static int udp_lib_lport_inuse(struct net *net, __u16 num,
const struct udp_hslot *hslot,
unsigned long *bitmap,
struct sock *sk,
int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2))
+ const struct sock *sk2),
+ unsigned int log)
{
struct sock *sk2;
struct hlist_nulls_node *node;
@@ -142,8 +144,7 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num,
|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
(*saddr_comp)(sk, sk2)) {
if (bitmap)
- __set_bit(sk2->sk_hash / UDP_HTABLE_SIZE,
- bitmap);
+ __set_bit(sk2->sk_hash >> log, bitmap);
else
return 1;
}
@@ -180,13 +181,15 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
/*
* force rand to be an odd multiple of UDP_HTABLE_SIZE
*/
- rand = (rand | 1) * UDP_HTABLE_SIZE;
- for (last = first + UDP_HTABLE_SIZE; first != last; first++) {
- hslot = &udptable->hash[udp_hashfn(net, first)];
+ rand = (rand | 1) * (udptable->mask + 1);
+ for (last = first + udptable->mask + 1;
+ first != last;
+ first++) {
+ hslot = udp_hashslot(udptable, net, first);
bitmap_zero(bitmap, PORTS_PER_CHAIN);
spin_lock_bh(&hslot->lock);
udp_lib_lport_inuse(net, snum, hslot, bitmap, sk,
- saddr_comp);
+ saddr_comp, udptable->log);
snum = first;
/*
@@ -196,7 +199,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
*/
do {
if (low <= snum && snum <= high &&
- !test_bit(snum / UDP_HTABLE_SIZE, bitmap))
+ !test_bit(snum >> udptable->log, bitmap))
goto found;
snum += rand;
} while (snum != first);
@@ -204,9 +207,10 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
}
goto fail;
} else {
- hslot = &udptable->hash[udp_hashfn(net, snum)];
+ hslot = udp_hashslot(udptable, net, snum);
spin_lock_bh(&hslot->lock);
- if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, saddr_comp))
+ if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk,
+ saddr_comp, 0))
goto fail_unlock;
}
found:
@@ -283,7 +287,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
struct sock *sk, *result;
struct hlist_nulls_node *node;
unsigned short hnum = ntohs(dport);
- unsigned int hash = udp_hashfn(net, hnum);
+ unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot = &udptable->hash[hash];
int score, badness;
@@ -982,7 +986,7 @@ try_again:
UDP_INC_STATS_USER(sock_net(sk),
UDP_MIB_INDATAGRAMS, is_udplite);
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (sin) {
@@ -1044,8 +1048,8 @@ void udp_lib_unhash(struct sock *sk)
{
if (sk_hashed(sk)) {
struct udp_table *udptable = sk->sk_prot->h.udp_table;
- unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash);
- struct udp_hslot *hslot = &udptable->hash[hash];
+ struct udp_hslot *hslot = udp_hashslot(udptable, sock_net(sk),
+ sk->sk_hash);
spin_lock_bh(&hslot->lock);
if (sk_nulls_del_node_init_rcu(sk)) {
@@ -1200,7 +1204,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
struct udp_table *udptable)
{
struct sock *sk;
- struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
+ struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
spin_lock(&hslot->lock);
@@ -1622,9 +1626,14 @@ static struct sock *udp_get_first(struct seq_file *seq, int start)
struct udp_iter_state *state = seq->private;
struct net *net = seq_file_net(seq);
- for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) {
+ for (state->bucket = start; state->bucket <= state->udp_table->mask;
+ ++state->bucket) {
struct hlist_nulls_node *node;
struct udp_hslot *hslot = &state->udp_table->hash[state->bucket];
+
+ if (hlist_nulls_empty(&hslot->head))
+ continue;
+
spin_lock_bh(&hslot->lock);
sk_nulls_for_each(sk, node, &hslot->head) {
if (!net_eq(sock_net(sk), net))
@@ -1649,7 +1658,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk)
} while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family));
if (!sk) {
- if (state->bucket < UDP_HTABLE_SIZE)
+ if (state->bucket <= state->udp_table->mask)
spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
return udp_get_first(seq, state->bucket + 1);
}
@@ -1669,7 +1678,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos)
static void *udp_seq_start(struct seq_file *seq, loff_t *pos)
{
struct udp_iter_state *state = seq->private;
- state->bucket = UDP_HTABLE_SIZE;
+ state->bucket = MAX_UDP_PORTS;
return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN;
}
@@ -1691,7 +1700,7 @@ static void udp_seq_stop(struct seq_file *seq, void *v)
{
struct udp_iter_state *state = seq->private;
- if (state->bucket < UDP_HTABLE_SIZE)
+ if (state->bucket <= state->udp_table->mask)
spin_unlock_bh(&state->udp_table->hash[state->bucket].lock);
}
@@ -1751,7 +1760,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
__u16 destp = ntohs(inet->dport);
__u16 srcp = ntohs(inet->sport);
- seq_printf(f, "%4d: %08X:%04X %08X:%04X"
+ seq_printf(f, "%5d: %08X:%04X %08X:%04X"
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n",
bucket, src, srcp, dest, destp, sp->sk_state,
sk_wmem_alloc_get(sp),
@@ -1817,11 +1826,43 @@ void udp4_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
-void __init udp_table_init(struct udp_table *table)
+static __initdata unsigned long uhash_entries;
+static int __init set_uhash_entries(char *str)
{
- int i;
+ if (!str)
+ return 0;
+ uhash_entries = simple_strtoul(str, &str, 0);
+ if (uhash_entries && uhash_entries < UDP_HTABLE_SIZE_MIN)
+ uhash_entries = UDP_HTABLE_SIZE_MIN;
+ return 1;
+}
+__setup("uhash_entries=", set_uhash_entries);
- for (i = 0; i < UDP_HTABLE_SIZE; i++) {
+void __init udp_table_init(struct udp_table *table, const char *name)
+{
+ unsigned int i;
+
+ if (!CONFIG_BASE_SMALL)
+ table->hash = alloc_large_system_hash(name,
+ sizeof(struct udp_hslot),
+ uhash_entries,
+ 21, /* one slot per 2 MB */
+ 0,
+ &table->log,
+ &table->mask,
+ 64 * 1024);
+ /*
+ * Make sure hash table has the minimum size
+ */
+ if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
+ table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
+ sizeof(struct udp_hslot), GFP_KERNEL);
+ if (!table->hash)
+ panic(name);
+ table->log = ilog2(UDP_HTABLE_SIZE_MIN);
+ table->mask = UDP_HTABLE_SIZE_MIN - 1;
+ }
+ for (i = 0; i <= table->mask; i++) {
INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
spin_lock_init(&table->hash[i].lock);
}
@@ -1831,7 +1872,7 @@ void __init udp_init(void)
{
unsigned long nr_pages, limit;
- udp_table_init(&udp_table);
+ udp_table_init(&udp_table, "UDP");
/* Set the pressure threshold up by the same strategy of TCP. It is a
* fraction of global memory that is up to 1/2 at 256 MB, decreasing
* toward zero with the amount of memory, with a floor of 128 pages.
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index 95248d7f75e..470c504b955 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -12,7 +12,7 @@
*/
#include "udp_impl.h"
-struct udp_table udplite_table;
+struct udp_table udplite_table __read_mostly;
EXPORT_SYMBOL(udplite_table);
static int udplite_rcv(struct sk_buff *skb)
@@ -110,7 +110,7 @@ static inline int udplite4_proc_init(void)
void __init udplite4_register(void)
{
- udp_table_init(&udplite_table);
+ udp_table_init(&udplite_table, "UDP-Lite");
if (proto_register(&udplite_prot, 1))
goto out_register_err;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index ead6c7a42f4..a578096152a 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -170,6 +170,25 @@ config IPV6_SIT
Saying M here will produce a module called sit. If unsure, say Y.
+config IPV6_SIT_6RD
+ bool "IPv6: IPv6 Rapid Deployment (6RD) (EXPERIMENTAL)"
+ depends on IPV6_SIT && EXPERIMENTAL
+ default n
+ ---help---
+ IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon
+ mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly
+ deploy IPv6 unicast service to IPv4 sites to which it provides
+ customer premise equipment. Like 6to4, it utilizes stateless IPv6 in
+ IPv4 encapsulation in order to transit IPv4-only network
+ infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6
+ prefix of its own in place of the fixed 6to4 prefix.
+
+ With this option enabled, the SIT driver offers 6rd functionality by
+ providing additional ioctl API to configure the IPv6 Prefix for in
+ stead of static 2002::/16 for 6to4.
+
+ If unsure, say N.
+
config IPV6_NDISC_NODETYPE
bool
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1fd0a3d775d..91864840961 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3708,6 +3708,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
#endif
array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6;
array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad;
+ array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao;
}
static inline size_t inet6_if_nlmsg_size(void)
@@ -4353,6 +4354,14 @@ static struct addrconf_sysctl_table
.proc_handler = proc_dointvec,
},
{
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "force_tllao",
+ .data = &ipv6_devconf.force_tllao,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.ctl_name = 0, /* sentinel */
}
},
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e127a32f954..94216519873 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -552,7 +552,7 @@ const struct proto_ops inet6_dgram_ops = {
#endif
};
-static struct net_proto_family inet6_family_ops = {
+static const struct net_proto_family inet6_family_ops = {
.family = PF_INET6,
.create = inet6_create,
.owner = THIS_MODULE,
@@ -654,6 +654,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.fl6_flowlabel = np->flow_label;
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_sk_classify_flow(sk, &fl);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e2bdc6d83a4..dbfec7147aa 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -98,17 +98,14 @@ ipv4_connected:
if (err)
goto out;
- ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
+ ipv6_addr_set_v4mapped(inet->daddr, &np->daddr);
- if (ipv6_addr_any(&np->saddr)) {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000ffff),
- inet->saddr);
- }
+ if (ipv6_addr_any(&np->saddr))
+ ipv6_addr_set_v4mapped(inet->saddr, &np->saddr);
+
+ if (ipv6_addr_any(&np->rcv_saddr))
+ ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr);
- if (ipv6_addr_any(&np->rcv_saddr)) {
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000ffff),
- inet->rcv_saddr);
- }
goto out;
}
@@ -147,6 +144,7 @@ ipv4_connected:
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
@@ -329,9 +327,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
sin->sin6_scope_id = IP6CB(skb)->iif;
} else {
- ipv6_addr_set(&sin->sin6_addr, 0, 0,
- htonl(0xffff),
- *(__be32 *)(nh + serr->addr_offset));
+ ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset),
+ &sin->sin6_addr);
}
}
@@ -351,8 +348,8 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
} else {
struct inet_sock *inet = inet_sk(sk);
- ipv6_addr_set(&sin->sin6_addr, 0, 0,
- htonl(0xffff), ip_hdr(skb)->saddr);
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
+ &sin->sin6_addr);
if (inet->cmsg_flags)
ip_cmsg_recv(msg, skb);
}
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index cc4797dd832..a9f4a21b31e 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -194,6 +194,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok)
fl.fl6_flowlabel = np->flow_label;
IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_sport = inet->sport;
fl.fl_ip_dport = inet->dport;
security_sk_classify_flow(sk, &fl);
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 1bcc3431859..874aed86e1a 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -73,7 +73,7 @@ struct sock *__inet6_lookup_established(struct net *net,
* have wildcards anyways.
*/
unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport);
- unsigned int slot = hash & (hashinfo->ehash_size - 1);
+ unsigned int slot = hash & hashinfo->ehash_mask;
struct inet_ehash_bucket *head = &hashinfo->ehash[slot];
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 14f54eb5a7f..dc0f7366073 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -424,6 +424,7 @@ sticky_done:
fl.fl6_flowlabel = 0;
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
if (optlen == 0)
goto update;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index f74e4e2cdd0..3507cfe1e7a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -598,6 +598,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
icmp6h.icmp6_solicited = solicited;
icmp6h.icmp6_override = override;
+ inc_opt |= ifp->idev->cnf.force_tllao;
__ndisc_send(dev, neigh, daddr, src_addr,
&icmp6h, solicited_addr,
inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4f24570b086..d8375bc7f2d 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -497,7 +497,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
sin6->sin6_scope_id = IP6CB(skb)->iif;
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (np->rxopt.all)
datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d6fe7646a8f..df9432a46ff 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1471,9 +1471,10 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
},
},
},
- .gateway = *gateway,
};
+ ipv6_addr_copy(&rdfl.gateway, gateway);
+
if (rt6_need_strict(dest))
flags |= RT6_LOOKUP_F_IFACE;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index dbd19a78ca7..510d31f3cb9 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -161,6 +161,23 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
write_unlock_bh(&ipip6_lock);
}
+static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
+{
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel *t = netdev_priv(dev);
+
+ if (t->dev == sitn->fb_tunnel_dev) {
+ ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
+ t->ip6rd.relay_prefix = 0;
+ t->ip6rd.prefixlen = 16;
+ t->ip6rd.relay_prefixlen = 0;
+ } else {
+ struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev);
+ memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd));
+ }
+#endif
+}
+
static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
struct ip_tunnel_parm *parms, int create)
{
@@ -204,6 +221,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
nt->parms = *parms;
ipip6_tunnel_init(dev);
+ ipip6_tunnel_clone_6rd(dev, sitn);
if (parms->i_flags & SIT_ISATAP)
dev->priv_flags |= IFF_ISATAP;
@@ -532,17 +550,41 @@ out:
return 0;
}
-/* Returns the embedded IPv4 address if the IPv6 address
- comes from 6to4 (RFC 3056) addr space */
-
-static inline __be32 try_6to4(struct in6_addr *v6dst)
+/*
+ * Returns the embedded IPv4 address if the IPv6 address
+ * comes from 6rd / 6to4 (RFC 3056) addr space.
+ */
+static inline
+__be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel)
{
__be32 dst = 0;
+#ifdef CONFIG_IPV6_SIT_6RD
+ if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix,
+ tunnel->ip6rd.prefixlen)) {
+ unsigned pbw0, pbi0;
+ int pbi1;
+ u32 d;
+
+ pbw0 = tunnel->ip6rd.prefixlen >> 5;
+ pbi0 = tunnel->ip6rd.prefixlen & 0x1f;
+
+ d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >>
+ tunnel->ip6rd.relay_prefixlen;
+
+ pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen;
+ if (pbi1 > 0)
+ d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >>
+ (32 - pbi1);
+
+ dst = tunnel->ip6rd.relay_prefix | htonl(d);
+ }
+#else
if (v6dst->s6_addr16[0] == htons(0x2002)) {
/* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */
memcpy(&dst, &v6dst->s6_addr16[1], 4);
}
+#endif
return dst;
}
@@ -555,7 +597,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct ip_tunnel *tunnel = netdev_priv(dev);
- struct net_device_stats *stats = &tunnel->dev->stats;
+ struct net_device_stats *stats = &dev->stats;
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
struct iphdr *tiph = &tunnel->parms.iph;
struct ipv6hdr *iph6 = ipv6_hdr(skb);
u8 tos = tunnel->parms.iph.tos;
@@ -595,7 +638,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
}
if (!dst)
- dst = try_6to4(&iph6->daddr);
+ dst = try_6rd(&iph6->daddr, tunnel);
if (!dst) {
struct neighbour *neigh = NULL;
@@ -688,7 +731,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
- stats->tx_dropped++;
+ txq->tx_dropped++;
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -785,9 +828,15 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
struct ip_tunnel *t;
struct net *net = dev_net(dev);
struct sit_net *sitn = net_generic(net, sit_net_id);
+#ifdef CONFIG_IPV6_SIT_6RD
+ struct ip_tunnel_6rd ip6rd;
+#endif
switch (cmd) {
case SIOCGETTUNNEL:
+#ifdef CONFIG_IPV6_SIT_6RD
+ case SIOCGET6RD:
+#endif
t = NULL;
if (dev == sitn->fb_tunnel_dev) {
if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
@@ -798,9 +847,25 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
}
if (t == NULL)
t = netdev_priv(dev);
- memcpy(&p, &t->parms, sizeof(p));
- if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
- err = -EFAULT;
+
+ err = -EFAULT;
+ if (cmd == SIOCGETTUNNEL) {
+ memcpy(&p, &t->parms, sizeof(p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p,
+ sizeof(p)))
+ goto done;
+#ifdef CONFIG_IPV6_SIT_6RD
+ } else {
+ ipv6_addr_copy(&ip6rd.prefix, &t->ip6rd.prefix);
+ ip6rd.relay_prefix = t->ip6rd.relay_prefix;
+ ip6rd.prefixlen = t->ip6rd.prefixlen;
+ ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen;
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd,
+ sizeof(ip6rd)))
+ goto done;
+#endif
+ }
+ err = 0;
break;
case SIOCADDTUNNEL:
@@ -921,6 +986,54 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd)
netdev_state_change(dev);
break;
+#ifdef CONFIG_IPV6_SIT_6RD
+ case SIOCADD6RD:
+ case SIOCCHG6RD:
+ case SIOCDEL6RD:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ goto done;
+
+ err = -EFAULT;
+ if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data,
+ sizeof(ip6rd)))
+ goto done;
+
+ t = netdev_priv(dev);
+
+ if (cmd != SIOCDEL6RD) {
+ struct in6_addr prefix;
+ __be32 relay_prefix;
+
+ err = -EINVAL;
+ if (ip6rd.relay_prefixlen > 32 ||
+ ip6rd.prefixlen + (32 - ip6rd.relay_prefixlen) > 64)
+ goto done;
+
+ ipv6_addr_prefix(&prefix, &ip6rd.prefix,
+ ip6rd.prefixlen);
+ if (!ipv6_addr_equal(&prefix, &ip6rd.prefix))
+ goto done;
+ if (ip6rd.relay_prefixlen)
+ relay_prefix = ip6rd.relay_prefix &
+ htonl(0xffffffffUL <<
+ (32 - ip6rd.relay_prefixlen));
+ else
+ relay_prefix = 0;
+ if (relay_prefix != ip6rd.relay_prefix)
+ goto done;
+
+ ipv6_addr_copy(&t->ip6rd.prefix, &prefix);
+ t->ip6rd.relay_prefix = relay_prefix;
+ t->ip6rd.prefixlen = ip6rd.prefixlen;
+ t->ip6rd.relay_prefixlen = ip6rd.relay_prefixlen;
+ } else
+ ipip6_tunnel_clone_6rd(dev, sitn);
+
+ err = 0;
+ break;
+#endif
+
default:
err = -EINVAL;
}
@@ -1039,6 +1152,7 @@ static int sit_init_net(struct net *net)
dev_net_set(sitn->fb_tunnel_dev, net);
ipip6_fb_tunnel_init(sitn->fb_tunnel_dev);
+ ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn);
if ((err = register_netdev(sitn->fb_tunnel_dev)))
goto err_reg_dev;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 6b6ae913b5d..cbe55e5d9f9 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -252,6 +252,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
}
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_sk(sk)->sport;
security_req_classify_flow(req, &fl);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 21d100b68b1..45176305914 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -226,10 +226,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
#endif
goto failure;
} else {
- ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF),
- inet->saddr);
- ipv6_addr_set(&np->rcv_saddr, 0, 0, htonl(0x0000FFFF),
- inet->rcv_saddr);
+ ipv6_addr_set_v4mapped(inet->saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr);
}
return err;
@@ -243,6 +241,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
ipv6_addr_copy(&fl.fl6_src,
(saddr ? saddr : &np->saddr));
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->sport;
@@ -383,6 +382,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_skb_classify_flow(skb, &fl);
@@ -477,6 +477,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req)
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.fl6_flowlabel = 0;
fl.oif = treq->iif;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_rsk(req)->loc_port;
security_req_classify_flow(req, &fl);
@@ -1290,11 +1291,9 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
- ipv6_addr_set(&newnp->daddr, 0, 0, htonl(0x0000FFFF),
- newinet->daddr);
+ ipv6_addr_set_v4mapped(newinet->daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -1345,6 +1344,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
}
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.oif = sk->sk_bound_dev_if;
+ fl.mark = sk->sk_mark;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
fl.fl_ip_sport = inet_rsk(req)->loc_port;
security_req_classify_flow(req, &fl);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3a60f12b34e..1f8e2afa449 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -132,7 +132,7 @@ static struct sock *__udp6_lib_lookup(struct net *net,
struct sock *sk, *result;
struct hlist_nulls_node *node;
unsigned short hnum = ntohs(dport);
- unsigned int hash = udp_hashfn(net, hnum);
+ unsigned int hash = udp_hashfn(net, hnum, udptable->mask);
struct udp_hslot *hslot = &udptable->hash[hash];
int score, badness;
@@ -252,7 +252,7 @@ try_again:
UDP_MIB_INDATAGRAMS, is_udplite);
}
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
/* Copy the address. */
if (msg->msg_name) {
@@ -265,8 +265,8 @@ try_again:
sin6->sin6_scope_id = 0;
if (is_udp4)
- ipv6_addr_set(&sin6->sin6_addr, 0, 0,
- htonl(0xffff), ip_hdr(skb)->saddr);
+ ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
+ &sin6->sin6_addr);
else {
ipv6_addr_copy(&sin6->sin6_addr,
&ipv6_hdr(skb)->saddr);
@@ -452,7 +452,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
{
struct sock *sk, *sk2;
const struct udphdr *uh = udp_hdr(skb);
- struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))];
+ struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest));
int dif;
spin_lock(&hslot->lock);
@@ -879,6 +879,8 @@ do_udp_sendmsg:
if (!fl.oif)
fl.oif = np->sticky_pktinfo.ipi6_ifindex;
+ fl.mark = sk->sk_mark;
+
if (msg->msg_controllen) {
opt = &opt_space;
memset(opt, 0, sizeof(struct ipv6_txoptions));
@@ -1195,7 +1197,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
destp = ntohs(inet->dport);
srcp = ntohs(inet->sport);
seq_printf(seq,
- "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+ "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
bucket,
src->s6_addr32[0], src->s6_addr32[1],
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 66c7a20011f..6481ee4bdf7 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1927,7 +1927,7 @@ static int ipx_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long
* Socket family declarations
*/
-static struct net_proto_family ipx_family_ops = {
+static const struct net_proto_family ipx_family_ops = {
.family = PF_IPX,
.create = ipx_create,
.owner = THIS_MODULE,
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index dd35641835f..9429e4002bc 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2463,7 +2463,7 @@ bed:
return 0;
}
-static struct net_proto_family irda_family_ops = {
+static const struct net_proto_family irda_family_ops = {
.family = PF_IRDA,
.create = irda_create,
.owner = THIS_MODULE,
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index bada1b9c670..004134b60d8 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1715,7 +1715,7 @@ static const struct proto_ops iucv_sock_ops = {
.getsockopt = iucv_sock_getsockopt,
};
-static struct net_proto_family iucv_sock_family_ops = {
+static const struct net_proto_family iucv_sock_family_ops = {
.family = AF_IUCV,
.owner = THIS_MODULE,
.create = iucv_sock_create,
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 4e98193dfa0..472f6594184 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3606,7 +3606,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
err = (flags & MSG_TRUNC) ? skb->len : copied;
@@ -3644,7 +3644,7 @@ static const struct proto_ops pfkey_ops = {
.recvmsg = pfkey_recvmsg,
};
-static struct net_proto_family pfkey_family_ops = {
+static const struct net_proto_family pfkey_family_ops = {
.family = PF_KEY,
.create = pfkey_create,
.owner = THIS_MODULE,
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7aa4fd17010..4866b4fb0c2 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -1092,7 +1092,7 @@ out:
return rc;
}
-static struct net_proto_family llc_ui_family_ops = {
+static const struct net_proto_family llc_ui_family_ops = {
.family = PF_LLC,
.create = llc_ui_create,
.owner = THIS_MODULE,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b8295cbd7e8..87aff1d923b 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -184,10 +184,12 @@ static int ieee80211_open(struct net_device *dev)
* No need to check netif_running since we do not allow
* it to start up with this invalid address.
*/
- if (compare_ether_addr(null_addr, ndev->dev_addr) == 0)
+ if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) {
memcpy(ndev->dev_addr,
local->hw.wiphy->perm_addr,
ETH_ALEN);
+ memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
+ }
}
/*
@@ -754,10 +756,6 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
return 0;
}
-static struct device_type wiphy_type = {
- .name = "wlan",
-};
-
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device **new_dev, enum nl80211_iftype type,
struct vif_params *params)
@@ -788,8 +786,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
goto fail;
memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ memcpy(ndev->perm_addr, ndev->dev_addr, ETH_ALEN);
SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
- SET_NETDEV_DEVTYPE(ndev, &wiphy_type);
/* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
sdata = netdev_priv(ndev);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 19e98007691..0cd2d882931 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -2050,7 +2050,7 @@ static const struct proto_ops netlink_ops = {
.sendpage = sock_no_sendpage,
};
-static struct net_proto_family netlink_family_ops = {
+static const struct net_proto_family netlink_family_ops = {
.family = PF_NETLINK,
.create = netlink_create,
.owner = THIS_MODULE, /* for consistency 8) */
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 7a834952f67..281fa597cae 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1372,7 +1372,7 @@ static const struct file_operations nr_info_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct net_proto_family nr_family_ops = {
+static const struct net_proto_family nr_family_ops = {
.family = PF_NETROM,
.create = nr_create,
.owner = THIS_MODULE,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1238949e66a..bf3a2954cd4 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -490,6 +490,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock,
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
if (err)
goto out_free;
@@ -626,15 +627,14 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
spin_lock(&sk->sk_receive_queue.lock);
po->stats.tp_packets++;
+ skb->dropcount = atomic_read(&sk->sk_drops);
__skb_queue_tail(&sk->sk_receive_queue, skb);
spin_unlock(&sk->sk_receive_queue.lock);
sk->sk_data_ready(sk, skb->len);
return 0;
drop_n_acct:
- spin_lock(&sk->sk_receive_queue.lock);
- po->stats.tp_drops++;
- spin_unlock(&sk->sk_receive_queue.lock);
+ po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
drop_n_restore:
if (skb_head != skb->data && skb_shared(skb)) {
@@ -856,6 +856,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->protocol = proto;
skb->dev = dev;
skb->priority = po->sk.sk_priority;
+ skb->mark = po->sk.sk_mark;
skb_shinfo(skb)->destructor_arg = ph.raw;
switch (po->tp_version) {
@@ -1125,6 +1126,7 @@ static int packet_snd(struct socket *sock,
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->sk_priority;
+ skb->mark = sk->sk_mark;
/*
* Now send it
@@ -1475,7 +1477,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (msg->msg_name)
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
@@ -2084,7 +2086,7 @@ static void packet_mm_close(struct vm_area_struct *vma)
atomic_dec(&pkt_sk(sk)->mapped);
}
-static struct vm_operations_struct packet_mmap_ops = {
+static const struct vm_operations_struct packet_mmap_ops = {
.open = packet_mm_open,
.close = packet_mm_close,
};
@@ -2363,7 +2365,7 @@ static const struct proto_ops packet_ops = {
.sendpage = sock_no_sendpage,
};
-static struct net_proto_family packet_family_ops = {
+static const struct net_proto_family packet_family_ops = {
.family = PF_PACKET,
.create = packet_create,
.owner = THIS_MODULE,
diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c
index f60c0c2aacb..c711d58b4bb 100644
--- a/net/phonet/af_phonet.c
+++ b/net/phonet/af_phonet.c
@@ -118,7 +118,7 @@ out:
return err;
}
-static struct net_proto_family phonet_proto_family = {
+static const struct net_proto_family phonet_proto_family = {
.family = PF_PHONET,
.create = pn_socket_create,
.owner = THIS_MODULE,
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
index 98e05382fd3..a202e5b3607 100644
--- a/net/rds/af_rds.c
+++ b/net/rds/af_rds.c
@@ -431,7 +431,7 @@ void rds_sock_put(struct rds_sock *rs)
sock_put(rds_rs_to_sk(rs));
}
-static struct net_proto_family rds_family_ops = {
+static const struct net_proto_family rds_family_ops = {
.family = AF_RDS,
.create = rds_create,
.owner = THIS_MODULE,
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index dbeaf298382..ba2efb960c6 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -27,6 +27,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/rfkill.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index 502cce76621..c17734c2ce8 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1509,7 +1509,7 @@ static const struct file_operations rose_info_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct net_proto_family rose_family_ops = {
+static const struct net_proto_family rose_family_ops = {
.family = PF_ROSE,
.create = rose_create,
.owner = THIS_MODULE,
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index a86afceaa94..6817c9781ef 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -777,7 +777,7 @@ static struct proto rxrpc_proto = {
.max_header = sizeof(struct rxrpc_header),
};
-static struct net_proto_family rxrpc_family_ops = {
+static const struct net_proto_family rxrpc_family_ops = {
.family = PF_RXRPC,
.create = rxrpc_create,
.owner = THIS_MODULE,
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
index a39bf97f883..60c2b94e6b5 100644
--- a/net/rxrpc/ar-recvmsg.c
+++ b/net/rxrpc/ar-recvmsg.c
@@ -146,7 +146,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
memcpy(msg->msg_name,
&call->conn->trans->peer->srx,
sizeof(call->conn->trans->peer->srx));
- sock_recv_timestamp(msg, &rx->sk, skb);
+ sock_recv_ts_and_drops(msg, &rx->sk, skb);
}
/* receive the message */
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 2dfb3e7a040..ca2e1fd2bf6 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -618,7 +618,8 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
goto errout;
if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
+ gnet_stats_copy_rate_est(&d, &h->tcf_bstats,
+ &h->tcf_rate_est) < 0 ||
gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
goto errout;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 903e4188b6c..1acfd29cc82 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1179,7 +1179,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
goto nla_put_failure;
if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
- gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(&d, &q->bstats, &q->rate_est) < 0 ||
gnet_stats_copy_queue(&d, &q->qstats) < 0)
goto nla_put_failure;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 5b132c47326..3846d65bc03 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1609,7 +1609,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
cl->xstats.undertime = cl->undertime - q->now;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 5a888af7e5d..a65604f8f2b 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -280,7 +280,7 @@ static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg,
}
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0)
return -1;
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 2c5c76be18f..b38b39c6075 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1375,7 +1375,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
xstats.rtwork = cl->cl_cumul;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, &cl->bstats, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 85acab9dc6f..2e38d1abd83 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1105,7 +1105,7 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
cl->xstats.ctokens = cl->ctokens;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
- gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
+ gnet_stats_copy_rate_est(d, NULL, &cl->rate_est) < 0 ||
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c8d05758661..0970e92c6ac 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1958,7 +1958,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
if (err)
goto out_free;
- sock_recv_timestamp(msg, sk, skb);
+ sock_recv_ts_and_drops(msg, sk, skb);
if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
diff --git a/net/socket.c b/net/socket.c
index 75655365b5f..9dff31c9b79 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -668,10 +668,24 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
-static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t size, int flags)
+inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
+{
+ if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
+ put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
+ sizeof(__u32), &skb->dropcount);
+}
+
+void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+ struct sk_buff *skb)
+{
+ sock_recv_timestamp(msg, sk, skb);
+ sock_recv_drops(msg, sk, skb);
+}
+EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
+
+static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
{
- int err;
struct sock_iocb *si = kiocb_to_siocb(iocb);
si->sock = sock;
@@ -680,13 +694,17 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
si->size = size;
si->flags = flags;
- err = security_socket_recvmsg(sock, msg, size, flags);
- if (err)
- return err;
-
return sock->ops->recvmsg(iocb, sock, msg, size, flags);
}
+static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size, int flags)
+{
+ int err = security_socket_recvmsg(sock, msg, size, flags);
+
+ return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags);
+}
+
int sock_recvmsg(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
{
@@ -702,6 +720,21 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
return ret;
}
+static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
+ size_t size, int flags)
+{
+ struct kiocb iocb;
+ struct sock_iocb siocb;
+ int ret;
+
+ init_sync_kiocb(&iocb, NULL);
+ iocb.private = &siocb;
+ ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags);
+ if (-EIOCBQUEUED == ret)
+ ret = wait_on_sync_kiocb(&iocb);
+ return ret;
+}
+
int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size, int flags)
{
@@ -905,11 +938,11 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
err = dev_ioctl(net, cmd, argp);
} else
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_WEXT_CORE
if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
err = dev_ioctl(net, cmd, argp);
} else
-#endif /* CONFIG_WIRELESS_EXT */
+#endif
switch (cmd) {
case FIOSETOWN:
case SIOCSPGRP:
@@ -1100,11 +1133,14 @@ static int sock_fasync(int fd, struct file *filp, int on)
fna->fa_next = sock->fasync_list;
write_lock_bh(&sk->sk_callback_lock);
sock->fasync_list = fna;
+ sock_set_flag(sk, SOCK_FASYNC);
write_unlock_bh(&sk->sk_callback_lock);
} else {
if (fa != NULL) {
write_lock_bh(&sk->sk_callback_lock);
*prev = fa->fa_next;
+ if (!sock->fasync_list)
+ sock_reset_flag(sk, SOCK_FASYNC);
write_unlock_bh(&sk->sk_callback_lock);
kfree(fa);
}
@@ -1965,22 +2001,15 @@ out:
return err;
}
-/*
- * BSD recvmsg interface
- */
-
-SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
- unsigned int, flags)
+static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
+ struct msghdr *msg_sys, unsigned flags, int nosec)
{
struct compat_msghdr __user *msg_compat =
(struct compat_msghdr __user *)msg;
- struct socket *sock;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov = iovstack;
- struct msghdr msg_sys;
unsigned long cmsg_ptr;
int err, iov_size, total_len, len;
- int fput_needed;
/* kernel mode address */
struct sockaddr_storage addr;
@@ -1990,27 +2019,23 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
int __user *uaddr_len;
if (MSG_CMSG_COMPAT & flags) {
- if (get_compat_msghdr(&msg_sys, msg_compat))
+ if (get_compat_msghdr(msg_sys, msg_compat))
return -EFAULT;
}
- else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
- sock = sockfd_lookup_light(fd, &err, &fput_needed);
- if (!sock)
- goto out;
-
err = -EMSGSIZE;
- if (msg_sys.msg_iovlen > UIO_MAXIOV)
- goto out_put;
+ if (msg_sys->msg_iovlen > UIO_MAXIOV)
+ goto out;
/* Check whether to allocate the iovec area */
err = -ENOMEM;
- iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
- if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+ iov_size = msg_sys->msg_iovlen * sizeof(struct iovec);
+ if (msg_sys->msg_iovlen > UIO_FASTIOV) {
iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
if (!iov)
- goto out_put;
+ goto out;
}
/*
@@ -2018,46 +2043,47 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
* kernel msghdr to use the kernel address space)
*/
- uaddr = (__force void __user *)msg_sys.msg_name;
+ uaddr = (__force void __user *)msg_sys->msg_name;
uaddr_len = COMPAT_NAMELEN(msg);
if (MSG_CMSG_COMPAT & flags) {
- err = verify_compat_iovec(&msg_sys, iov,
+ err = verify_compat_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
} else
- err = verify_iovec(&msg_sys, iov,
+ err = verify_iovec(msg_sys, iov,
(struct sockaddr *)&addr,
VERIFY_WRITE);
if (err < 0)
goto out_freeiov;
total_len = err;
- cmsg_ptr = (unsigned long)msg_sys.msg_control;
- msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
+ cmsg_ptr = (unsigned long)msg_sys->msg_control;
+ msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
- err = sock_recvmsg(sock, &msg_sys, total_len, flags);
+ err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
+ total_len, flags);
if (err < 0)
goto out_freeiov;
len = err;
if (uaddr != NULL) {
err = move_addr_to_user((struct sockaddr *)&addr,
- msg_sys.msg_namelen, uaddr,
+ msg_sys->msg_namelen, uaddr,
uaddr_len);
if (err < 0)
goto out_freeiov;
}
- err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT),
+ err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT),
COMPAT_FLAGS(msg));
if (err)
goto out_freeiov;
if (MSG_CMSG_COMPAT & flags)
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg_compat->msg_controllen);
else
- err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr,
+ err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
&msg->msg_controllen);
if (err)
goto out_freeiov;
@@ -2066,21 +2092,150 @@ SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
out_freeiov:
if (iov != iovstack)
sock_kfree_s(sock->sk, iov, iov_size);
-out_put:
+out:
+ return err;
+}
+
+/*
+ * BSD recvmsg interface
+ */
+
+SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
+ unsigned int, flags)
+{
+ int fput_needed, err;
+ struct msghdr msg_sys;
+ struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed);
+
+ if (!sock)
+ goto out;
+
+ err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0);
+
fput_light(sock->file, fput_needed);
out:
return err;
}
-#ifdef __ARCH_WANT_SYS_SOCKETCALL
+/*
+ * Linux recvmmsg interface
+ */
+
+int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
+ unsigned int flags, struct timespec *timeout)
+{
+ int fput_needed, err, datagrams;
+ struct socket *sock;
+ struct mmsghdr __user *entry;
+ struct msghdr msg_sys;
+ struct timespec end_time;
+
+ if (timeout &&
+ poll_select_set_timeout(&end_time, timeout->tv_sec,
+ timeout->tv_nsec))
+ return -EINVAL;
+
+ datagrams = 0;
+
+ sock = sockfd_lookup_light(fd, &err, &fput_needed);
+ if (!sock)
+ return err;
+
+ err = sock_error(sock->sk);
+ if (err)
+ goto out_put;
+
+ entry = mmsg;
+
+ while (datagrams < vlen) {
+ /*
+ * No need to ask LSM for more than the first datagram.
+ */
+ err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
+ &msg_sys, flags, datagrams);
+ if (err < 0)
+ break;
+ err = put_user(err, &entry->msg_len);
+ if (err)
+ break;
+ ++entry;
+ ++datagrams;
+
+ if (timeout) {
+ ktime_get_ts(timeout);
+ *timeout = timespec_sub(end_time, *timeout);
+ if (timeout->tv_sec < 0) {
+ timeout->tv_sec = timeout->tv_nsec = 0;
+ break;
+ }
+
+ /* Timeout, return less than vlen datagrams */
+ if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
+ break;
+ }
+
+ /* Out of band data, return right away */
+ if (msg_sys.msg_flags & MSG_OOB)
+ break;
+ }
+
+out_put:
+ fput_light(sock->file, fput_needed);
+
+ if (err == 0)
+ return datagrams;
+
+ if (datagrams != 0) {
+ /*
+ * We may return less entries than requested (vlen) if the
+ * sock is non block and there aren't enough datagrams...
+ */
+ if (err != -EAGAIN) {
+ /*
+ * ... or if recvmsg returns an error after we
+ * received some datagrams, where we record the
+ * error to return on the next call or if the
+ * app asks about it using getsockopt(SO_ERROR).
+ */
+ sock->sk->sk_err = -err;
+ }
+ return datagrams;
+ }
+
+ return err;
+}
+
+SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
+ unsigned int, vlen, unsigned int, flags,
+ struct timespec __user *, timeout)
+{
+ int datagrams;
+ struct timespec timeout_sys;
+
+ if (!timeout)
+ return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
+
+ if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys)))
+ return -EFAULT;
+
+ datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
+
+ if (datagrams > 0 &&
+ copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys)))
+ datagrams = -EFAULT;
+
+ return datagrams;
+}
+
+#ifdef __ARCH_WANT_SYS_SOCKETCALL
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
-static const unsigned char nargs[19]={
+static const unsigned char nargs[20] = {
AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4)
+ AL(4),AL(5)
};
#undef AL
@@ -2100,7 +2255,7 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
int err;
unsigned int len;
- if (call < 1 || call > SYS_ACCEPT4)
+ if (call < 1 || call > SYS_RECVMMSG)
return -EINVAL;
len = nargs[call];
@@ -2178,6 +2333,10 @@ SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
case SYS_RECVMSG:
err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
break;
+ case SYS_RECVMMSG:
+ err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
+ (struct timespec __user *)a[4]);
+ break;
case SYS_ACCEPT4:
err = sys_accept4(a0, (struct sockaddr __user *)a1,
(int __user *)a[2], a[3]);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 117f68a8aa4..f4c7ff3a53e 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -686,8 +686,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
case AF_INET:
sin = svc_addr_in(rqstp);
sin6 = &sin6_storage;
- ipv6_addr_set(&sin6->sin6_addr, 0, 0,
- htonl(0x0000FFFF), sin->sin_addr.s_addr);
+ ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
break;
case AF_INET6:
sin6 = svc_addr_in6(rqstp);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 51ab497115e..0f133c5a8d3 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2214,7 +2214,7 @@ static const struct file_operations unix_seq_fops = {
#endif
-static struct net_proto_family unix_family_ops = {
+static const struct net_proto_family unix_family_ops = {
.family = PF_UNIX,
.create = unix_create,
.owner = THIS_MODULE,
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index abf7ca3f9ff..614bdcec1c8 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -1,3 +1,21 @@
+config WIRELESS_EXT
+ bool
+
+config WEXT_CORE
+ def_bool y
+ depends on CFG80211_WEXT || WIRELESS_EXT
+
+config WEXT_PROC
+ def_bool y
+ depends on PROC_FS
+ depends on WEXT_CORE
+
+config WEXT_SPY
+ bool
+
+config WEXT_PRIV
+ bool
+
config CFG80211
tristate "cfg80211 - wireless configuration API"
depends on RFKILL || !RFKILL
@@ -56,6 +74,12 @@ config CFG80211_REG_DEBUG
If unsure, say N.
+config CFG80211_DEFAULT_PS_VALUE
+ int
+ default 1 if CFG80211_DEFAULT_PS
+ default 0
+ depends on CFG80211
+
config CFG80211_DEFAULT_PS
bool "enable powersave by default"
depends on CFG80211
@@ -67,14 +91,10 @@ config CFG80211_DEFAULT_PS
applications instead -- they need to register their network
latency requirement, see Documentation/power/pm_qos_interface.txt.
-config CFG80211_DEFAULT_PS_VALUE
- int
- default 1 if CFG80211_DEFAULT_PS
- default 0
-
config CFG80211_DEBUGFS
bool "cfg80211 DebugFS entries"
- depends on CFG80211 && DEBUG_FS
+ depends on CFG80211
+ depends on DEBUG_FS
---help---
You can enable this if you want to debugfs entries for cfg80211.
@@ -83,6 +103,7 @@ config CFG80211_DEBUGFS
config WIRELESS_OLD_REGULATORY
bool "Old wireless static regulatory definitions"
default n
+ depends on CFG80211
---help---
This option enables the old static regulatory information
and uses it within the new framework. This option is available
@@ -94,20 +115,19 @@ config WIRELESS_OLD_REGULATORY
Say N and if you say Y, please tell us why. The default is N.
-config WIRELESS_EXT
- bool "Wireless extensions"
+config CFG80211_WEXT
+ bool "cfg80211 wireless extensions compatibility"
+ depends on CFG80211
+ select WEXT_CORE
default y
- ---help---
- This option enables the legacy wireless extensions
- (wireless network interface configuration via ioctls.)
-
- Say Y unless you've upgraded all your userspace to use
- nl80211 instead of wireless extensions.
+ help
+ Enable this option if you need old userspace for wireless
+ extensions with cfg80211-based drivers.
config WIRELESS_EXT_SYSFS
bool "Wireless extensions sysfs files"
default y
- depends on WIRELESS_EXT && SYSFS
+ depends on WEXT_CORE && SYSFS
help
This option enables the deprecated wireless statistics
files in /sys/class/net/*/wireless/. The same information
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3ecaa917997..f07c8dc7aab 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,13 +1,17 @@
-obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
obj-$(CONFIG_LIB80211) += lib80211.o
obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o
obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
+obj-$(CONFIG_WEXT_CORE) += wext-core.o
+obj-$(CONFIG_WEXT_PROC) += wext-proc.o
+obj-$(CONFIG_WEXT_SPY) += wext-spy.o
+obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
+
cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
-cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
+cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 45b2be3274d..07252967be9 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -21,6 +21,7 @@
#include "sysfs.h"
#include "debugfs.h"
#include "wext-compat.h"
+#include "ethtool.h"
/* name for sysfs, %d is appended */
#define PHY_NAME "phy"
@@ -358,6 +359,10 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
+#ifdef CONFIG_CFG80211_WEXT
+ rdev->wiphy.wext = &cfg80211_wext_handler;
+#endif
+
device_initialize(&rdev->wiphy.dev);
rdev->wiphy.dev.class = &ieee80211_class;
rdev->wiphy.dev.platform_data = rdev;
@@ -625,6 +630,10 @@ static void wdev_cleanup_work(struct work_struct *work)
dev_put(wdev->netdev);
}
+static struct device_type wiphy_type = {
+ .name = "wlan",
+};
+
static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
unsigned long state,
void *ndev)
@@ -641,6 +650,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
WARN_ON(wdev->iftype == NL80211_IFTYPE_UNSPECIFIED);
switch (state) {
+ case NETDEV_POST_INIT:
+ SET_NETDEV_DEVTYPE(dev, &wiphy_type);
+ break;
case NETDEV_REGISTER:
/*
* NB: cannot take rdev->mtx here because this may be
@@ -665,9 +677,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->netdev = dev;
wdev->sme_state = CFG80211_SME_IDLE;
mutex_unlock(&rdev->devlist_mtx);
-#ifdef CONFIG_WIRELESS_EXT
- if (!dev->wireless_handlers)
- dev->wireless_handlers = &cfg80211_wext_handler;
+#ifdef CONFIG_CFG80211_WEXT
wdev->wext.default_key = -1;
wdev->wext.default_mgmt_key = -1;
wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
@@ -681,6 +691,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
wdev->wext.ps = false;
}
#endif
+ if (!dev->ethtool_ops)
+ dev->ethtool_ops = &cfg80211_ethtool_ops;
break;
case NETDEV_GOING_DOWN:
switch (wdev->iftype) {
@@ -689,7 +701,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
break;
case NL80211_IFTYPE_STATION:
wdev_lock(wdev);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
wdev->wext.ie = NULL;
wdev->wext.ie_len = 0;
@@ -721,7 +733,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
mutex_unlock(&rdev->devlist_mtx);
dev_put(dev);
}
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
cfg80211_lock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
wdev_lock(wdev);
@@ -759,7 +771,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
sysfs_remove_link(&dev->dev.kobj, "phy80211");
list_del_init(&wdev->list);
rdev->devlist_generation++;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.keys);
#endif
}
diff --git a/net/wireless/ethtool.c b/net/wireless/ethtool.c
new file mode 100644
index 00000000000..ca4c825be93
--- /dev/null
+++ b/net/wireless/ethtool.c
@@ -0,0 +1,45 @@
+#include <linux/utsname.h>
+#include <net/cfg80211.h>
+#include "ethtool.h"
+
+static void cfg80211_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ strlcpy(info->driver, wiphy_dev(wdev->wiphy)->driver->name,
+ sizeof(info->driver));
+
+ strlcpy(info->version, init_utsname()->release, sizeof(info->version));
+
+ if (wdev->wiphy->fw_version[0])
+ strncpy(info->fw_version, wdev->wiphy->fw_version,
+ sizeof(info->fw_version));
+ else
+ strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+
+ strlcpy(info->bus_info, dev_name(wiphy_dev(wdev->wiphy)),
+ sizeof(info->bus_info));
+}
+
+static int cfg80211_get_regs_len(struct net_device *dev)
+{
+ /* For now, return 0... */
+ return 0;
+}
+
+static void cfg80211_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+ void *data)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ regs->version = wdev->wiphy->hw_version;
+ regs->len = 0;
+}
+
+const struct ethtool_ops cfg80211_ethtool_ops = {
+ .get_drvinfo = cfg80211_get_drvinfo,
+ .get_regs_len = cfg80211_get_regs_len,
+ .get_regs = cfg80211_get_regs,
+ .get_link = ethtool_op_get_link,
+};
diff --git a/net/wireless/ethtool.h b/net/wireless/ethtool.h
new file mode 100644
index 00000000000..695ecad20bd
--- /dev/null
+++ b/net/wireless/ethtool.h
@@ -0,0 +1,6 @@
+#ifndef __CFG80211_ETHTOOL__
+#define __CFG80211_ETHTOOL__
+
+extern const struct ethtool_ops cfg80211_ethtool_ops;
+
+#endif /* __CFG80211_ETHTOOL__ */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index c8833891197..39b6d92e282 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -15,7 +15,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_bss *bss;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -44,7 +44,7 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
@@ -96,7 +96,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
kfree(wdev->connect_keys);
wdev->connect_keys = connkeys;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
wdev->wext.ibss.channel = params->channel;
#endif
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
@@ -154,7 +154,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
wdev->current_bss = NULL;
wdev->ssid_len = 0;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!nowext)
wdev->wext.ibss.ssid_len = 0;
#endif
@@ -203,7 +203,7 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
return err;
}
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev)
{
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 79d2eec54ce..ceb2c14c8f4 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -331,7 +331,7 @@ void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
{
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
char *buf = kmalloc(128, gfp);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index ca3c92a0a14..f48394126bf 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1264,7 +1264,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = func(&rdev->wiphy, dev, key.idx);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!err) {
if (func == rdev->ops->set_default_key)
dev->ieee80211_ptr->wext.default_key = key.idx;
@@ -1365,7 +1365,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
if (!err)
err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!err) {
if (key.idx == dev->ieee80211_ptr->wext.default_key)
dev->ieee80211_ptr->wext.default_key = -1;
@@ -3105,6 +3105,8 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U16(msg, NL80211_BSS_BEACON_INTERVAL, res->beacon_interval);
NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
+ NLA_PUT_U32(msg, NL80211_BSS_SEEN_MS_AGO,
+ jiffies_to_msecs(jiffies - intbss->ts));
switch (rdev->wiphy.signal_type) {
case CFG80211_SIGNAL_TYPE_MBM:
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index e5f92ee758f..2e8c515f3c5 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -22,7 +22,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
{
struct cfg80211_scan_request *request;
struct net_device *dev;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -47,7 +47,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
else
nl80211_send_scan_done(rdev, dev);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (!request->aborted) {
memset(&wrqu, 0, sizeof(wrqu));
@@ -592,7 +592,7 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
}
EXPORT_SYMBOL(cfg80211_unlink_bss);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
int cfg80211_wext_siwscan(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 93c3ed32920..d3624152f7f 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -345,7 +345,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
u8 *country_ie;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -362,7 +362,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
resp_ie, resp_ie_len,
status, GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (wextev) {
if (req_ie && status == WLAN_STATUS_SUCCESS) {
memset(&wrqu, 0, sizeof(wrqu));
@@ -477,7 +477,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
const u8 *resp_ie, size_t resp_ie_len)
{
struct cfg80211_bss *bss;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -512,7 +512,7 @@ void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
req_ie, req_ie_len, resp_ie, resp_ie_len,
GFP_KERNEL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
if (req_ie) {
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = req_ie_len;
@@ -573,7 +573,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
int i;
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
@@ -631,7 +631,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
for (i = 0; i < 6; i++)
rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
-#ifdef CONFIG_WIRELESS_EXT
+#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
diff --git a/net/wireless/wext.c b/net/wireless/wext-core.c
index 60fe57761ca..a4e5ddc8d4f 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext-core.c
@@ -1,112 +1,28 @@
/*
- * This file implement the Wireless Extensions APIs.
+ * This file implement the Wireless Extensions core API.
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* (As all part of the Linux kernel, this file is GPL)
*/
-
-/************************** DOCUMENTATION **************************/
-/*
- * API definition :
- * --------------
- * See <linux/wireless.h> for details of the APIs and the rest.
- *
- * History :
- * -------
- *
- * v1 - 5.12.01 - Jean II
- * o Created this file.
- *
- * v2 - 13.12.01 - Jean II
- * o Move /proc/net/wireless stuff from net/core/dev.c to here
- * o Make Wireless Extension IOCTLs go through here
- * o Added iw_handler handling ;-)
- * o Added standard ioctl description
- * o Initial dumb commit strategy based on orinoco.c
- *
- * v3 - 19.12.01 - Jean II
- * o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
- * o Add event dispatcher function
- * o Add event description
- * o Propagate events as rtnetlink IFLA_WIRELESS option
- * o Generate event on selected SET requests
- *
- * v4 - 18.04.02 - Jean II
- * o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
- *
- * v5 - 21.06.02 - Jean II
- * o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
- * o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
- * o Add IWEVCUSTOM for driver specific event/scanning token
- * o Turn on WE_STRICT_WRITE by default + kernel warning
- * o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
- * o Fix off-by-one in test (extra_size <= IFNAMSIZ)
- *
- * v6 - 9.01.03 - Jean II
- * o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
- * o Add enhanced spy support : iw_handler_set_thrspy() and event.
- * o Add WIRELESS_EXT version display in /proc/net/wireless
- *
- * v6 - 18.06.04 - Jean II
- * o Change get_spydata() method for added safety
- * o Remove spy #ifdef, they are always on -> cleaner code
- * o Allow any size GET request if user specifies length > max
- * and if request has IW_DESCR_FLAG_NOMAX flag or is SIOCGIWPRIV
- * o Start migrating get_wireless_stats to struct iw_handler_def
- * o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
- * Based on patch from Pavel Roskin <proski@gnu.org> :
- * o Fix kernel data leak to user space in private handler handling
- *
- * v7 - 18.3.05 - Jean II
- * o Remove (struct iw_point *)->pointer from events and streams
- * o Remove spy_offset from struct iw_handler_def
- * o Start deprecating dev->get_wireless_stats, output a warning
- * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless
- * o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats)
- *
- * v8 - 17.02.06 - Jean II
- * o RtNetlink requests support (SET/GET)
- *
- * v8b - 03.08.06 - Herbert Xu
- * o Fix Wireless Event locking issues.
- *
- * v9 - 14.3.06 - Jean II
- * o Change length in ESSID and NICK to strlen() instead of strlen()+1
- * o Make standard_ioctl_num and standard_event_num unsigned
- * o Remove (struct net_device *)->get_wireless_stats()
- *
- * v10 - 16.3.07 - Jean II
- * o Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/***************************** INCLUDES *****************************/
-
-#include <linux/module.h>
-#include <linux/types.h> /* off_t */
-#include <linux/netdevice.h> /* struct ifreq, dev_get_by_name() */
-#include <linux/proc_fs.h>
-#include <linux/rtnetlink.h> /* rtnetlink stuff */
-#include <linux/seq_file.h>
-#include <linux/init.h> /* for __init */
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-#include <linux/etherdevice.h> /* compare_ether_addr */
-#include <linux/interrupt.h>
-#include <net/net_namespace.h>
-
-#include <linux/wireless.h> /* Pretty obvious */
-#include <net/iw_handler.h> /* New driver API */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/wireless.h>
+#include <linux/uaccess.h>
+#include <net/cfg80211.h>
+#include <net/iw_handler.h>
#include <net/netlink.h>
#include <net/wext.h>
+#include <net/net_namespace.h>
+
+typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
+ unsigned int, struct iw_request_info *,
+ iw_handler);
-#include <asm/uaccess.h> /* copy_to_user() */
-/************************* GLOBAL VARIABLES *************************/
-/*
- * You should not use global variables, because of re-entrancy.
- * On our case, it's only const, so it's OK...
- */
/*
* Meta-data about all the standard Wireless Extension request we
* know about.
@@ -390,18 +306,6 @@ static const struct iw_ioctl_description standard_event[] = {
};
static const unsigned standard_event_num = ARRAY_SIZE(standard_event);
-/* Size (in bytes) of the various private data types */
-static const char iw_priv_type_size[] = {
- 0, /* IW_PRIV_TYPE_NONE */
- 1, /* IW_PRIV_TYPE_BYTE */
- 1, /* IW_PRIV_TYPE_CHAR */
- 0, /* Not defined */
- sizeof(__u32), /* IW_PRIV_TYPE_INT */
- sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
- sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
- 0, /* Not defined */
-};
-
/* Size (in bytes) of various events */
static const int event_type_size[] = {
IW_EV_LCP_LEN, /* IW_HEADER_TYPE_NULL */
@@ -433,323 +337,346 @@ static const int compat_event_type_size[] = {
};
#endif
-/************************ COMMON SUBROUTINES ************************/
-/*
- * Stuff that may be used in various place or doesn't fit in one
- * of the section below.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the driver handler associated with a specific Wireless Extension.
- */
-static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
-{
- /* Don't "optimise" the following variable, it will crash */
- unsigned int index; /* *MUST* be unsigned */
- /* Check if we have some wireless handlers defined */
- if (dev->wireless_handlers == NULL)
- return NULL;
-
- /* Try as a standard command */
- index = cmd - SIOCIWFIRST;
- if (index < dev->wireless_handlers->num_standard)
- return dev->wireless_handlers->standard[index];
-
- /* Try as a private command */
- index = cmd - SIOCIWFIRSTPRIV;
- if (index < dev->wireless_handlers->num_private)
- return dev->wireless_handlers->private[index];
+/* IW event code */
- /* Not found */
- return NULL;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Get statistics out of the driver
- */
-struct iw_statistics *get_wireless_stats(struct net_device *dev)
+static int __net_init wext_pernet_init(struct net *net)
{
- /* New location */
- if ((dev->wireless_handlers != NULL) &&
- (dev->wireless_handlers->get_wireless_stats != NULL))
- return dev->wireless_handlers->get_wireless_stats(dev);
-
- /* Not found */
- return NULL;
+ skb_queue_head_init(&net->wext_nlevents);
+ return 0;
}
-/* ---------------------------------------------------------------- */
-/*
- * Call the commit handler in the driver
- * (if exist and if conditions are right)
- *
- * Note : our current commit strategy is currently pretty dumb,
- * but we will be able to improve on that...
- * The goal is to try to agreagate as many changes as possible
- * before doing the commit. Drivers that will define a commit handler
- * are usually those that need a reset after changing parameters, so
- * we want to minimise the number of reset.
- * A cool idea is to use a timer : at each "set" command, we re-set the
- * timer, when the timer eventually fires, we call the driver.
- * Hopefully, more on that later.
- *
- * Also, I'm waiting to see how many people will complain about the
- * netif_running(dev) test. I'm open on that one...
- * Hopefully, the driver will remember to do a commit in "open()" ;-)
- */
-static int call_commit_handler(struct net_device *dev)
+static void __net_exit wext_pernet_exit(struct net *net)
{
- if ((netif_running(dev)) &&
- (dev->wireless_handlers->standard[0] != NULL))
- /* Call the commit handler on the driver */
- return dev->wireless_handlers->standard[0](dev, NULL,
- NULL, NULL);
- else
- return 0; /* Command completed successfully */
+ skb_queue_purge(&net->wext_nlevents);
}
-/* ---------------------------------------------------------------- */
-/*
- * Calculate size of private arguments
- */
-static int get_priv_size(__u16 args)
-{
- int num = args & IW_PRIV_SIZE_MASK;
- int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+static struct pernet_operations wext_pernet_ops = {
+ .init = wext_pernet_init,
+ .exit = wext_pernet_exit,
+};
- return num * iw_priv_type_size[type];
+static int __init wireless_nlevent_init(void)
+{
+ return register_pernet_subsys(&wext_pernet_ops);
}
-/* ---------------------------------------------------------------- */
-/*
- * Re-calculate the size of private arguments
- */
-static int adjust_priv_size(__u16 args, struct iw_point *iwp)
+subsys_initcall(wireless_nlevent_init);
+
+/* Process events generated by the wireless layer or the driver. */
+static void wireless_nlevent_process(struct work_struct *work)
{
- int num = iwp->length;
- int max = args & IW_PRIV_SIZE_MASK;
- int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+ struct sk_buff *skb;
+ struct net *net;
- /* Make sure the driver doesn't goof up */
- if (max < num)
- num = max;
+ rtnl_lock();
+
+ for_each_net(net) {
+ while ((skb = skb_dequeue(&net->wext_nlevents)))
+ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
+ GFP_KERNEL);
+ }
- return num * iw_priv_type_size[type];
+ rtnl_unlock();
}
-/* ---------------------------------------------------------------- */
-/*
- * Standard Wireless Handler : get wireless stats
- * Allow programatic access to /proc/net/wireless even if /proc
- * doesn't exist... Also more efficient...
- */
-static int iw_handler_get_iwstats(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
+
+static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
+ struct sk_buff *skb)
{
- /* Get stats from the driver */
- struct iw_statistics *stats;
+ struct ifinfomsg *r;
+ struct nlmsghdr *nlh;
- stats = get_wireless_stats(dev);
- if (stats) {
- /* Copy statistics to extra */
- memcpy(extra, stats, sizeof(struct iw_statistics));
- wrqu->data.length = sizeof(struct iw_statistics);
+ nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
+ if (!nlh)
+ return NULL;
- /* Check if we need to clear the updated flag */
- if (wrqu->data.flags != 0)
- stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
- return 0;
- } else
- return -EOPNOTSUPP;
+ r = nlmsg_data(nlh);
+ r->ifi_family = AF_UNSPEC;
+ r->__ifi_pad = 0;
+ r->ifi_type = dev->type;
+ r->ifi_index = dev->ifindex;
+ r->ifi_flags = dev_get_flags(dev);
+ r->ifi_change = 0; /* Wireless changes don't affect those flags */
+
+ NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
+
+ return nlh;
+ nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return NULL;
}
-/* ---------------------------------------------------------------- */
+
/*
- * Standard Wireless Handler : get iwpriv definitions
- * Export the driver private handler definition
- * They will be picked up by tools like iwpriv...
+ * Main event dispatcher. Called from other parts and drivers.
+ * Send the event on the appropriate channels.
+ * May be called from interrupt context.
*/
-static int iw_handler_get_private(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
+void wireless_send_event(struct net_device * dev,
+ unsigned int cmd,
+ union iwreq_data * wrqu,
+ const char * extra)
{
- /* Check if the driver has something to export */
- if ((dev->wireless_handlers->num_private_args == 0) ||
- (dev->wireless_handlers->private_args == NULL))
- return -EOPNOTSUPP;
+ const struct iw_ioctl_description * descr = NULL;
+ int extra_len = 0;
+ struct iw_event *event; /* Mallocated whole event */
+ int event_len; /* Its size */
+ int hdr_len; /* Size of the event header */
+ int wrqu_off = 0; /* Offset in wrqu */
+ /* Don't "optimise" the following variable, it will crash */
+ unsigned cmd_index; /* *MUST* be unsigned */
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct nlattr *nla;
+#ifdef CONFIG_COMPAT
+ struct __compat_iw_event *compat_event;
+ struct compat_iw_point compat_wrqu;
+ struct sk_buff *compskb;
+#endif
- /* Check if there is enough buffer up there */
- if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
- /* User space can't know in advance how large the buffer
- * needs to be. Give it a hint, so that we can support
- * any size buffer we want somewhat efficiently... */
- wrqu->data.length = dev->wireless_handlers->num_private_args;
- return -E2BIG;
+ /*
+ * Nothing in the kernel sends scan events with data, be safe.
+ * This is necessary because we cannot fix up scan event data
+ * for compat, due to being contained in 'extra', but normally
+ * applications are required to retrieve the scan data anyway
+ * and no data is included in the event, this codifies that
+ * practice.
+ */
+ if (WARN_ON(cmd == SIOCGIWSCAN && extra))
+ extra = NULL;
+
+ /* Get the description of the Event */
+ if (cmd <= SIOCIWLAST) {
+ cmd_index = cmd - SIOCIWFIRST;
+ if (cmd_index < standard_ioctl_num)
+ descr = &(standard_ioctl[cmd_index]);
+ } else {
+ cmd_index = cmd - IWEVFIRST;
+ if (cmd_index < standard_event_num)
+ descr = &(standard_event[cmd_index]);
+ }
+ /* Don't accept unknown events */
+ if (descr == NULL) {
+ /* Note : we don't return an error to the driver, because
+ * the driver would not know what to do about it. It can't
+ * return an error to the user, because the event is not
+ * initiated by a user request.
+ * The best the driver could do is to log an error message.
+ * We will do it ourselves instead...
+ */
+ printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+ dev->name, cmd);
+ return;
}
- /* Set the number of available ioctls. */
- wrqu->data.length = dev->wireless_handlers->num_private_args;
+ /* Check extra parameters and set extra_len */
+ if (descr->header_type == IW_HEADER_TYPE_POINT) {
+ /* Check if number of token fits within bounds */
+ if (wrqu->data.length > descr->max_tokens) {
+ printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
+ return;
+ }
+ if (wrqu->data.length < descr->min_tokens) {
+ printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
+ return;
+ }
+ /* Calculate extra_len - extra is NULL for restricted events */
+ if (extra != NULL)
+ extra_len = wrqu->data.length * descr->token_size;
+ /* Always at an offset in wrqu */
+ wrqu_off = IW_EV_POINT_OFF;
+ }
- /* Copy structure to the user buffer. */
- memcpy(extra, dev->wireless_handlers->private_args,
- sizeof(struct iw_priv_args) * wrqu->data.length);
+ /* Total length of the event */
+ hdr_len = event_type_size[descr->header_type];
+ event_len = hdr_len + extra_len;
- return 0;
-}
+ /*
+ * The problem for 64/32 bit.
+ *
+ * On 64-bit, a regular event is laid out as follows:
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ * | event.len | event.cmd | p a d d i n g |
+ * | wrqu data ... (with the correct size) |
+ *
+ * This padding exists because we manipulate event->u,
+ * and 'event' is not packed.
+ *
+ * An iw_point event is laid out like this instead:
+ * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ * | event.len | event.cmd | p a d d i n g |
+ * | iwpnt.len | iwpnt.flg | p a d d i n g |
+ * | extra data ...
+ *
+ * The second padding exists because struct iw_point is extended,
+ * but this depends on the platform...
+ *
+ * On 32-bit, all the padding shouldn't be there.
+ */
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!skb)
+ return;
-/******************** /proc/net/wireless SUPPORT ********************/
-/*
- * The /proc/net/wireless file is a human readable user-space interface
- * exporting various wireless specific statistics from the wireless devices.
- * This is the most popular part of the Wireless Extensions ;-)
- *
- * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
- * The content of the file is basically the content of "struct iw_statistics".
- */
+ /* Send via the RtNetlink event channel */
+ nlh = rtnetlink_ifinfo_prep(dev, skb);
+ if (WARN_ON(!nlh)) {
+ kfree_skb(skb);
+ return;
+ }
-#ifdef CONFIG_PROC_FS
+ /* Add the wireless events in the netlink packet */
+ nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
+ if (!nla) {
+ kfree_skb(skb);
+ return;
+ }
+ event = nla_data(nla);
-/* ---------------------------------------------------------------- */
-/*
- * Print one entry (line) of /proc/net/wireless
- */
-static void wireless_seq_printf_stats(struct seq_file *seq,
- struct net_device *dev)
-{
- /* Get stats from the driver */
- struct iw_statistics *stats = get_wireless_stats(dev);
- static struct iw_statistics nullstats = {};
+ /* Fill event - first clear to avoid data leaking */
+ memset(event, 0, hdr_len);
+ event->len = event_len;
+ event->cmd = cmd;
+ memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
+ if (extra_len)
+ memcpy(((char *) event) + hdr_len, extra, extra_len);
- /* show device if it's wireless regardless of current stats */
- if (!stats && dev->wireless_handlers)
- stats = &nullstats;
+ nlmsg_end(skb, nlh);
+#ifdef CONFIG_COMPAT
+ hdr_len = compat_event_type_size[descr->header_type];
+ event_len = hdr_len + extra_len;
- if (stats) {
- seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
- "%6d %6d %6d\n",
- dev->name, stats->status, stats->qual.qual,
- stats->qual.updated & IW_QUAL_QUAL_UPDATED
- ? '.' : ' ',
- ((__s32) stats->qual.level) -
- ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
- stats->qual.updated & IW_QUAL_LEVEL_UPDATED
- ? '.' : ' ',
- ((__s32) stats->qual.noise) -
- ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
- stats->qual.updated & IW_QUAL_NOISE_UPDATED
- ? '.' : ' ',
- stats->discard.nwid, stats->discard.code,
- stats->discard.fragment, stats->discard.retries,
- stats->discard.misc, stats->miss.beacon);
-
- if (stats != &nullstats)
- stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
+ if (!compskb) {
+ kfree_skb(skb);
+ return;
}
-}
-/* ---------------------------------------------------------------- */
-/*
- * Print info for /proc/net/wireless (print all entries)
- */
-static int wireless_dev_seq_show(struct seq_file *seq, void *v)
-{
- might_sleep();
-
- if (v == SEQ_START_TOKEN)
- seq_printf(seq, "Inter-| sta-| Quality | Discarded "
- "packets | Missed | WE\n"
- " face | tus | link level noise | nwid "
- "crypt frag retry misc | beacon | %d\n",
- WIRELESS_EXT);
- else
- wireless_seq_printf_stats(seq, v);
- return 0;
+ /* Send via the RtNetlink event channel */
+ nlh = rtnetlink_ifinfo_prep(dev, compskb);
+ if (WARN_ON(!nlh)) {
+ kfree_skb(skb);
+ kfree_skb(compskb);
+ return;
+ }
+
+ /* Add the wireless events in the netlink packet */
+ nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
+ if (!nla) {
+ kfree_skb(skb);
+ kfree_skb(compskb);
+ return;
+ }
+ compat_event = nla_data(nla);
+
+ compat_event->len = event_len;
+ compat_event->cmd = cmd;
+ if (descr->header_type == IW_HEADER_TYPE_POINT) {
+ compat_wrqu.length = wrqu->data.length;
+ compat_wrqu.flags = wrqu->data.flags;
+ memcpy(&compat_event->pointer,
+ ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
+ hdr_len - IW_EV_COMPAT_LCP_LEN);
+ if (extra_len)
+ memcpy(((char *) compat_event) + hdr_len,
+ extra, extra_len);
+ } else {
+ /* extra_len must be zero, so no if (extra) needed */
+ memcpy(&compat_event->pointer, wrqu,
+ hdr_len - IW_EV_COMPAT_LCP_LEN);
+ }
+
+ nlmsg_end(compskb, nlh);
+
+ skb_shinfo(skb)->frag_list = compskb;
+#endif
+ skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
+ schedule_work(&wireless_nlevent_work);
}
+EXPORT_SYMBOL(wireless_send_event);
+
+
+
+/* IW handlers */
-static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+struct iw_statistics *get_wireless_stats(struct net_device *dev)
{
- struct net *net = seq_file_net(seq);
- loff_t off;
- struct net_device *dev;
+#ifdef CONFIG_WIRELESS_EXT
+ if ((dev->wireless_handlers != NULL) &&
+ (dev->wireless_handlers->get_wireless_stats != NULL))
+ return dev->wireless_handlers->get_wireless_stats(dev);
+#endif
- rtnl_lock();
- if (!*pos)
- return SEQ_START_TOKEN;
+#ifdef CONFIG_CFG80211_WEXT
+ if (dev->ieee80211_ptr && dev->ieee80211_ptr &&
+ dev->ieee80211_ptr->wiphy &&
+ dev->ieee80211_ptr->wiphy->wext &&
+ dev->ieee80211_ptr->wiphy->wext->get_wireless_stats)
+ return dev->ieee80211_ptr->wiphy->wext->get_wireless_stats(dev);
+#endif
- off = 1;
- for_each_netdev(net, dev)
- if (off++ == *pos)
- return dev;
+ /* not found */
return NULL;
}
-static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static int iw_handler_get_iwstats(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
{
- struct net *net = seq_file_net(seq);
+ /* Get stats from the driver */
+ struct iw_statistics *stats;
- ++*pos;
+ stats = get_wireless_stats(dev);
+ if (stats) {
+ /* Copy statistics to extra */
+ memcpy(extra, stats, sizeof(struct iw_statistics));
+ wrqu->data.length = sizeof(struct iw_statistics);
- return v == SEQ_START_TOKEN ?
- first_net_device(net) : next_net_device(v);
+ /* Check if we need to clear the updated flag */
+ if (wrqu->data.flags != 0)
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ return 0;
+ } else
+ return -EOPNOTSUPP;
}
-static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
{
- rtnl_unlock();
-}
-
-static const struct seq_operations wireless_seq_ops = {
- .start = wireless_dev_seq_start,
- .next = wireless_dev_seq_next,
- .stop = wireless_dev_seq_stop,
- .show = wireless_dev_seq_show,
-};
+ /* Don't "optimise" the following variable, it will crash */
+ unsigned int index; /* *MUST* be unsigned */
+ const struct iw_handler_def *handlers = NULL;
-static int seq_open_wireless(struct inode *inode, struct file *file)
-{
- return seq_open_net(inode, file, &wireless_seq_ops,
- sizeof(struct seq_net_private));
-}
+#ifdef CONFIG_CFG80211_WEXT
+ if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)
+ handlers = dev->ieee80211_ptr->wiphy->wext;
+#endif
+#ifdef CONFIG_WIRELESS_EXT
+ if (dev->wireless_handlers)
+ handlers = dev->wireless_handlers;
+#endif
-static const struct file_operations wireless_seq_fops = {
- .owner = THIS_MODULE,
- .open = seq_open_wireless,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release_net,
-};
+ if (!handlers)
+ return NULL;
-int wext_proc_init(struct net *net)
-{
- /* Create /proc/net/wireless entry */
- if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
- return -ENOMEM;
+ /* Try as a standard command */
+ index = cmd - SIOCIWFIRST;
+ if (index < handlers->num_standard)
+ return handlers->standard[index];
- return 0;
-}
+#ifdef CONFIG_WEXT_PRIV
+ /* Try as a private command */
+ index = cmd - SIOCIWFIRSTPRIV;
+ if (index < handlers->num_private)
+ return handlers->private[index];
+#endif
-void wext_proc_exit(struct net *net)
-{
- proc_net_remove(net, "wireless");
+ /* Not found */
+ return NULL;
}
-#endif /* CONFIG_PROC_FS */
-/************************** IOCTL SUPPORT **************************/
-/*
- * The original user space API to configure all those Wireless Extensions
- * is through IOCTLs.
- * In there, we check if we need to call the new driver API (iw_handler)
- * or just call the driver ioctl handler.
- */
-
-/* ---------------------------------------------------------------- */
static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd,
const struct iw_ioctl_description *descr,
iw_handler handler, struct net_device *dev,
@@ -893,188 +820,39 @@ out:
}
/*
- * Wrapper to call a standard Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- */
-static int ioctl_standard_call(struct net_device * dev,
- struct iwreq *iwr,
- unsigned int cmd,
- struct iw_request_info *info,
- iw_handler handler)
-{
- const struct iw_ioctl_description * descr;
- int ret = -EINVAL;
-
- /* Get the description of the IOCTL */
- if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
- return -EOPNOTSUPP;
- descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
-
- /* Check if we have a pointer to user space data or not */
- if (descr->header_type != IW_HEADER_TYPE_POINT) {
-
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), NULL);
-
- /* Generate an event to notify listeners of the change */
- if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
- ((ret == 0) || (ret == -EIWCOMMIT)))
- wireless_send_event(dev, cmd, &(iwr->u), NULL);
- } else {
- ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, info);
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- /* Here, we will generate the appropriate event if needed */
-
- return ret;
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Wrapper to call a private Wireless Extension handler.
- * We do various checks and also take care of moving data between
- * user space and kernel space.
- * It's not as nice and slimline as the standard wrapper. The cause
- * is struct iw_priv_args, which was not really designed for the
- * job we are going here.
+ * Call the commit handler in the driver
+ * (if exist and if conditions are right)
+ *
+ * Note : our current commit strategy is currently pretty dumb,
+ * but we will be able to improve on that...
+ * The goal is to try to agreagate as many changes as possible
+ * before doing the commit. Drivers that will define a commit handler
+ * are usually those that need a reset after changing parameters, so
+ * we want to minimise the number of reset.
+ * A cool idea is to use a timer : at each "set" command, we re-set the
+ * timer, when the timer eventually fires, we call the driver.
+ * Hopefully, more on that later.
*
- * IMPORTANT : This function prevent to set and get data on the same
- * IOCTL and enforce the SET/GET convention. Not doing it would be
- * far too hairy...
- * If you need to set and get data at the same time, please don't use
- * a iw_handler but process it in your ioctl handler (i.e. use the
- * old driver API).
+ * Also, I'm waiting to see how many people will complain about the
+ * netif_running(dev) test. I'm open on that one...
+ * Hopefully, the driver will remember to do a commit in "open()" ;-)
*/
-static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
- const struct iw_priv_args **descrp)
-{
- const struct iw_priv_args *descr;
- int i, extra_size;
-
- descr = NULL;
- for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
- if (cmd == dev->wireless_handlers->private_args[i].cmd) {
- descr = &dev->wireless_handlers->private_args[i];
- break;
- }
- }
-
- extra_size = 0;
- if (descr) {
- if (IW_IS_SET(cmd)) {
- int offset = 0; /* For sub-ioctls */
- /* Check for sub-ioctl handler */
- if (descr->name[0] == '\0')
- /* Reserve one int for sub-ioctl index */
- offset = sizeof(__u32);
-
- /* Size of set arguments */
- extra_size = get_priv_size(descr->set_args);
-
- /* Does it fits in iwr ? */
- if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
- ((extra_size + offset) <= IFNAMSIZ))
- extra_size = 0;
- } else {
- /* Size of get arguments */
- extra_size = get_priv_size(descr->get_args);
-
- /* Does it fits in iwr ? */
- if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
- (extra_size <= IFNAMSIZ))
- extra_size = 0;
- }
- }
- *descrp = descr;
- return extra_size;
-}
-
-static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
- const struct iw_priv_args *descr,
- iw_handler handler, struct net_device *dev,
- struct iw_request_info *info, int extra_size)
-{
- char *extra;
- int err;
-
- /* Check what user space is giving us */
- if (IW_IS_SET(cmd)) {
- if (!iwp->pointer && iwp->length != 0)
- return -EFAULT;
-
- if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
- return -E2BIG;
- } else if (!iwp->pointer)
- return -EFAULT;
-
- extra = kmalloc(extra_size, GFP_KERNEL);
- if (!extra)
- return -ENOMEM;
-
- /* If it is a SET, get all the extra data in here */
- if (IW_IS_SET(cmd) && (iwp->length != 0)) {
- if (copy_from_user(extra, iwp->pointer, extra_size)) {
- err = -EFAULT;
- goto out;
- }
- }
-
- /* Call the handler */
- err = handler(dev, info, (union iwreq_data *) iwp, extra);
-
- /* If we have something to return to the user */
- if (!err && IW_IS_GET(cmd)) {
- /* Adjust for the actual length if it's variable,
- * avoid leaking kernel bits outside.
- */
- if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
- extra_size = adjust_priv_size(descr->get_args, iwp);
-
- if (copy_to_user(iwp->pointer, extra, extra_size))
- err = -EFAULT;
- }
-
-out:
- kfree(extra);
- return err;
-}
-
-static int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, struct iw_request_info *info,
- iw_handler handler)
+int call_commit_handler(struct net_device *dev)
{
- int extra_size = 0, ret = -EINVAL;
- const struct iw_priv_args *descr;
-
- extra_size = get_priv_descr_and_size(dev, cmd, &descr);
-
- /* Check if we have a pointer to user space data or not. */
- if (extra_size == 0) {
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
- } else {
- ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
- handler, dev, info, extra_size);
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- return ret;
+#ifdef CONFIG_WIRELESS_EXT
+ if ((netif_running(dev)) &&
+ (dev->wireless_handlers->standard[0] != NULL))
+ /* Call the commit handler on the driver */
+ return dev->wireless_handlers->standard[0](dev, NULL,
+ NULL, NULL);
+ else
+ return 0; /* Command completed successfully */
+#else
+ /* cfg80211 has no commit */
+ return 0;
+#endif
}
-/* ---------------------------------------------------------------- */
-typedef int (*wext_ioctl_func)(struct net_device *, struct iwreq *,
- unsigned int, struct iw_request_info *,
- iw_handler);
-
/*
* Main IOCTl dispatcher.
* Check the type of IOCTL and call the appropriate wrapper...
@@ -1103,9 +881,11 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
return standard(dev, iwr, cmd, info,
&iw_handler_get_iwstats);
+#ifdef CONFIG_WEXT_PRIV
if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
return standard(dev, iwr, cmd, info,
- &iw_handler_get_private);
+ iw_handler_get_private);
+#endif
/* Basic check */
if (!netif_device_present(dev))
@@ -1117,7 +897,7 @@ static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
/* Standard and private are not the same */
if (cmd < SIOCIWFIRSTPRIV)
return standard(dev, iwr, cmd, info, handler);
- else
+ else if (private)
return private(dev, iwr, cmd, info, handler);
}
/* Old driver API : call driver ioctl handler */
@@ -1157,6 +937,50 @@ static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
return ret;
}
+/*
+ * Wrapper to call a standard Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ */
+static int ioctl_standard_call(struct net_device * dev,
+ struct iwreq *iwr,
+ unsigned int cmd,
+ struct iw_request_info *info,
+ iw_handler handler)
+{
+ const struct iw_ioctl_description * descr;
+ int ret = -EINVAL;
+
+ /* Get the description of the IOCTL */
+ if ((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+ return -EOPNOTSUPP;
+ descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+
+ /* Check if we have a pointer to user space data or not */
+ if (descr->header_type != IW_HEADER_TYPE_POINT) {
+
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), NULL);
+
+ /* Generate an event to notify listeners of the change */
+ if ((descr->flags & IW_DESCR_FLAG_EVENT) &&
+ ((ret == 0) || (ret == -EIWCOMMIT)))
+ wireless_send_event(dev, cmd, &(iwr->u), NULL);
+ } else {
+ ret = ioctl_standard_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, info);
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ /* Here, we will generate the appropriate event if needed */
+
+ return ret;
+}
+
+
int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
void __user *arg)
{
@@ -1205,43 +1029,6 @@ static int compat_standard_call(struct net_device *dev,
return err;
}
-static int compat_private_call(struct net_device *dev, struct iwreq *iwr,
- unsigned int cmd, struct iw_request_info *info,
- iw_handler handler)
-{
- const struct iw_priv_args *descr;
- int ret, extra_size;
-
- extra_size = get_priv_descr_and_size(dev, cmd, &descr);
-
- /* Check if we have a pointer to user space data or not. */
- if (extra_size == 0) {
- /* No extra arguments. Trivial to handle */
- ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
- } else {
- struct compat_iw_point *iwp_compat;
- struct iw_point iwp;
-
- iwp_compat = (struct compat_iw_point *) &iwr->u.data;
- iwp.pointer = compat_ptr(iwp_compat->pointer);
- iwp.length = iwp_compat->length;
- iwp.flags = iwp_compat->flags;
-
- ret = ioctl_private_iw_point(&iwp, cmd, descr,
- handler, dev, info, extra_size);
-
- iwp_compat->pointer = ptr_to_compat(iwp.pointer);
- iwp_compat->length = iwp.length;
- iwp_compat->flags = iwp.flags;
- }
-
- /* Call commit handler if needed and defined */
- if (ret == -EIWCOMMIT)
- ret = call_commit_handler(dev);
-
- return ret;
-}
-
int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
unsigned long arg)
{
@@ -1274,502 +1061,3 @@ int compat_wext_handle_ioctl(struct net *net, unsigned int cmd,
return ret;
}
#endif
-
-static int __net_init wext_pernet_init(struct net *net)
-{
- skb_queue_head_init(&net->wext_nlevents);
- return 0;
-}
-
-static void __net_exit wext_pernet_exit(struct net *net)
-{
- skb_queue_purge(&net->wext_nlevents);
-}
-
-static struct pernet_operations wext_pernet_ops = {
- .init = wext_pernet_init,
- .exit = wext_pernet_exit,
-};
-
-static int __init wireless_nlevent_init(void)
-{
- return register_pernet_subsys(&wext_pernet_ops);
-}
-
-subsys_initcall(wireless_nlevent_init);
-
-/* Process events generated by the wireless layer or the driver. */
-static void wireless_nlevent_process(struct work_struct *work)
-{
- struct sk_buff *skb;
- struct net *net;
-
- rtnl_lock();
-
- for_each_net(net) {
- while ((skb = skb_dequeue(&net->wext_nlevents)))
- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
- GFP_KERNEL);
- }
-
- rtnl_unlock();
-}
-
-static DECLARE_WORK(wireless_nlevent_work, wireless_nlevent_process);
-
-static struct nlmsghdr *rtnetlink_ifinfo_prep(struct net_device *dev,
- struct sk_buff *skb)
-{
- struct ifinfomsg *r;
- struct nlmsghdr *nlh;
-
- nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*r), 0);
- if (!nlh)
- return NULL;
-
- r = nlmsg_data(nlh);
- r->ifi_family = AF_UNSPEC;
- r->__ifi_pad = 0;
- r->ifi_type = dev->type;
- r->ifi_index = dev->ifindex;
- r->ifi_flags = dev_get_flags(dev);
- r->ifi_change = 0; /* Wireless changes don't affect those flags */
-
- NLA_PUT_STRING(skb, IFLA_IFNAME, dev->name);
-
- return nlh;
- nla_put_failure:
- nlmsg_cancel(skb, nlh);
- return NULL;
-}
-
-
-/*
- * Main event dispatcher. Called from other parts and drivers.
- * Send the event on the appropriate channels.
- * May be called from interrupt context.
- */
-void wireless_send_event(struct net_device * dev,
- unsigned int cmd,
- union iwreq_data * wrqu,
- const char * extra)
-{
- const struct iw_ioctl_description * descr = NULL;
- int extra_len = 0;
- struct iw_event *event; /* Mallocated whole event */
- int event_len; /* Its size */
- int hdr_len; /* Size of the event header */
- int wrqu_off = 0; /* Offset in wrqu */
- /* Don't "optimise" the following variable, it will crash */
- unsigned cmd_index; /* *MUST* be unsigned */
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- struct nlattr *nla;
-#ifdef CONFIG_COMPAT
- struct __compat_iw_event *compat_event;
- struct compat_iw_point compat_wrqu;
- struct sk_buff *compskb;
-#endif
-
- /*
- * Nothing in the kernel sends scan events with data, be safe.
- * This is necessary because we cannot fix up scan event data
- * for compat, due to being contained in 'extra', but normally
- * applications are required to retrieve the scan data anyway
- * and no data is included in the event, this codifies that
- * practice.
- */
- if (WARN_ON(cmd == SIOCGIWSCAN && extra))
- extra = NULL;
-
- /* Get the description of the Event */
- if (cmd <= SIOCIWLAST) {
- cmd_index = cmd - SIOCIWFIRST;
- if (cmd_index < standard_ioctl_num)
- descr = &(standard_ioctl[cmd_index]);
- } else {
- cmd_index = cmd - IWEVFIRST;
- if (cmd_index < standard_event_num)
- descr = &(standard_event[cmd_index]);
- }
- /* Don't accept unknown events */
- if (descr == NULL) {
- /* Note : we don't return an error to the driver, because
- * the driver would not know what to do about it. It can't
- * return an error to the user, because the event is not
- * initiated by a user request.
- * The best the driver could do is to log an error message.
- * We will do it ourselves instead...
- */
- printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
- dev->name, cmd);
- return;
- }
-
- /* Check extra parameters and set extra_len */
- if (descr->header_type == IW_HEADER_TYPE_POINT) {
- /* Check if number of token fits within bounds */
- if (wrqu->data.length > descr->max_tokens) {
- printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
- return;
- }
- if (wrqu->data.length < descr->min_tokens) {
- printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
- return;
- }
- /* Calculate extra_len - extra is NULL for restricted events */
- if (extra != NULL)
- extra_len = wrqu->data.length * descr->token_size;
- /* Always at an offset in wrqu */
- wrqu_off = IW_EV_POINT_OFF;
- }
-
- /* Total length of the event */
- hdr_len = event_type_size[descr->header_type];
- event_len = hdr_len + extra_len;
-
- /*
- * The problem for 64/32 bit.
- *
- * On 64-bit, a regular event is laid out as follows:
- * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
- * | event.len | event.cmd | p a d d i n g |
- * | wrqu data ... (with the correct size) |
- *
- * This padding exists because we manipulate event->u,
- * and 'event' is not packed.
- *
- * An iw_point event is laid out like this instead:
- * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
- * | event.len | event.cmd | p a d d i n g |
- * | iwpnt.len | iwpnt.flg | p a d d i n g |
- * | extra data ...
- *
- * The second padding exists because struct iw_point is extended,
- * but this depends on the platform...
- *
- * On 32-bit, all the padding shouldn't be there.
- */
-
- skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
- if (!skb)
- return;
-
- /* Send via the RtNetlink event channel */
- nlh = rtnetlink_ifinfo_prep(dev, skb);
- if (WARN_ON(!nlh)) {
- kfree_skb(skb);
- return;
- }
-
- /* Add the wireless events in the netlink packet */
- nla = nla_reserve(skb, IFLA_WIRELESS, event_len);
- if (!nla) {
- kfree_skb(skb);
- return;
- }
- event = nla_data(nla);
-
- /* Fill event - first clear to avoid data leaking */
- memset(event, 0, hdr_len);
- event->len = event_len;
- event->cmd = cmd;
- memcpy(&event->u, ((char *) wrqu) + wrqu_off, hdr_len - IW_EV_LCP_LEN);
- if (extra_len)
- memcpy(((char *) event) + hdr_len, extra, extra_len);
-
- nlmsg_end(skb, nlh);
-#ifdef CONFIG_COMPAT
- hdr_len = compat_event_type_size[descr->header_type];
- event_len = hdr_len + extra_len;
-
- compskb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC);
- if (!compskb) {
- kfree_skb(skb);
- return;
- }
-
- /* Send via the RtNetlink event channel */
- nlh = rtnetlink_ifinfo_prep(dev, compskb);
- if (WARN_ON(!nlh)) {
- kfree_skb(skb);
- kfree_skb(compskb);
- return;
- }
-
- /* Add the wireless events in the netlink packet */
- nla = nla_reserve(compskb, IFLA_WIRELESS, event_len);
- if (!nla) {
- kfree_skb(skb);
- kfree_skb(compskb);
- return;
- }
- compat_event = nla_data(nla);
-
- compat_event->len = event_len;
- compat_event->cmd = cmd;
- if (descr->header_type == IW_HEADER_TYPE_POINT) {
- compat_wrqu.length = wrqu->data.length;
- compat_wrqu.flags = wrqu->data.flags;
- memcpy(&compat_event->pointer,
- ((char *) &compat_wrqu) + IW_EV_COMPAT_POINT_OFF,
- hdr_len - IW_EV_COMPAT_LCP_LEN);
- if (extra_len)
- memcpy(((char *) compat_event) + hdr_len,
- extra, extra_len);
- } else {
- /* extra_len must be zero, so no if (extra) needed */
- memcpy(&compat_event->pointer, wrqu,
- hdr_len - IW_EV_COMPAT_LCP_LEN);
- }
-
- nlmsg_end(compskb, nlh);
-
- skb_shinfo(skb)->frag_list = compskb;
-#endif
- skb_queue_tail(&dev_net(dev)->wext_nlevents, skb);
- schedule_work(&wireless_nlevent_work);
-}
-EXPORT_SYMBOL(wireless_send_event);
-
-/********************** ENHANCED IWSPY SUPPORT **********************/
-/*
- * In the old days, the driver was handling spy support all by itself.
- * Now, the driver can delegate this task to Wireless Extensions.
- * It needs to use those standard spy iw_handler in struct iw_handler_def,
- * push data to us via wireless_spy_update() and include struct iw_spy_data
- * in its private part (and export it in net_device->wireless_data->spy_data).
- * One of the main advantage of centralising spy support here is that
- * it becomes much easier to improve and extend it without having to touch
- * the drivers. One example is the addition of the Spy-Threshold events.
- */
-
-/* ---------------------------------------------------------------- */
-/*
- * Return the pointer to the spy data in the driver.
- * Because this is called on the Rx path via wireless_spy_update(),
- * we want it to be efficient...
- */
-static inline struct iw_spy_data *get_spydata(struct net_device *dev)
-{
- /* This is the new way */
- if (dev->wireless_data)
- return dev->wireless_data->spy_data;
- return NULL;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set Spy List
- */
-int iw_handler_set_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct sockaddr * address = (struct sockaddr *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Disable spy collection while we copy the addresses.
- * While we copy addresses, any call to wireless_spy_update()
- * will NOP. This is OK, as anyway the addresses are changing. */
- spydata->spy_number = 0;
-
- /* We want to operate without locking, because wireless_spy_update()
- * most likely will happen in the interrupt handler, and therefore
- * have its own locking constraints and needs performance.
- * The rtnl_lock() make sure we don't race with the other iw_handlers.
- * This make sure wireless_spy_update() "see" that the spy list
- * is temporarily disabled. */
- smp_wmb();
-
- /* Are there are addresses to copy? */
- if (wrqu->data.length > 0) {
- int i;
-
- /* Copy addresses */
- for (i = 0; i < wrqu->data.length; i++)
- memcpy(spydata->spy_address[i], address[i].sa_data,
- ETH_ALEN);
- /* Reset stats */
- memset(spydata->spy_stat, 0,
- sizeof(struct iw_quality) * IW_MAX_SPY);
- }
-
- /* Make sure above is updated before re-enabling */
- smp_wmb();
-
- /* Enable addresses */
- spydata->spy_number = wrqu->data.length;
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get Spy List
- */
-int iw_handler_get_spy(struct net_device * dev,
- struct iw_request_info * info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct sockaddr * address = (struct sockaddr *) extra;
- int i;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- wrqu->data.length = spydata->spy_number;
-
- /* Copy addresses. */
- for (i = 0; i < spydata->spy_number; i++) {
- memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
- address[i].sa_family = AF_UNIX;
- }
- /* Copy stats to the user buffer (just after). */
- if (spydata->spy_number > 0)
- memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
- spydata->spy_stat,
- sizeof(struct iw_quality) * spydata->spy_number);
- /* Reset updated flags. */
- for (i = 0; i < spydata->spy_number; i++)
- spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_spy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : set spy threshold
- */
-int iw_handler_set_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Just do it */
- memcpy(&(spydata->spy_thr_low), &(threshold->low),
- 2 * sizeof(struct iw_quality));
-
- /* Clear flag */
- memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_set_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Standard Wireless Handler : get spy threshold
- */
-int iw_handler_get_thrspy(struct net_device * dev,
- struct iw_request_info *info,
- union iwreq_data * wrqu,
- char * extra)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return -EOPNOTSUPP;
-
- /* Just do it */
- memcpy(&(threshold->low), &(spydata->spy_thr_low),
- 2 * sizeof(struct iw_quality));
-
- return 0;
-}
-EXPORT_SYMBOL(iw_handler_get_thrspy);
-
-/*------------------------------------------------------------------*/
-/*
- * Prepare and send a Spy Threshold event
- */
-static void iw_send_thrspy_event(struct net_device * dev,
- struct iw_spy_data * spydata,
- unsigned char * address,
- struct iw_quality * wstats)
-{
- union iwreq_data wrqu;
- struct iw_thrspy threshold;
-
- /* Init */
- wrqu.data.length = 1;
- wrqu.data.flags = 0;
- /* Copy address */
- memcpy(threshold.addr.sa_data, address, ETH_ALEN);
- threshold.addr.sa_family = ARPHRD_ETHER;
- /* Copy stats */
- memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
- /* Copy also thresholds */
- memcpy(&(threshold.low), &(spydata->spy_thr_low),
- 2 * sizeof(struct iw_quality));
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
-}
-
-/* ---------------------------------------------------------------- */
-/*
- * Call for the driver to update the spy data.
- * For now, the spy data is a simple array. As the size of the array is
- * small, this is good enough. If we wanted to support larger number of
- * spy addresses, we should use something more efficient...
- */
-void wireless_spy_update(struct net_device * dev,
- unsigned char * address,
- struct iw_quality * wstats)
-{
- struct iw_spy_data * spydata = get_spydata(dev);
- int i;
- int match = -1;
-
- /* Make sure driver is not buggy or using the old API */
- if (!spydata)
- return;
-
- /* Update all records that match */
- for (i = 0; i < spydata->spy_number; i++)
- if (!compare_ether_addr(address, spydata->spy_address[i])) {
- memcpy(&(spydata->spy_stat[i]), wstats,
- sizeof(struct iw_quality));
- match = i;
- }
-
- /* Generate an event if we cross the spy threshold.
- * To avoid event storms, we have a simple hysteresis : we generate
- * event only when we go under the low threshold or above the
- * high threshold. */
- if (match >= 0) {
- if (spydata->spy_thr_under[match]) {
- if (wstats->level > spydata->spy_thr_high.level) {
- spydata->spy_thr_under[match] = 0;
- iw_send_thrspy_event(dev, spydata,
- address, wstats);
- }
- } else {
- if (wstats->level < spydata->spy_thr_low.level) {
- spydata->spy_thr_under[match] = 1;
- iw_send_thrspy_event(dev, spydata,
- address, wstats);
- }
- }
- }
-}
-EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/wireless/wext-priv.c b/net/wireless/wext-priv.c
new file mode 100644
index 00000000000..a3c2277de9e
--- /dev/null
+++ b/net/wireless/wext-priv.c
@@ -0,0 +1,248 @@
+/*
+ * This file implement the Wireless Extensions priv API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <net/iw_handler.h>
+#include <net/wext.h>
+
+int iw_handler_get_private(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ /* Check if the driver has something to export */
+ if ((dev->wireless_handlers->num_private_args == 0) ||
+ (dev->wireless_handlers->private_args == NULL))
+ return -EOPNOTSUPP;
+
+ /* Check if there is enough buffer up there */
+ if (wrqu->data.length < dev->wireless_handlers->num_private_args) {
+ /* User space can't know in advance how large the buffer
+ * needs to be. Give it a hint, so that we can support
+ * any size buffer we want somewhat efficiently... */
+ wrqu->data.length = dev->wireless_handlers->num_private_args;
+ return -E2BIG;
+ }
+
+ /* Set the number of available ioctls. */
+ wrqu->data.length = dev->wireless_handlers->num_private_args;
+
+ /* Copy structure to the user buffer. */
+ memcpy(extra, dev->wireless_handlers->private_args,
+ sizeof(struct iw_priv_args) * wrqu->data.length);
+
+ return 0;
+}
+
+/* Size (in bytes) of the various private data types */
+static const char iw_priv_type_size[] = {
+ 0, /* IW_PRIV_TYPE_NONE */
+ 1, /* IW_PRIV_TYPE_BYTE */
+ 1, /* IW_PRIV_TYPE_CHAR */
+ 0, /* Not defined */
+ sizeof(__u32), /* IW_PRIV_TYPE_INT */
+ sizeof(struct iw_freq), /* IW_PRIV_TYPE_FLOAT */
+ sizeof(struct sockaddr), /* IW_PRIV_TYPE_ADDR */
+ 0, /* Not defined */
+};
+
+static int get_priv_size(__u16 args)
+{
+ int num = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ return num * iw_priv_type_size[type];
+}
+
+static int adjust_priv_size(__u16 args, struct iw_point *iwp)
+{
+ int num = iwp->length;
+ int max = args & IW_PRIV_SIZE_MASK;
+ int type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+ /* Make sure the driver doesn't goof up */
+ if (max < num)
+ num = max;
+
+ return num * iw_priv_type_size[type];
+}
+
+/*
+ * Wrapper to call a private Wireless Extension handler.
+ * We do various checks and also take care of moving data between
+ * user space and kernel space.
+ * It's not as nice and slimline as the standard wrapper. The cause
+ * is struct iw_priv_args, which was not really designed for the
+ * job we are going here.
+ *
+ * IMPORTANT : This function prevent to set and get data on the same
+ * IOCTL and enforce the SET/GET convention. Not doing it would be
+ * far too hairy...
+ * If you need to set and get data at the same time, please don't use
+ * a iw_handler but process it in your ioctl handler (i.e. use the
+ * old driver API).
+ */
+static int get_priv_descr_and_size(struct net_device *dev, unsigned int cmd,
+ const struct iw_priv_args **descrp)
+{
+ const struct iw_priv_args *descr;
+ int i, extra_size;
+
+ descr = NULL;
+ for (i = 0; i < dev->wireless_handlers->num_private_args; i++) {
+ if (cmd == dev->wireless_handlers->private_args[i].cmd) {
+ descr = &dev->wireless_handlers->private_args[i];
+ break;
+ }
+ }
+
+ extra_size = 0;
+ if (descr) {
+ if (IW_IS_SET(cmd)) {
+ int offset = 0; /* For sub-ioctls */
+ /* Check for sub-ioctl handler */
+ if (descr->name[0] == '\0')
+ /* Reserve one int for sub-ioctl index */
+ offset = sizeof(__u32);
+
+ /* Size of set arguments */
+ extra_size = get_priv_size(descr->set_args);
+
+ /* Does it fits in iwr ? */
+ if ((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+ ((extra_size + offset) <= IFNAMSIZ))
+ extra_size = 0;
+ } else {
+ /* Size of get arguments */
+ extra_size = get_priv_size(descr->get_args);
+
+ /* Does it fits in iwr ? */
+ if ((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+ (extra_size <= IFNAMSIZ))
+ extra_size = 0;
+ }
+ }
+ *descrp = descr;
+ return extra_size;
+}
+
+static int ioctl_private_iw_point(struct iw_point *iwp, unsigned int cmd,
+ const struct iw_priv_args *descr,
+ iw_handler handler, struct net_device *dev,
+ struct iw_request_info *info, int extra_size)
+{
+ char *extra;
+ int err;
+
+ /* Check what user space is giving us */
+ if (IW_IS_SET(cmd)) {
+ if (!iwp->pointer && iwp->length != 0)
+ return -EFAULT;
+
+ if (iwp->length > (descr->set_args & IW_PRIV_SIZE_MASK))
+ return -E2BIG;
+ } else if (!iwp->pointer)
+ return -EFAULT;
+
+ extra = kmalloc(extra_size, GFP_KERNEL);
+ if (!extra)
+ return -ENOMEM;
+
+ /* If it is a SET, get all the extra data in here */
+ if (IW_IS_SET(cmd) && (iwp->length != 0)) {
+ if (copy_from_user(extra, iwp->pointer, extra_size)) {
+ err = -EFAULT;
+ goto out;
+ }
+ }
+
+ /* Call the handler */
+ err = handler(dev, info, (union iwreq_data *) iwp, extra);
+
+ /* If we have something to return to the user */
+ if (!err && IW_IS_GET(cmd)) {
+ /* Adjust for the actual length if it's variable,
+ * avoid leaking kernel bits outside.
+ */
+ if (!(descr->get_args & IW_PRIV_SIZE_FIXED))
+ extra_size = adjust_priv_size(descr->get_args, iwp);
+
+ if (copy_to_user(iwp->pointer, extra, extra_size))
+ err = -EFAULT;
+ }
+
+out:
+ kfree(extra);
+ return err;
+}
+
+int ioctl_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
+{
+ int extra_size = 0, ret = -EINVAL;
+ const struct iw_priv_args *descr;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ ret = ioctl_private_iw_point(&iwr->u.data, cmd, descr,
+ handler, dev, info, extra_size);
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+int compat_private_call(struct net_device *dev, struct iwreq *iwr,
+ unsigned int cmd, struct iw_request_info *info,
+ iw_handler handler)
+{
+ const struct iw_priv_args *descr;
+ int ret, extra_size;
+
+ extra_size = get_priv_descr_and_size(dev, cmd, &descr);
+
+ /* Check if we have a pointer to user space data or not. */
+ if (extra_size == 0) {
+ /* No extra arguments. Trivial to handle */
+ ret = handler(dev, info, &(iwr->u), (char *) &(iwr->u));
+ } else {
+ struct compat_iw_point *iwp_compat;
+ struct iw_point iwp;
+
+ iwp_compat = (struct compat_iw_point *) &iwr->u.data;
+ iwp.pointer = compat_ptr(iwp_compat->pointer);
+ iwp.length = iwp_compat->length;
+ iwp.flags = iwp_compat->flags;
+
+ ret = ioctl_private_iw_point(&iwp, cmd, descr,
+ handler, dev, info, extra_size);
+
+ iwp_compat->pointer = ptr_to_compat(iwp.pointer);
+ iwp_compat->length = iwp.length;
+ iwp_compat->flags = iwp.flags;
+ }
+
+ /* Call commit handler if needed and defined */
+ if (ret == -EIWCOMMIT)
+ ret = call_commit_handler(dev);
+
+ return ret;
+}
+#endif
diff --git a/net/wireless/wext-proc.c b/net/wireless/wext-proc.c
new file mode 100644
index 00000000000..273a7f77c83
--- /dev/null
+++ b/net/wireless/wext-proc.c
@@ -0,0 +1,155 @@
+/*
+ * This file implement the Wireless Extensions proc API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+/*
+ * The /proc/net/wireless file is a human readable user-space interface
+ * exporting various wireless specific statistics from the wireless devices.
+ * This is the most popular part of the Wireless Extensions ;-)
+ *
+ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
+ * The content of the file is basically the content of "struct iw_statistics".
+ */
+
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <net/wext.h>
+
+
+static void wireless_seq_printf_stats(struct seq_file *seq,
+ struct net_device *dev)
+{
+ /* Get stats from the driver */
+ struct iw_statistics *stats = get_wireless_stats(dev);
+ static struct iw_statistics nullstats = {};
+
+ /* show device if it's wireless regardless of current stats */
+ if (!stats) {
+#ifdef CONFIG_WIRELESS_EXT
+ if (dev->wireless_handlers)
+ stats = &nullstats;
+#endif
+#ifdef CONFIG_CFG80211
+ if (dev->ieee80211_ptr)
+ stats = &nullstats;
+#endif
+ }
+
+ if (stats) {
+ seq_printf(seq, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d "
+ "%6d %6d %6d\n",
+ dev->name, stats->status, stats->qual.qual,
+ stats->qual.updated & IW_QUAL_QUAL_UPDATED
+ ? '.' : ' ',
+ ((__s32) stats->qual.level) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+ stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+ ? '.' : ' ',
+ ((__s32) stats->qual.noise) -
+ ((stats->qual.updated & IW_QUAL_DBM) ? 0x100 : 0),
+ stats->qual.updated & IW_QUAL_NOISE_UPDATED
+ ? '.' : ' ',
+ stats->discard.nwid, stats->discard.code,
+ stats->discard.fragment, stats->discard.retries,
+ stats->discard.misc, stats->miss.beacon);
+
+ if (stats != &nullstats)
+ stats->qual.updated &= ~IW_QUAL_ALL_UPDATED;
+ }
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Print info for /proc/net/wireless (print all entries)
+ */
+static int wireless_dev_seq_show(struct seq_file *seq, void *v)
+{
+ might_sleep();
+
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "Inter-| sta-| Quality | Discarded "
+ "packets | Missed | WE\n"
+ " face | tus | link level noise | nwid "
+ "crypt frag retry misc | beacon | %d\n",
+ WIRELESS_EXT);
+ else
+ wireless_seq_printf_stats(seq, v);
+ return 0;
+}
+
+static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct net *net = seq_file_net(seq);
+ loff_t off;
+ struct net_device *dev;
+
+ rtnl_lock();
+ if (!*pos)
+ return SEQ_START_TOKEN;
+
+ off = 1;
+ for_each_netdev(net, dev)
+ if (off++ == *pos)
+ return dev;
+ return NULL;
+}
+
+static void *wireless_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct net *net = seq_file_net(seq);
+
+ ++*pos;
+
+ return v == SEQ_START_TOKEN ?
+ first_net_device(net) : next_net_device(v);
+}
+
+static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ rtnl_unlock();
+}
+
+static const struct seq_operations wireless_seq_ops = {
+ .start = wireless_dev_seq_start,
+ .next = wireless_dev_seq_next,
+ .stop = wireless_dev_seq_stop,
+ .show = wireless_dev_seq_show,
+};
+
+static int seq_open_wireless(struct inode *inode, struct file *file)
+{
+ return seq_open_net(inode, file, &wireless_seq_ops,
+ sizeof(struct seq_net_private));
+}
+
+static const struct file_operations wireless_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = seq_open_wireless,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_net,
+};
+
+int wext_proc_init(struct net *net)
+{
+ /* Create /proc/net/wireless entry */
+ if (!proc_net_fops_create(net, "wireless", S_IRUGO, &wireless_seq_fops))
+ return -ENOMEM;
+
+ return 0;
+}
+
+void wext_proc_exit(struct net *net)
+{
+ proc_net_remove(net, "wireless");
+}
diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c
new file mode 100644
index 00000000000..6dcfe65a2d1
--- /dev/null
+++ b/net/wireless/wext-spy.c
@@ -0,0 +1,231 @@
+/*
+ * This file implement the Wireless Extensions spy API.
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
+ *
+ * (As all part of the Linux kernel, this file is GPL)
+ */
+
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/iw_handler.h>
+#include <net/arp.h>
+#include <net/wext.h>
+
+static inline struct iw_spy_data *get_spydata(struct net_device *dev)
+{
+ /* This is the new way */
+ if (dev->wireless_data)
+ return dev->wireless_data->spy_data;
+ return NULL;
+}
+
+int iw_handler_set_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Disable spy collection while we copy the addresses.
+ * While we copy addresses, any call to wireless_spy_update()
+ * will NOP. This is OK, as anyway the addresses are changing. */
+ spydata->spy_number = 0;
+
+ /* We want to operate without locking, because wireless_spy_update()
+ * most likely will happen in the interrupt handler, and therefore
+ * have its own locking constraints and needs performance.
+ * The rtnl_lock() make sure we don't race with the other iw_handlers.
+ * This make sure wireless_spy_update() "see" that the spy list
+ * is temporarily disabled. */
+ smp_wmb();
+
+ /* Are there are addresses to copy? */
+ if (wrqu->data.length > 0) {
+ int i;
+
+ /* Copy addresses */
+ for (i = 0; i < wrqu->data.length; i++)
+ memcpy(spydata->spy_address[i], address[i].sa_data,
+ ETH_ALEN);
+ /* Reset stats */
+ memset(spydata->spy_stat, 0,
+ sizeof(struct iw_quality) * IW_MAX_SPY);
+ }
+
+ /* Make sure above is updated before re-enabling */
+ smp_wmb();
+
+ /* Enable addresses */
+ spydata->spy_number = wrqu->data.length;
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_spy);
+
+int iw_handler_get_spy(struct net_device * dev,
+ struct iw_request_info * info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct sockaddr * address = (struct sockaddr *) extra;
+ int i;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ wrqu->data.length = spydata->spy_number;
+
+ /* Copy addresses. */
+ for (i = 0; i < spydata->spy_number; i++) {
+ memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ }
+ /* Copy stats to the user buffer (just after). */
+ if (spydata->spy_number > 0)
+ memcpy(extra + (sizeof(struct sockaddr) *spydata->spy_number),
+ spydata->spy_stat,
+ sizeof(struct iw_quality) * spydata->spy_number);
+ /* Reset updated flags. */
+ for (i = 0; i < spydata->spy_number; i++)
+ spydata->spy_stat[i].updated &= ~IW_QUAL_ALL_UPDATED;
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_spy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int iw_handler_set_thrspy(struct net_device * dev,
+ struct iw_request_info *info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Just do it */
+ memcpy(&(spydata->spy_thr_low), &(threshold->low),
+ 2 * sizeof(struct iw_quality));
+
+ /* Clear flag */
+ memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_set_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int iw_handler_get_thrspy(struct net_device * dev,
+ struct iw_request_info *info,
+ union iwreq_data * wrqu,
+ char * extra)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ struct iw_thrspy * threshold = (struct iw_thrspy *) extra;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return -EOPNOTSUPP;
+
+ /* Just do it */
+ memcpy(&(threshold->low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ return 0;
+}
+EXPORT_SYMBOL(iw_handler_get_thrspy);
+
+/*------------------------------------------------------------------*/
+/*
+ * Prepare and send a Spy Threshold event
+ */
+static void iw_send_thrspy_event(struct net_device * dev,
+ struct iw_spy_data * spydata,
+ unsigned char * address,
+ struct iw_quality * wstats)
+{
+ union iwreq_data wrqu;
+ struct iw_thrspy threshold;
+
+ /* Init */
+ wrqu.data.length = 1;
+ wrqu.data.flags = 0;
+ /* Copy address */
+ memcpy(threshold.addr.sa_data, address, ETH_ALEN);
+ threshold.addr.sa_family = ARPHRD_ETHER;
+ /* Copy stats */
+ memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
+ /* Copy also thresholds */
+ memcpy(&(threshold.low), &(spydata->spy_thr_low),
+ 2 * sizeof(struct iw_quality));
+
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call for the driver to update the spy data.
+ * For now, the spy data is a simple array. As the size of the array is
+ * small, this is good enough. If we wanted to support larger number of
+ * spy addresses, we should use something more efficient...
+ */
+void wireless_spy_update(struct net_device * dev,
+ unsigned char * address,
+ struct iw_quality * wstats)
+{
+ struct iw_spy_data * spydata = get_spydata(dev);
+ int i;
+ int match = -1;
+
+ /* Make sure driver is not buggy or using the old API */
+ if (!spydata)
+ return;
+
+ /* Update all records that match */
+ for (i = 0; i < spydata->spy_number; i++)
+ if (!compare_ether_addr(address, spydata->spy_address[i])) {
+ memcpy(&(spydata->spy_stat[i]), wstats,
+ sizeof(struct iw_quality));
+ match = i;
+ }
+
+ /* Generate an event if we cross the spy threshold.
+ * To avoid event storms, we have a simple hysteresis : we generate
+ * event only when we go under the low threshold or above the
+ * high threshold. */
+ if (match >= 0) {
+ if (spydata->spy_thr_under[match]) {
+ if (wstats->level > spydata->spy_thr_high.level) {
+ spydata->spy_thr_under[match] = 0;
+ iw_send_thrspy_event(dev, spydata,
+ address, wstats);
+ }
+ } else {
+ if (wstats->level < spydata->spy_thr_low.level) {
+ spydata->spy_thr_under[match] = 1;
+ iw_send_thrspy_event(dev, spydata,
+ address, wstats);
+ }
+ }
+ }
+}
+EXPORT_SYMBOL(wireless_spy_update);
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 7fa9c7ad3d3..e19d811788a 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1363,7 +1363,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
facilities.throughput > 0xDD)
break;
if (facilities.reverse &&
- (facilities.reverse | 0x81)!= 0x81)
+ (facilities.reverse & 0x81) != 0x81)
break;
x25->facilities = facilities;
rc = 0;
@@ -1476,7 +1476,7 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return rc;
}
-static struct net_proto_family x25_family_ops = {
+static const struct net_proto_family x25_family_ops = {
.family = AF_X25,
.create = x25_create,
.owner = THIS_MODULE,